diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 000000000..a7b25af86 --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,56 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize] + # Optional: Only run on specific file changes + # paths: + # - "src/**/*.ts" + # - "src/**/*.tsx" + # - "src/**/*.js" + # - "src/**/*.jsx" + +jobs: + claude-review: + # Optional: Filter by PR author + # if: | + # github.event.pull_request.user.login == 'external-contributor' || + # github.event.pull_request.user.login == 'new-developer' || + # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code Review + id: claude-review + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + prompt: | + REPO: ${{ github.repository }} + PR NUMBER: ${{ github.event.pull_request.number }} + + Please review this pull request and provide feedback on: + - Code quality and best practices + - Potential bugs or issues + - Performance considerations + - Security concerns + - Test coverage + + Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback. + + Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR. + + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 000000000..8d0bf3663 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,49 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: read + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. + # prompt: 'Update the pull request description to include a summary of changes.' + + # Optional: Add claude_args to customize behavior and configuration + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + # claude_args: '--allowed-tools Bash(gh pr:*)' diff --git a/lib/v2-core b/lib/v2-core index 3d02c34d1..d913b783b 160000 --- a/lib/v2-core +++ b/lib/v2-core @@ -1 +1 @@ -Subproject commit 3d02c34d105088bc0ff2698616b6e887e60931e3 +Subproject commit d913b783b906908530994690f801666914a24ae5 diff --git a/script/ConfigureGovernorAddresses.s.sol b/script/ConfigureGovernorAddresses.s.sol new file mode 100644 index 000000000..c57c95c63 --- /dev/null +++ b/script/ConfigureGovernorAddresses.s.sol @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.30; + +import { DeployV2Base } from "./DeployV2Base.s.sol"; +import { SuperGovernor } from "../src/SuperGovernor.sol"; +import { console2 } from "forge-std/console2.sol"; + +/// @title ConfigureGovernorAddresses +/// @notice Script to register core contract addresses in SuperGovernor +/// @dev This is a standalone script to set SUPER_VAULT_AGGREGATOR, SUPER_ORACLE, and SUPER_BANK +/// addresses in SuperGovernor when the deployment script exits early due to all contracts +/// already being deployed. +contract ConfigureGovernorAddresses is DeployV2Base { + /// @notice Configure SuperGovernor with core contract addresses + /// @param env Environment (0 = prod, 1 = test, 2 = staging) + /// @param chainId Chain ID for deployment + function run(uint256 env, uint64 chainId) external broadcast(env) { + _setBaseConfiguration(env, ""); + _configure(chainId, env); + } + + /// @notice Configure SuperGovernor with core contract addresses (with salt namespace) + /// @param env Environment (0 = prod, 1 = test, 2 = staging) + /// @param chainId Chain ID for deployment + /// @param saltNamespace Salt namespace for deployment + function run(uint256 env, uint64 chainId, string calldata saltNamespace) external broadcast(env) { + _setBaseConfiguration(env, saltNamespace); + _configure(chainId, env); + } + + function _configure(uint64 chainId, uint256 env) internal { + console2.log("=== Configuring SuperGovernor Core Addresses ==="); + console2.log("Chain ID:", chainId); + console2.log("Environment:", env); + + // Read addresses from deployment JSON + string memory peripheryJson = _readPeripheryContractsFromOutput(chainId, env); + + if (bytes(peripheryJson).length == 0) { + console2.log("ERROR: Could not read periphery deployment file"); + revert("PERIPHERY_JSON_NOT_FOUND"); + } + + // Parse addresses from JSON + address superGovernor = _safeParseJsonAddress(peripheryJson, ".SuperGovernor"); + address superVaultAggregator = _safeParseJsonAddress(peripheryJson, ".SuperVaultAggregator"); + address superOracle = _safeParseJsonAddress(peripheryJson, ".SuperOracle"); + address superBank = _safeParseJsonAddress(peripheryJson, ".SuperBank"); + address ecdsappsOracle = _safeParseJsonAddress(peripheryJson, ".ECDSAPPSOracle"); + + console2.log(""); + console2.log("Addresses from deployment file:"); + console2.log(" SuperGovernor:", superGovernor); + console2.log(" SuperVaultAggregator:", superVaultAggregator); + console2.log(" SuperOracle:", superOracle); + console2.log(" SuperBank:", superBank); + console2.log(" ECDSAPPSOracle:", ecdsappsOracle); + + if (superGovernor == address(0)) { + console2.log("ERROR: SuperGovernor address not found in deployment file"); + revert("SUPER_GOVERNOR_NOT_FOUND"); + } + + SuperGovernor governor = SuperGovernor(superGovernor); + + // Set SuperVaultAggregator + if (superVaultAggregator != address(0)) { + _setAddressIfNeeded(governor, governor.SUPER_VAULT_AGGREGATOR(), superVaultAggregator, "SUPER_VAULT_AGGREGATOR"); + } else { + console2.log("SKIP: SuperVaultAggregator not in deployment file"); + } + + // Set SuperOracle + if (superOracle != address(0)) { + _setAddressIfNeeded(governor, governor.SUPER_ORACLE(), superOracle, "SUPER_ORACLE"); + } else { + console2.log("SKIP: SuperOracle not in deployment file"); + } + + // Set SuperBank + if (superBank != address(0)) { + _setAddressIfNeeded(governor, governor.SUPER_BANK(), superBank, "SUPER_BANK"); + } else { + console2.log("SKIP: SuperBank not in deployment file"); + } + + // Set Active PPS Oracle (ECDSAPPSOracle) + if (ecdsappsOracle != address(0)) { + _setActivePPSOracleIfNeeded(governor, ecdsappsOracle); + } else { + console2.log("SKIP: ECDSAPPSOracle not in deployment file"); + } + + // Set Validator Configuration + _setValidatorConfigIfNeeded(governor); + + console2.log(""); + console2.log("=== Configuration Complete ==="); + } + + /// @notice Set validator configuration if not already set + function _setValidatorConfigIfNeeded(SuperGovernor governor) internal { + // Get current validator config + (, address[] memory currentValidators,, uint256 currentQuorum) = governor.getValidatorConfig(); + + console2.log(""); + console2.log("Validator Configuration:"); + console2.log(" Current validator count:", currentValidators.length); + console2.log(" Current quorum:", currentQuorum); + console2.log(" Expected validator count:", validators.length); + console2.log(" Expected quorum:", INITIAL_VALIDATOR_QUORUM); + + // Check if already configured correctly + if (currentValidators.length == validators.length && currentQuorum == INITIAL_VALIDATOR_QUORUM) { + // Verify all validators match + bool allMatch = true; + for (uint256 i = 0; i < validators.length; i++) { + if (currentValidators[i] != validators[i]) { + allMatch = false; + break; + } + } + if (allMatch) { + console2.log("SKIP: Validator configuration already set correctly"); + return; + } + } + + // Set validator configuration + console2.log("SET: Validator configuration with %s validators", validators.length); + governor.setValidatorConfig( + INITIAL_VALIDATOR_CONFIG_VERSION, + validators, + validatorPublicKeys, + INITIAL_VALIDATOR_QUORUM, + "" // offchainConfig - empty for initial setup + ); + console2.log("SUCCESS: Validator configuration set"); + } + + /// @notice Set the active PPS oracle if not already set + function _setActivePPSOracleIfNeeded(SuperGovernor governor, address expected) internal { + // Check if already set correctly + try governor.getActivePPSOracle() returns (address current) { + if (current == expected) { + console2.log("SKIP: Active PPS Oracle already set correctly to %s", current); + return; + } else { + // Already set to different address - requires timelock to change + console2.log("WARNING: Active PPS Oracle already set to different address: %s", current); + console2.log("WARNING: Use proposeActivePPSOracle + executeActivePPSOracleChange to change it"); + return; + } + } catch { + // Not set yet - can set directly + console2.log("SET: Active PPS Oracle to %s", expected); + } + + // Set the active PPS oracle + governor.setActivePPSOracle(expected); + console2.log("SUCCESS: Active PPS Oracle configured"); + } + + /// @notice Set an address in SuperGovernor if not already set to the expected value + function _setAddressIfNeeded( + SuperGovernor governor, + bytes32 key, + address expected, + string memory keyName + ) internal { + // Check if already set correctly + try governor.getAddress(key) returns (address current) { + if (current == expected) { + console2.log("SKIP: %s already set correctly to %s", keyName, current); + return; + } else { + console2.log("UPDATE: %s from %s to %s", keyName, current, expected); + } + } catch { + console2.log("SET: %s to %s", keyName, expected); + } + + // Set the address + governor.setAddress(key, expected); + console2.log("SUCCESS: %s configured", keyName); + } + + /// @notice Read periphery contracts from output files + function _readPeripheryContractsFromOutput(uint64 chainId, uint256 env) internal view returns (string memory) { + string memory peripheryRoot = vm.projectRoot(); + string memory chainName = _getChainName(chainId); + + string memory envName; + if (env == 0) { + envName = "prod"; + } else if (env == 2) { + envName = "staging"; + } else { + envName = "test"; + } + + string memory outputPath = string( + abi.encodePacked( + peripheryRoot, + "/script/output/", + envName, + "/", + vm.toString(uint256(chainId)), + "/", + chainName, + "-latest.json" + ) + ); + + console2.log("Reading from:", outputPath); + + try vm.readFile(outputPath) returns (string memory fileContent) { + return fileContent; + } catch { + console2.log("Failed to read:", outputPath); + return ""; + } + } + + /// @notice Get chain name from chain ID + function _getChainName(uint64 chainId) internal pure returns (string memory) { + if (chainId == 1) return "Ethereum"; + if (chainId == 8453) return "Base"; + if (chainId == 999) return "HyperEVM"; + if (chainId == 10) return "Optimism"; + if (chainId == 42161) return "Arbitrum"; + return "Unknown"; + } + + /// @notice Safely parse an address from JSON + function _safeParseJsonAddress(string memory json, string memory key) internal pure returns (address) { + try vm.parseJsonAddress(json, key) returns (address addr) { + return addr; + } catch { + return address(0); + } + } +} diff --git a/script/ConfigureHyperEVMLZEndpoint.s.sol b/script/ConfigureHyperEVMLZEndpoint.s.sol new file mode 100644 index 000000000..d81a20592 --- /dev/null +++ b/script/ConfigureHyperEVMLZEndpoint.s.sol @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Script, console2 } from "forge-std/Script.sol"; + +interface ILayerZeroEndpointV2 { + struct SetConfigParam { + uint32 eid; + uint32 configType; + bytes config; + } + + function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; + function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; + function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; +} + +/// @title ConfigureHyperEVMLZEndpoint +/// @notice Configures LZ Endpoint for ETH/Base -> HyperEVM OFT pathways (TX 3-6) +/// @dev These transactions can be executed by the delegate (deployer: 0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8) +/// +/// Simulate on Ethereum: +/// forge script script/ConfigureHyperEVMLZEndpoint.s.sol:ConfigureHyperEVMLZEndpointETH -f ethereum -vvv +/// +/// Execute on Ethereum: +/// forge script script/ConfigureHyperEVMLZEndpoint.s.sol:ConfigureHyperEVMLZEndpointETH -f ethereum --broadcast -vvv +/// +/// Simulate on Base: +/// forge script script/ConfigureHyperEVMLZEndpoint.s.sol:ConfigureHyperEVMLZEndpointBase -f base -vvv +/// +/// Execute on Base: +/// forge script script/ConfigureHyperEVMLZEndpoint.s.sol:ConfigureHyperEVMLZEndpointBase -f base --broadcast -vvv +contract ConfigureHyperEVMLZEndpointETH is Script { + // LayerZero constants + address constant LZ_ENDPOINT = 0x1a44076050125825900e736c501f859c50fE728c; + uint32 constant HYPEREVM_EID = 30367; + + // Config types + uint32 constant EXECUTOR_CONFIG_TYPE = 1; + uint32 constant ULN_CONFIG_TYPE = 2; + + // Ethereum addresses + address constant ETH_ADAPTER = 0x722ff7C0665F4b1823c9C4cFcDF73A43de5865BD; + address constant SEND_LIB_ETH = 0xbB2Ea70C9E858123480642Cf96acbcCE1372dCe1; + address constant RECEIVE_LIB_ETH = 0xc02Ab410f0734EFa3F14628780e6e695156024C2; + address constant DVN1_ETH = 0x589dEDbD617e0CBcB916A9223F4d1300c294236b; + address constant EXECUTOR_ETH = 0x173272739Bd7Aa6e4e214714048a9fE699453059; + + // ULN Config struct + struct UlnConfig { + uint64 confirmations; + uint8 requiredDVNCount; + uint8 optionalDVNCount; + uint8 optionalDVNThreshold; + address[] requiredDVNs; + address[] optionalDVNs; + } + + // Executor Config struct + struct ExecutorConfig { + uint32 maxMessageSize; + address executor; + } + + function run() public { + vm.startBroadcast(); + + ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(LZ_ENDPOINT); + + // TX 3: setSendLibrary + console2.log("TX 3: Setting send library..."); + endpoint.setSendLibrary(ETH_ADAPTER, HYPEREVM_EID, SEND_LIB_ETH); + console2.log(" Done: setSendLibrary"); + + // TX 4: setReceiveLibrary + console2.log("TX 4: Setting receive library..."); + endpoint.setReceiveLibrary(ETH_ADAPTER, HYPEREVM_EID, RECEIVE_LIB_ETH, 0); + console2.log(" Done: setReceiveLibrary"); + + // TX 5: setConfig for SendLib (Executor + ULN) + console2.log("TX 5: Setting send config..."); + _setSendConfig(endpoint); + console2.log(" Done: setConfig (SendLib)"); + + // TX 6: setConfig for ReceiveLib (ULN only) + console2.log("TX 6: Setting receive config..."); + _setReceiveConfig(endpoint); + console2.log(" Done: setConfig (ReceiveLib)"); + + vm.stopBroadcast(); + + console2.log(""); + console2.log("All Ethereum LZ Endpoint configurations complete!"); + } + + function _setSendConfig(ILayerZeroEndpointV2 endpoint) internal { + address[] memory requiredDVNs = new address[](1); + requiredDVNs[0] = DVN1_ETH; + + address[] memory optionalDVNs = new address[](0); + + UlnConfig memory ulnConfig = UlnConfig({ + confirmations: 15, + requiredDVNCount: 1, + optionalDVNCount: 0, + optionalDVNThreshold: 0, + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs + }); + + ExecutorConfig memory execConfig = ExecutorConfig({ maxMessageSize: 10_000, executor: EXECUTOR_ETH }); + + ILayerZeroEndpointV2.SetConfigParam[] memory params = new ILayerZeroEndpointV2.SetConfigParam[](2); + params[0] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: EXECUTOR_CONFIG_TYPE, + config: abi.encode(execConfig) + }); + params[1] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: ULN_CONFIG_TYPE, + config: abi.encode(ulnConfig) + }); + + endpoint.setConfig(ETH_ADAPTER, SEND_LIB_ETH, params); + } + + function _setReceiveConfig(ILayerZeroEndpointV2 endpoint) internal { + address[] memory requiredDVNs = new address[](1); + requiredDVNs[0] = DVN1_ETH; + + address[] memory optionalDVNs = new address[](0); + + UlnConfig memory ulnConfig = UlnConfig({ + confirmations: 1, // HyperEVM confirmations + requiredDVNCount: 1, + optionalDVNCount: 0, + optionalDVNThreshold: 0, + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs + }); + + ILayerZeroEndpointV2.SetConfigParam[] memory params = new ILayerZeroEndpointV2.SetConfigParam[](1); + params[0] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: ULN_CONFIG_TYPE, + config: abi.encode(ulnConfig) + }); + + endpoint.setConfig(ETH_ADAPTER, RECEIVE_LIB_ETH, params); + } +} + +contract ConfigureHyperEVMLZEndpointBase is Script { + // LayerZero constants + address constant LZ_ENDPOINT = 0x1a44076050125825900e736c501f859c50fE728c; + uint32 constant HYPEREVM_EID = 30367; + + // Config types + uint32 constant EXECUTOR_CONFIG_TYPE = 1; + uint32 constant ULN_CONFIG_TYPE = 2; + + // Base addresses + address constant BASE_OFT = 0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B; + address constant SEND_LIB_BASE = 0xB5320B0B3a13cC860893E2Bd79FCd7e13484Dda2; + address constant RECEIVE_LIB_BASE = 0xc70AB6f32772f59fBfc23889Caf4Ba3376C84bAf; + address constant DVN1_BASE = 0x9e059a54699a285714207b43B055483E78FAac25; + address constant EXECUTOR_BASE = 0x2CCA08ae69E0C44b18a57Ab2A87644234dAebaE4; + + // ULN Config struct + struct UlnConfig { + uint64 confirmations; + uint8 requiredDVNCount; + uint8 optionalDVNCount; + uint8 optionalDVNThreshold; + address[] requiredDVNs; + address[] optionalDVNs; + } + + // Executor Config struct + struct ExecutorConfig { + uint32 maxMessageSize; + address executor; + } + + function run() public { + vm.startBroadcast(); + + ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(LZ_ENDPOINT); + + // TX 3: setSendLibrary + console2.log("TX 3: Setting send library..."); + endpoint.setSendLibrary(BASE_OFT, HYPEREVM_EID, SEND_LIB_BASE); + console2.log(" Done: setSendLibrary"); + + // TX 4: setReceiveLibrary + console2.log("TX 4: Setting receive library..."); + endpoint.setReceiveLibrary(BASE_OFT, HYPEREVM_EID, RECEIVE_LIB_BASE, 0); + console2.log(" Done: setReceiveLibrary"); + + // TX 5: setConfig for SendLib (Executor + ULN) + console2.log("TX 5: Setting send config..."); + _setSendConfig(endpoint); + console2.log(" Done: setConfig (SendLib)"); + + // TX 6: setConfig for ReceiveLib (ULN only) + console2.log("TX 6: Setting receive config..."); + _setReceiveConfig(endpoint); + console2.log(" Done: setConfig (ReceiveLib)"); + + vm.stopBroadcast(); + + console2.log(""); + console2.log("All Base LZ Endpoint configurations complete!"); + } + + function _setSendConfig(ILayerZeroEndpointV2 endpoint) internal { + address[] memory requiredDVNs = new address[](1); + requiredDVNs[0] = DVN1_BASE; + + address[] memory optionalDVNs = new address[](0); + + UlnConfig memory ulnConfig = UlnConfig({ + confirmations: 10, + requiredDVNCount: 1, + optionalDVNCount: 0, + optionalDVNThreshold: 0, + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs + }); + + ExecutorConfig memory execConfig = ExecutorConfig({ maxMessageSize: 10_000, executor: EXECUTOR_BASE }); + + ILayerZeroEndpointV2.SetConfigParam[] memory params = new ILayerZeroEndpointV2.SetConfigParam[](2); + params[0] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: EXECUTOR_CONFIG_TYPE, + config: abi.encode(execConfig) + }); + params[1] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: ULN_CONFIG_TYPE, + config: abi.encode(ulnConfig) + }); + + endpoint.setConfig(BASE_OFT, SEND_LIB_BASE, params); + } + + function _setReceiveConfig(ILayerZeroEndpointV2 endpoint) internal { + address[] memory requiredDVNs = new address[](1); + requiredDVNs[0] = DVN1_BASE; + + address[] memory optionalDVNs = new address[](0); + + UlnConfig memory ulnConfig = UlnConfig({ + confirmations: 1, // HyperEVM confirmations + requiredDVNCount: 1, + optionalDVNCount: 0, + optionalDVNThreshold: 0, + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs + }); + + ILayerZeroEndpointV2.SetConfigParam[] memory params = new ILayerZeroEndpointV2.SetConfigParam[](1); + params[0] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: ULN_CONFIG_TYPE, + config: abi.encode(ulnConfig) + }); + + endpoint.setConfig(BASE_OFT, RECEIVE_LIB_BASE, params); + } +} diff --git a/script/ConfigureV2Periphery.s.sol b/script/ConfigureV2Periphery.s.sol index a7a66c74b..ae2a38bfb 100644 --- a/script/ConfigureV2Periphery.s.sol +++ b/script/ConfigureV2Periphery.s.sol @@ -37,6 +37,7 @@ contract ConfigureV2Periphery is DeployV2Base { address merklClaimRewardHook; address pendleRouterRedeemHook; address pendleRouterSwapHook; + address pendleUnifiedHook; address acrossSendFundsAndExecuteOnDstHook; } @@ -208,11 +209,13 @@ contract ConfigureV2Periphery is DeployV2Base { } // If not found locally, read from periphery deployment JSON files - string memory peripheryJson = - _readPeripheryContractsFromOutput(params.chainId, params.env, params.saltNamespace); + PeripheryJsonData memory data = + _readPeripheryContractsFromOutputWithChainName(params.chainId, params.env, params.saltNamespace); - if (bytes(peripheryJson).length > 0) { - address governorAddr = _safeParseJsonAddress(peripheryJson, ".SuperGovernor"); + if (bytes(data.json).length > 0 && bytes(data.chainName).length > 0) { + // Parse using the latest.json structure: .networks.{ChainName}.contracts.{ContractName} + string memory key = string(abi.encodePacked(".networks.", data.chainName, ".contracts.SuperGovernor")); + address governorAddr = _safeParseJsonAddress(data.json, key); if (governorAddr != address(0)) { console2.log("Found SuperGovernor from periphery deployment file:", governorAddr); return governorAddr; @@ -275,6 +278,7 @@ contract ConfigureV2Periphery is DeployV2Base { hooks.merklClaimRewardHook = _safeParseJsonAddress(coreJson, ".MerklClaimRewardHook"); hooks.pendleRouterRedeemHook = _safeParseJsonAddress(coreJson, ".PendleRouterRedeemHook"); hooks.pendleRouterSwapHook = _safeParseJsonAddress(coreJson, ".PendleRouterSwapHook"); + hooks.pendleUnifiedHook = _safeParseJsonAddress(coreJson, ".PendleUnifiedHook"); hooks.acrossSendFundsAndExecuteOnDstHook = _safeParseJsonAddress(coreJson, ".AcrossSendFundsAndExecuteOnDstHook"); } @@ -332,7 +336,13 @@ contract ConfigureV2Periphery is DeployV2Base { } } - /// @notice Read periphery contracts from output files + /// @notice Struct to hold periphery JSON data and chain name for parsing + struct PeripheryJsonData { + string json; + string chainName; + } + + /// @notice Read periphery contracts from latest.json function _readPeripheryContractsFromOutput( uint64 chainId, uint256 env, @@ -341,13 +351,24 @@ contract ConfigureV2Periphery is DeployV2Base { internal view returns (string memory) + { + PeripheryJsonData memory data = _readPeripheryContractsFromOutputWithChainName(chainId, env, branchName); + return data.json; + } + + /// @notice Read periphery contracts from latest.json with chain name + function _readPeripheryContractsFromOutputWithChainName( + uint64 chainId, + uint256 env, + string memory branchName + ) + internal + view + returns (PeripheryJsonData memory data) { // Use the current project root for periphery deployment files string memory peripheryRoot = vm.projectRoot(); - // Map chain ID to chain name - string memory chainName = _getChainName(chainId); - string memory envName; if (env == 0) { envName = "prod"; @@ -358,39 +379,70 @@ contract ConfigureV2Periphery is DeployV2Base { envName = "staging"; // env=2 } - // Construct path: script/output/{env}/{chainId}/{ChainName}-latest.json - string memory outputPath = string( - abi.encodePacked( - peripheryRoot, - "/script/output/", - envName, - "/", - vm.toString(uint256(chainId)), - "/", - chainName, - "-latest.json" - ) + // Read from latest.json which contains all networks + string memory latestPath = string( + abi.encodePacked(peripheryRoot, "/script/output/", envName, "/latest.json") ); - console2.log("Reading periphery contracts from:", outputPath); + console2.log("Reading periphery contracts from:", latestPath); - try vm.readFile(outputPath) returns (string memory fileContent) { - console2.log("Successfully read periphery deployment file"); - return fileContent; + try vm.readFile(latestPath) returns (string memory fileContent) { + console2.log("Successfully read latest.json"); + + // Extract the contracts for this specific chain + string memory chainName = _getChainNameFromLatestJson(fileContent, chainId); + if (bytes(chainName).length == 0) { + console2.log("Chain ID not found in latest.json:", chainId); + return data; // Return empty data + } + + console2.log("Found network:", chainName); + + // Verify the contracts section exists for this network + string memory contractsKey = string(abi.encodePacked(".networks.", chainName, ".contracts")); + try vm.parseJson(fileContent, contractsKey) returns (bytes memory) { + data.json = fileContent; + data.chainName = chainName; + return data; + } catch { + console2.log("Failed to parse contracts for network:", chainName); + return data; // Return empty data + } } catch { - console2.log("Failed to read periphery deployment file:", outputPath); - return ""; + console2.log("Failed to read latest.json:", latestPath); + return data; // Return empty data } } - /// @notice Get chain name from chain ID + /// @notice Get chain name from chain ID (for file paths) function _getChainName(uint64 chainId) internal pure returns (string memory) { if (chainId == 1) return "Ethereum"; if (chainId == 8453) return "Base"; if (chainId == 10) return "Optimism"; + if (chainId == 42161) return "Arbitrum"; + if (chainId == 137) return "Polygon"; + if (chainId == 43114) return "Avalanche"; + if (chainId == 56) return "BNB"; + if (chainId == 80094) return "Berachain"; + if (chainId == 146) return "Sonic"; + if (chainId == 100) return "Gnosis"; + if (chainId == 130) return "Unichain"; + if (chainId == 480) return "Worldchain"; + if (chainId == 999) return "HyperEVM"; return "Unknown"; } + /// @notice Get chain name from latest.json by searching for chain ID + /// @dev Returns empty string for unknown chains (so caller can handle gracefully) + function _getChainNameFromLatestJson(string memory, uint64 chainId) internal pure returns (string memory) { + string memory name = _getChainName(chainId); + // Return empty for "Unknown" so caller handles missing chains gracefully + if (keccak256(bytes(name)) == keccak256(bytes("Unknown"))) { + return ""; + } + return name; + } + /// @notice Hook registration result codes uint256 internal constant HOOK_NOT_DEPLOYED = 0; uint256 internal constant HOOK_NEWLY_REGISTERED = 1; @@ -400,7 +452,7 @@ contract ConfigureV2Periphery is DeployV2Base { /// @notice Register all hooks with SuperGovernor function _registerAllHooks(address superGovernor, HookAddresses memory hooks) internal { ISuperGovernor governor = ISuperGovernor(superGovernor); - uint256 totalHooks = 26; // Total number of hooks in HookAddresses struct + uint256 totalHooks = 27; // Total number of hooks in HookAddresses struct uint256 newlyRegistered = 0; uint256 alreadyRegistered = 0; uint256 notDeployed = 0; @@ -522,6 +574,10 @@ contract ConfigureV2Periphery is DeployV2Base { (newlyRegistered, alreadyRegistered, notDeployed, failed) = _updateCounts(result, newlyRegistered, alreadyRegistered, notDeployed, failed); + result = _registerHook(governor, hooks.pendleUnifiedHook, "pendleUnifiedHook"); + (newlyRegistered, alreadyRegistered, notDeployed, failed) = + _updateCounts(result, newlyRegistered, alreadyRegistered, notDeployed, failed); + // Across bridge hooks result = _registerHook(governor, hooks.acrossSendFundsAndExecuteOnDstHook, "acrossSendFundsAndExecuteOnDstHook"); (newlyRegistered, alreadyRegistered, notDeployed, failed) = diff --git a/script/DeploySuperVaultBatchOperator.s.sol b/script/DeploySuperVaultBatchOperator.s.sol index b0804f741..2f7f7e606 100644 --- a/script/DeploySuperVaultBatchOperator.s.sol +++ b/script/DeploySuperVaultBatchOperator.s.sol @@ -98,16 +98,6 @@ contract DeploySuperVaultBatchOperator is DeployV2Base { console2.log("====== Check Complete ======"); } - /// @notice Validate environment and branchName combination - /// @param env Environment (0 = prod, 1 = vnet, 2 = staging) - /// @param branchName Branch name (required for vnet) - function _validateEnvAndBranchName(uint256 env, string calldata branchName) internal pure { - require(env == 0 || env == 1 || env == 2, "INVALID_ENV"); - if (env == 1) { - require(bytes(branchName).length > 0, "BRANCH_NAME_REQUIRED_FOR_VNET"); - } - } - /// @notice Get operator address based on environment /// @param env Environment (0 = prod, 1 = vnet, 2 = staging) function _getOperatorForEnv(uint256 env) internal pure returns (address) { diff --git a/script/DeployUpOFT.s.sol b/script/DeployUpOFT.s.sol index 05e7ddd86..3953dbe3f 100644 --- a/script/DeployUpOFT.s.sol +++ b/script/DeployUpOFT.s.sol @@ -27,9 +27,11 @@ contract DeployUpOFT is Script { uint32 internal constant ETH_EID = 30101; uint32 internal constant BASE_EID = 30184; + uint32 internal constant HYPEREVM_EID = 30367; uint64 internal constant MAINNET_CHAIN_ID = 1; uint64 internal constant BASE_CHAIN_ID = 8453; + uint64 internal constant HYPEREVM_CHAIN_ID = 999; uint16 internal constant SEND = 1; uint16 internal constant SEND_AND_CALL = 2; @@ -56,6 +58,13 @@ contract DeployUpOFT is Script { address internal constant EXECUTOR_ETH = 0x173272739Bd7Aa6e4e214714048a9fE699453059; address internal constant EXECUTOR_BASE = 0x2CCA08ae69E0C44b18a57Ab2A87644234dAebaE4; + // HyperEVM LayerZero V2 contracts + address internal constant LZ_ENDPOINT_HYPEREVM = 0x3A73033C0b1407574C76BdBAc67f126f6b4a9AA9; + address internal constant DVN_LZ_HYPEREVM = 0xc097ab8CD7b053326DFe9fB3E3a31a0CCe3B526f; // DVN LZ HyperEVM + address internal constant SEND_LIB_HYPEREVM = 0xfd76d9CB0Bac839725aB79127E7411fe71b1e3CA; + address internal constant RECEIVE_LIB_HYPEREVM = 0x7cacBe439EaD55fa1c22790330b12835c6884a91; + address internal constant EXECUTOR_HYPEREVM = 0x41Bdb4aa4A63a5b2Efc531858d3118392B1A1C3d; + uint32 internal constant GRACE_PERIOD = 0; string internal constant MNEMONIC = "test test test test test test test test test test test junk"; @@ -64,13 +73,22 @@ contract DeployUpOFT is Script { UlnConfig ulnEthToBase; UlnConfig ulnBaseToEth; + UlnConfig ulnEthToHyperEVM; + UlnConfig ulnHyperEVMToEth; + UlnConfig ulnBaseToHyperEVM; + UlnConfig ulnHyperEVMToBase; ExecutorConfig execEthToBase; ExecutorConfig execBaseToEth; + ExecutorConfig execEthToHyperEVM; + ExecutorConfig execHyperEVMToEth; + ExecutorConfig execBaseToHyperEVM; + ExecutorConfig execHyperEVMToBase; struct OFTContracts { address adapter; address oft; + address oftHyperEVM; } modifier broadcast(uint256 env) { @@ -133,6 +151,71 @@ contract DeployUpOFT is Script { maxMessageSize: 10_000, executor: EXECUTOR_BASE }); + + // HyperEVM pathway configs (single DVN - LayerZero Labs only) + address[] memory dvnsHyperEVM = new address[](1); + dvnsHyperEVM[0] = DVN_LZ_HYPEREVM; + ulnHyperEVMToEth = UlnConfig({ + confirmations: 15, + requiredDVNCount: 1, + optionalDVNCount: type(uint8).max, + optionalDVNThreshold: 0, + requiredDVNs: dvnsHyperEVM, + optionalDVNs: new address[](0) + }); + + // ETH to HyperEVM uses ETH DVNs + address[] memory dvnsEthForHyperEVM = new address[](1); + dvnsEthForHyperEVM[0] = DVN1_ETH; // Only LZ Labs DVN for HyperEVM pathway + ulnEthToHyperEVM = UlnConfig({ + confirmations: 15, + requiredDVNCount: 1, + optionalDVNCount: type(uint8).max, + optionalDVNThreshold: 0, + requiredDVNs: dvnsEthForHyperEVM, + optionalDVNs: new address[](0) + }); + + execEthToHyperEVM = ExecutorConfig({ + maxMessageSize: 10_000, + executor: EXECUTOR_ETH + }); + + execHyperEVMToEth = ExecutorConfig({ + maxMessageSize: 10_000, + executor: EXECUTOR_HYPEREVM + }); + + // Base to HyperEVM uses Base DVNs (only LZ Labs for HyperEVM pathway) + address[] memory dvnsBaseForHyperEVM = new address[](1); + dvnsBaseForHyperEVM[0] = DVN1_BASE; // Only LZ Labs DVN for HyperEVM pathway + ulnBaseToHyperEVM = UlnConfig({ + confirmations: 15, + requiredDVNCount: 1, + optionalDVNCount: type(uint8).max, + optionalDVNThreshold: 0, + requiredDVNs: dvnsBaseForHyperEVM, + optionalDVNs: new address[](0) + }); + + ulnHyperEVMToBase = UlnConfig({ + confirmations: 15, + requiredDVNCount: 1, + optionalDVNCount: type(uint8).max, + optionalDVNThreshold: 0, + requiredDVNs: dvnsHyperEVM, // Already defined above + optionalDVNs: new address[](0) + }); + + execBaseToHyperEVM = ExecutorConfig({ + maxMessageSize: 10_000, + executor: EXECUTOR_BASE + }); + + execHyperEVMToBase = ExecutorConfig({ + maxMessageSize: 10_000, + executor: EXECUTOR_HYPEREVM + }); } function deployAdapter(uint256 env) public { @@ -425,6 +508,573 @@ contract DeployUpOFT is Script { console2.log("============================================"); } + // ============ HyperEVM Functions ============ + + function deployOFTOnHyperEVM(uint256 env) public { + _deployOFTOnHyperEVMWithBroadcast(env, ""); + } + + function deployOFTOnHyperEVM(uint256 env, string memory saltNamespace) public { + _deployOFTOnHyperEVMWithBroadcast(env, saltNamespace); + } + + function _deployOFTOnHyperEVMWithBroadcast(uint256 env, string memory saltNamespace) internal broadcast(env) { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + address owner; + if (env == 1) { + (owner,) = deriveRememberKey(MNEMONIC, 0); + } else { + owner = msg.sender; + } + + console2.log(""); + console2.log("====== Deploying UpOFT on HyperEVM ======"); + console2.log("Chain ID:", block.chainid); + console2.log("Owner:", owner); + + address deployed = _deployOFTHyperEVM(owner); + + console2.log(""); + console2.log("UpOFT deployed:", deployed); + console2.log("========================================="); + } + + function configurePeerOnHyperEVM(uint256 env) public { + _configurePeerOnHyperEVMWithBroadcast(env, ""); + } + + function configurePeerOnHyperEVM(uint256 env, string memory saltNamespace) public { + _configurePeerOnHyperEVMWithBroadcast(env, saltNamespace); + } + + function _configurePeerOnHyperEVMWithBroadcast(uint256 env, string memory saltNamespace) internal broadcast(env) { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Configuring Peer on HyperEVM ======"); + console2.log("UpOFT:", contracts.oftHyperEVM); + console2.log("Peer (Ethereum UpOFTAdapter):", contracts.adapter); + + if (contracts.oftHyperEVM.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping peer configuration"); + return; + } + _setPeer(contracts.oftHyperEVM, ETH_EID, contracts.adapter); + console2.log("[+] Peer configured successfully"); + console2.log("=========================================="); + } + + function configurePeerOnEthereumForHyperEVM(uint256 env) public { + _configurePeerOnEthereumForHyperEVMWithBroadcast(env, "", address(0)); + } + + function configurePeerOnEthereumForHyperEVM(uint256 env, string memory saltNamespace) public { + _configurePeerOnEthereumForHyperEVMWithBroadcast(env, saltNamespace, address(0)); + } + + /// @param hyperEvmOft Explicit HyperEVM UpOFT address (use when caller is not the HyperEVM deployer) + function configurePeerOnEthereumForHyperEVM(uint256 env, address hyperEvmOft) public { + _configurePeerOnEthereumForHyperEVMWithBroadcast(env, "", hyperEvmOft); + } + + function _configurePeerOnEthereumForHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace, + address hyperEvmOftOverride + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == MAINNET_CHAIN_ID, "Must run on Ethereum"); + + OFTContracts memory contracts = _computeAddresses(); + address hyperEvmOft = hyperEvmOftOverride != address(0) ? hyperEvmOftOverride : contracts.oftHyperEVM; + + console2.log(""); + console2.log("====== Configuring Peer on Ethereum for HyperEVM ======"); + console2.log("UpOFTAdapter:", contracts.adapter); + console2.log("Peer (HyperEVM UpOFT):", hyperEvmOft); + + if (contracts.adapter.code.length == 0) { + console2.log("[!] UpOFTAdapter not deployed yet, skipping peer configuration"); + return; + } + _setPeer(contracts.adapter, HYPEREVM_EID, hyperEvmOft); + console2.log("[+] Peer configured successfully"); + console2.log("========================================================"); + } + + function setEnforcedOptionsOnHyperEVM(uint256 env) public { + _setEnforcedOptionsOnHyperEVMWithBroadcast(env, ""); + } + + function setEnforcedOptionsOnHyperEVM(uint256 env, string memory saltNamespace) public { + _setEnforcedOptionsOnHyperEVMWithBroadcast(env, saltNamespace); + } + + function _setEnforcedOptionsOnHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Setting Enforced Options on HyperEVM ======"); + console2.log("UpOFT:", contracts.oftHyperEVM); + console2.log("Destination: Ethereum (EID:", ETH_EID, ")"); + + if (contracts.oftHyperEVM.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping enforced options"); + return; + } + _setEnforcedOptions(contracts.oftHyperEVM, ETH_EID); + console2.log("[+] Enforced options set successfully"); + console2.log("=================================================="); + } + + function setEnforcedOptionsOnEthereumForHyperEVM(uint256 env) public { + _setEnforcedOptionsOnEthereumForHyperEVMWithBroadcast(env, ""); + } + + function setEnforcedOptionsOnEthereumForHyperEVM(uint256 env, string memory saltNamespace) public { + _setEnforcedOptionsOnEthereumForHyperEVMWithBroadcast(env, saltNamespace); + } + + function _setEnforcedOptionsOnEthereumForHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == MAINNET_CHAIN_ID, "Must run on Ethereum"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Setting Enforced Options on Ethereum for HyperEVM ======"); + console2.log("UpOFTAdapter:", contracts.adapter); + console2.log("Destination: HyperEVM (EID:", HYPEREVM_EID, ")"); + + if (contracts.adapter.code.length == 0) { + console2.log("[!] UpOFTAdapter not deployed yet, skipping enforced options"); + return; + } + _setEnforcedOptions(contracts.adapter, HYPEREVM_EID); + console2.log("[+] Enforced options set successfully"); + console2.log("================================================================"); + } + + function configureLibrariesOnHyperEVM(uint256 env) public { + _configureLibrariesOnHyperEVMWithBroadcast(env, ""); + } + + function configureLibrariesOnHyperEVM(uint256 env, string memory saltNamespace) public { + _configureLibrariesOnHyperEVMWithBroadcast(env, saltNamespace); + } + + function _configureLibrariesOnHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Configuring Libraries on HyperEVM ======"); + console2.log("UpOFT:", contracts.oftHyperEVM); + console2.log("SendLib:", SEND_LIB_HYPEREVM); + console2.log("ReceiveLib:", RECEIVE_LIB_HYPEREVM); + console2.log("DVN (LZ Labs):", DVN_LZ_HYPEREVM); + console2.log("Executor:", EXECUTOR_HYPEREVM); + + if (contracts.oftHyperEVM.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping library configuration"); + return; + } + + _setLibrariesHyperEVM({ + oapp: contracts.oftHyperEVM, + dstEid: ETH_EID, + srcEid: ETH_EID, + sendLib: SEND_LIB_HYPEREVM, + receiveLib: RECEIVE_LIB_HYPEREVM, + gracePeriod: GRACE_PERIOD + }); + console2.log("[+] Send/Receive libraries set"); + + _setSendConfigHyperEVM({ + oapp: contracts.oftHyperEVM, + remoteEid: ETH_EID, + sendLib: SEND_LIB_HYPEREVM, + uln: ulnHyperEVMToEth, + exec: execHyperEVMToEth + }); + console2.log("[+] Send config (ULN + Executor) set"); + + _setReceiveConfigHyperEVM({ + oapp: contracts.oftHyperEVM, + remoteEid: ETH_EID, + receiveLib: RECEIVE_LIB_HYPEREVM, + uln: ulnHyperEVMToEth + }); + console2.log("[+] Receive config (ULN) set"); + + console2.log("================================================"); + } + + function configureLibrariesOnEthereumForHyperEVM(uint256 env) public { + _configureLibrariesOnEthereumForHyperEVMWithBroadcast(env, ""); + } + + function configureLibrariesOnEthereumForHyperEVM(uint256 env, string memory saltNamespace) public { + _configureLibrariesOnEthereumForHyperEVMWithBroadcast(env, saltNamespace); + } + + function _configureLibrariesOnEthereumForHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == MAINNET_CHAIN_ID, "Must run on Ethereum"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Configuring Libraries on Ethereum for HyperEVM ======"); + console2.log("UpOFTAdapter:", contracts.adapter); + console2.log("SendLib:", SEND_LIB_ETH); + console2.log("ReceiveLib:", RECEIVE_LIB_ETH); + console2.log("DVN (LZ Labs):", DVN1_ETH); + console2.log("Executor:", EXECUTOR_ETH); + + if (contracts.adapter.code.length == 0) { + console2.log("[!] UpOFTAdapter not deployed yet, skipping library configuration"); + return; + } + + _setLibraries({ + oapp: contracts.adapter, + dstEid: HYPEREVM_EID, + srcEid: HYPEREVM_EID, + sendLib: SEND_LIB_ETH, + receiveLib: RECEIVE_LIB_ETH, + gracePeriod: GRACE_PERIOD + }); + console2.log("[+] Send/Receive libraries set"); + + _setSendConfig({ + oapp: contracts.adapter, + remoteEid: HYPEREVM_EID, + sendLib: SEND_LIB_ETH, + uln: ulnEthToHyperEVM, + exec: execEthToHyperEVM + }); + console2.log("[+] Send config (ULN + Executor) set"); + + _setReceiveConfig({ + oapp: contracts.adapter, + remoteEid: HYPEREVM_EID, + receiveLib: RECEIVE_LIB_ETH, + uln: ulnEthToHyperEVM + }); + console2.log("[+] Receive config (ULN) set"); + + console2.log("============================================================"); + } + + // ============ HyperEVM <-> Base Functions ============ + + function configurePeerOnHyperEVMForBase(uint256 env) public { + _configurePeerOnHyperEVMForBaseWithBroadcast(env, ""); + } + + function configurePeerOnHyperEVMForBase(uint256 env, string memory saltNamespace) public { + _configurePeerOnHyperEVMForBaseWithBroadcast(env, saltNamespace); + } + + function _configurePeerOnHyperEVMForBaseWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Configuring Peer on HyperEVM for Base ======"); + console2.log("UpOFT:", contracts.oftHyperEVM); + console2.log("Peer (Base UpOFT):", contracts.oft); + + if (contracts.oftHyperEVM.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping peer configuration"); + return; + } + _setPeer(contracts.oftHyperEVM, BASE_EID, contracts.oft); + console2.log("[+] Peer configured successfully"); + console2.log("=================================================="); + } + + function configurePeerOnBaseForHyperEVM(uint256 env) public { + _configurePeerOnBaseForHyperEVMWithBroadcast(env, "", address(0)); + } + + function configurePeerOnBaseForHyperEVM(uint256 env, string memory saltNamespace) public { + _configurePeerOnBaseForHyperEVMWithBroadcast(env, saltNamespace, address(0)); + } + + /// @param hyperEvmOft Explicit HyperEVM UpOFT address (use when caller is not the HyperEVM deployer) + function configurePeerOnBaseForHyperEVM(uint256 env, address hyperEvmOft) public { + _configurePeerOnBaseForHyperEVMWithBroadcast(env, "", hyperEvmOft); + } + + function _configurePeerOnBaseForHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace, + address hyperEvmOftOverride + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == BASE_CHAIN_ID, "Must run on Base"); + + OFTContracts memory contracts = _computeAddresses(); + address hyperEvmOft = hyperEvmOftOverride != address(0) ? hyperEvmOftOverride : contracts.oftHyperEVM; + + console2.log(""); + console2.log("====== Configuring Peer on Base for HyperEVM ======"); + console2.log("UpOFT:", contracts.oft); + console2.log("Peer (HyperEVM UpOFT):", hyperEvmOft); + + if (contracts.oft.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping peer configuration"); + return; + } + _setPeer(contracts.oft, HYPEREVM_EID, hyperEvmOft); + console2.log("[+] Peer configured successfully"); + console2.log("=================================================="); + } + + function setEnforcedOptionsOnHyperEVMForBase(uint256 env) public { + _setEnforcedOptionsOnHyperEVMForBaseWithBroadcast(env, ""); + } + + function setEnforcedOptionsOnHyperEVMForBase(uint256 env, string memory saltNamespace) public { + _setEnforcedOptionsOnHyperEVMForBaseWithBroadcast(env, saltNamespace); + } + + function _setEnforcedOptionsOnHyperEVMForBaseWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Setting Enforced Options on HyperEVM for Base ======"); + console2.log("UpOFT:", contracts.oftHyperEVM); + console2.log("Destination: Base (EID:", BASE_EID, ")"); + + if (contracts.oftHyperEVM.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping enforced options"); + return; + } + _setEnforcedOptions(contracts.oftHyperEVM, BASE_EID); + console2.log("[+] Enforced options set successfully"); + console2.log("=========================================================="); + } + + function setEnforcedOptionsOnBaseForHyperEVM(uint256 env) public { + _setEnforcedOptionsOnBaseForHyperEVMWithBroadcast(env, ""); + } + + function setEnforcedOptionsOnBaseForHyperEVM(uint256 env, string memory saltNamespace) public { + _setEnforcedOptionsOnBaseForHyperEVMWithBroadcast(env, saltNamespace); + } + + function _setEnforcedOptionsOnBaseForHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == BASE_CHAIN_ID, "Must run on Base"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Setting Enforced Options on Base for HyperEVM ======"); + console2.log("UpOFT:", contracts.oft); + console2.log("Destination: HyperEVM (EID:", HYPEREVM_EID, ")"); + + if (contracts.oft.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping enforced options"); + return; + } + _setEnforcedOptions(contracts.oft, HYPEREVM_EID); + console2.log("[+] Enforced options set successfully"); + console2.log("=========================================================="); + } + + function configureLibrariesOnHyperEVMForBase(uint256 env) public { + _configureLibrariesOnHyperEVMForBaseWithBroadcast(env, ""); + } + + function configureLibrariesOnHyperEVMForBase(uint256 env, string memory saltNamespace) public { + _configureLibrariesOnHyperEVMForBaseWithBroadcast(env, saltNamespace); + } + + function _configureLibrariesOnHyperEVMForBaseWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == HYPEREVM_CHAIN_ID, "Must run on HyperEVM"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Configuring Libraries on HyperEVM for Base ======"); + console2.log("UpOFT:", contracts.oftHyperEVM); + console2.log("SendLib:", SEND_LIB_HYPEREVM); + console2.log("ReceiveLib:", RECEIVE_LIB_HYPEREVM); + console2.log("DVN (LZ Labs):", DVN_LZ_HYPEREVM); + console2.log("Executor:", EXECUTOR_HYPEREVM); + + if (contracts.oftHyperEVM.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping library configuration"); + return; + } + + _setLibrariesHyperEVM({ + oapp: contracts.oftHyperEVM, + dstEid: BASE_EID, + srcEid: BASE_EID, + sendLib: SEND_LIB_HYPEREVM, + receiveLib: RECEIVE_LIB_HYPEREVM, + gracePeriod: GRACE_PERIOD + }); + console2.log("[+] Send/Receive libraries set"); + + _setSendConfigHyperEVM({ + oapp: contracts.oftHyperEVM, + remoteEid: BASE_EID, + sendLib: SEND_LIB_HYPEREVM, + uln: ulnHyperEVMToBase, + exec: execHyperEVMToBase + }); + console2.log("[+] Send config (ULN + Executor) set"); + + _setReceiveConfigHyperEVM({ + oapp: contracts.oftHyperEVM, + remoteEid: BASE_EID, + receiveLib: RECEIVE_LIB_HYPEREVM, + uln: ulnHyperEVMToBase + }); + console2.log("[+] Receive config (ULN) set"); + + console2.log("========================================================"); + } + + function configureLibrariesOnBaseForHyperEVM(uint256 env) public { + _configureLibrariesOnBaseForHyperEVMWithBroadcast(env, ""); + } + + function configureLibrariesOnBaseForHyperEVM(uint256 env, string memory saltNamespace) public { + _configureLibrariesOnBaseForHyperEVMWithBroadcast(env, saltNamespace); + } + + function _configureLibrariesOnBaseForHyperEVMWithBroadcast( + uint256 env, + string memory saltNamespace + ) + internal + broadcast(env) + { + _setConfiguration(env, saltNamespace); + require(block.chainid == BASE_CHAIN_ID, "Must run on Base"); + + OFTContracts memory contracts = _computeAddresses(); + + console2.log(""); + console2.log("====== Configuring Libraries on Base for HyperEVM ======"); + console2.log("UpOFT:", contracts.oft); + console2.log("SendLib:", SEND_LIB_BASE); + console2.log("ReceiveLib:", RECEIVE_LIB_BASE); + console2.log("DVN (LZ Labs):", DVN1_BASE); + console2.log("Executor:", EXECUTOR_BASE); + + if (contracts.oft.code.length == 0) { + console2.log("[!] UpOFT not deployed yet, skipping library configuration"); + return; + } + + _setLibraries({ + oapp: contracts.oft, + dstEid: HYPEREVM_EID, + srcEid: HYPEREVM_EID, + sendLib: SEND_LIB_BASE, + receiveLib: RECEIVE_LIB_BASE, + gracePeriod: GRACE_PERIOD + }); + console2.log("[+] Send/Receive libraries set"); + + _setSendConfig({ + oapp: contracts.oft, + remoteEid: HYPEREVM_EID, + sendLib: SEND_LIB_BASE, + uln: ulnBaseToHyperEVM, + exec: execBaseToHyperEVM + }); + console2.log("[+] Send config (ULN + Executor) set"); + + _setReceiveConfig({ + oapp: contracts.oft, + remoteEid: HYPEREVM_EID, + receiveLib: RECEIVE_LIB_BASE, + uln: ulnBaseToHyperEVM + }); + console2.log("[+] Receive config (ULN) set"); + + console2.log("========================================================"); + } + function _computeAddresses() internal returns (OFTContracts memory contracts) { return _computeAddresses(msg.sender); } @@ -436,6 +1086,10 @@ contract DeployUpOFT is Script { bytes memory oftBytecode = abi.encodePacked(type(UpOFT).creationCode, abi.encode(LZ_ENDPOINT, owner)); contracts.oft = DeterministicDeployerLib.computeAddress(oftBytecode, _getSalt("UpOFT")); + + bytes memory oftHyperEVMBytecode = + abi.encodePacked(type(UpOFT).creationCode, abi.encode(LZ_ENDPOINT_HYPEREVM, owner)); + contracts.oftHyperEVM = DeterministicDeployerLib.computeAddress(oftHyperEVMBytecode, _getSalt("UpOFT")); } function _deployAdapter(address owner) internal returns (address) { @@ -475,6 +1129,24 @@ contract DeployUpOFT is Script { return deployed; } + function _deployOFTHyperEVM(address owner) internal returns (address) { + bytes32 salt = _getSalt("UpOFT"); + bytes memory bytecode = abi.encodePacked(type(UpOFT).creationCode, abi.encode(LZ_ENDPOINT_HYPEREVM, owner)); + + address predicted = DeterministicDeployerLib.computeAddress(bytecode, salt); + + if (predicted.code.length > 0) { + console2.log("[!] UpOFT HyperEVM already deployed, skipping..."); + return predicted; + } + + address deployed = DeterministicDeployerLib.deploy(bytecode, salt); + require(deployed == predicted, "Address mismatch"); + require(deployed.code.length > 0, "Deployment failed"); + + return deployed; + } + function _setPeer(address oapp, uint32 peerEid, address peerAddress) internal { bytes32 peerBytes32 = bytes32(uint256(uint160(peerAddress))); @@ -543,6 +1215,48 @@ contract DeployUpOFT is Script { ILayerZeroEndpointV2(LZ_ENDPOINT).setConfig(oapp, receiveLib, params); } + // HyperEVM-specific library functions (use LZ_ENDPOINT_HYPEREVM) + function _setLibrariesHyperEVM( + address oapp, + uint32 dstEid, + uint32 srcEid, + address sendLib, + address receiveLib, + uint32 gracePeriod + ) internal { + // outbound messages to dstEid use sendLib + ILayerZeroEndpointV2(LZ_ENDPOINT_HYPEREVM).setSendLibrary(oapp, dstEid, sendLib); + + // inbound messages from srcEid use receiveLib + ILayerZeroEndpointV2(LZ_ENDPOINT_HYPEREVM).setReceiveLibrary(oapp, srcEid, receiveLib, gracePeriod); + } + + function _setSendConfigHyperEVM( + address oapp, + uint32 remoteEid, + address sendLib, + UlnConfig memory uln, + ExecutorConfig memory exec + ) internal { + SetConfigParam[] memory params = new SetConfigParam[](2); + params[0] = SetConfigParam(remoteEid, EXECUTOR_CONFIG_TYPE, abi.encode(exec)); + params[1] = SetConfigParam(remoteEid, ULN_CONFIG_TYPE, abi.encode(uln)); + + ILayerZeroEndpointV2(LZ_ENDPOINT_HYPEREVM).setConfig(oapp, sendLib, params); + } + + function _setReceiveConfigHyperEVM( + address oapp, + uint32 remoteEid, + address receiveLib, + UlnConfig memory uln + ) internal { + SetConfigParam[] memory params = new SetConfigParam[](1); + params[0] = SetConfigParam(remoteEid, ULN_CONFIG_TYPE, abi.encode(uln)); + + ILayerZeroEndpointV2(LZ_ENDPOINT_HYPEREVM).setConfig(oapp, receiveLib, params); + } + function _getSalt(string memory name) internal view returns (bytes32) { return keccak256(abi.encodePacked("SuperformV2", SALT_NAMESPACE, name, "v2.0")); } @@ -619,9 +1333,17 @@ contract DeployUpOFT is Script { _exportContract("UpOFT", contracts.oft, BASE_CHAIN_ID); _writeExportedContracts(BASE_CHAIN_ID, envName); + // Reset for HyperEVM + contractCount[BASE_CHAIN_ID] = 0; + + // Export HyperEVM contracts + _exportContract("UpOFT", contracts.oftHyperEVM, HYPEREVM_CHAIN_ID); + _writeExportedContracts(HYPEREVM_CHAIN_ID, envName); + console2.log(""); console2.log("====== Export Complete ======"); console2.log("UpOFTAdapter (Ethereum):", contracts.adapter); console2.log("UpOFT (Base):", contracts.oft); + console2.log("UpOFT (HyperEVM):", contracts.oftHyperEVM); } } diff --git a/script/DeployV2Base.s.sol b/script/DeployV2Base.s.sol index 532b82162..43d6e1ed7 100644 --- a/script/DeployV2Base.s.sol +++ b/script/DeployV2Base.s.sol @@ -47,6 +47,20 @@ abstract contract DeployV2Base is Script, ConfigBase { } } + /*////////////////////////////////////////////////////////////// + ENV VALIDATION + //////////////////////////////////////////////////////////////*/ + + /// @notice Validate environment and branchName combination + /// @param env Environment (0 = prod, 1 = vnet, 2 = staging) + /// @param branchName Branch name (required for vnet) + function _validateEnvAndBranchName(uint256 env, string calldata branchName) internal pure { + require(env == 0 || env == 1 || env == 2, "INVALID_ENV"); + if (env == 1) { + require(bytes(branchName).length > 0, "BRANCH_NAME_REQUIRED_FOR_VNET"); + } + } + function _getContract(uint64 chainId, string memory contractName) internal view returns (address) { return contractAddresses[chainId][contractName]; } @@ -66,19 +80,20 @@ abstract contract DeployV2Base is Script, ConfigBase { internal returns (address deployedAddr) { - console2.log("[!] Deploying %s...", contractName); - // Predict address first address predictedAddr = DeterministicDeployerLib.computeAddress(creationCode, salt); + // Check if already deployed BEFORE logging "Deploying" if (predictedAddr.code.length > 0) { - console2.log("[!] %s already deployed at:", contractName, predictedAddr); + console2.log("[=] %s already deployed at:", contractName, predictedAddr); console2.log(" skipping..."); contractAddresses[chainId][contractName] = predictedAddr; _exportContract(contractName, predictedAddr, chainId); return predictedAddr; } + console2.log("[!] Deploying %s...", contractName); + // Deploy using DeterministicDeployerLib deployedAddr = DeterministicDeployerLib.deploy(creationCode, salt); @@ -460,8 +475,62 @@ abstract contract DeployV2Base is Script, ConfigBase { // Write to {ChainName}-latest.json string memory outputPath = string(abi.encodePacked(root, chainOutputFolder, chainName, "-latest.json")); - vm.writeJson(exportedContracts[chainId], outputPath); + + // Merge with existing file if it exists + string memory finalJson = _mergeWithExistingJson(outputPath, chainId); + + vm.writeJson(finalJson, outputPath); console2.log("Exported", contractCount[chainId], "contracts to:", outputPath); } + + /// @notice Merge new exports with existing JSON file content + /// @param filePath Path to the existing JSON file + /// @param chainId Chain ID for the exports + /// @return Merged JSON string + function _mergeWithExistingJson(string memory filePath, uint64 chainId) internal returns (string memory) { + string memory objectKey = string(abi.encodePacked("MERGED_", vm.toString(uint256(chainId)))); + string memory result; + + // Try to read existing file + try vm.readFile(filePath) returns (string memory existingContent) { + if (bytes(existingContent).length > 0) { + // Parse existing keys and re-serialize them first + string[] memory keys = vm.parseJsonKeys(existingContent, "$"); + + for (uint256 i = 0; i < keys.length; i++) { + // Get the address for this key + string memory jsonPath = string(abi.encodePacked(".", keys[i])); + address existingAddr = vm.parseJsonAddress(existingContent, jsonPath); + + // Re-serialize existing contract (this adds to the object) + result = vm.serializeAddress(objectKey, keys[i], existingAddr); + } + } + } catch { + // File doesn't exist or can't be read, that's fine + } + + // Now add all new exports (this may overwrite existing keys with same name) + // Parse new exports and add them + string memory newExports = exportedContracts[chainId]; + if (bytes(newExports).length > 0) { + string[] memory newKeys = vm.parseJsonKeys(newExports, "$"); + + for (uint256 i = 0; i < newKeys.length; i++) { + string memory jsonPath = string(abi.encodePacked(".", newKeys[i])); + address newAddr = vm.parseJsonAddress(newExports, jsonPath); + + // Serialize (this overwrites any existing entry with same key) + result = vm.serializeAddress(objectKey, newKeys[i], newAddr); + } + } + + // Return the final merged JSON + // If nothing was serialized, return the original exports + if (bytes(result).length == 0) { + return exportedContracts[chainId]; + } + return result; + } } diff --git a/script/DeployV2Periphery.s.sol b/script/DeployV2Periphery.s.sol index 9d42d5657..a4c50a483 100644 --- a/script/DeployV2Periphery.s.sol +++ b/script/DeployV2Periphery.s.sol @@ -141,8 +141,8 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { totalGasEstimate += _estimateContractGas(SUPER_GOVERNOR_KEY, chainId, env); totalGasEstimate += _estimateContractGas(ECDSAPPS_ORACLE_KEY, chainId, env); totalGasEstimate += _estimateContractGas(FIXED_PRICE_ORACLE_KEY, chainId, env); - // SuperOracle (mainnet) or SuperOracleL2 (L2 chains) - same 3 feeds configuration - if (chainId == MAINNET_CHAIN_ID) { + // SuperOracle (mainnet/HyperEVM) or SuperOracleL2 (L2 chains with sequencer uptime feed) + if (chainId == MAINNET_CHAIN_ID || chainId == HYPEREVM_CHAIN_ID) { totalGasEstimate += _estimateContractGas(SUPER_ORACLE_KEY, chainId, env); } else { totalGasEstimate += _estimateContractGas(SUPER_ORACLE_L2_KEY, chainId, env); @@ -343,7 +343,7 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { address fixedPriceOracleAddr = _checkFixedPriceOracle(); // Check SuperOracle (same deployment for all chains with chain-specific addresses) - _checkSuperOracle(chainId, superGovernorAddr, fixedPriceOracleAddr); + _checkSuperOracle(chainId, superGovernorAddr, fixedPriceOracleAddr, env); // Check SuperBank _checkSuperBank(superGovernorAddr); @@ -430,7 +430,7 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { /// @notice Check SuperOracle (mainnet) or SuperOracleL2 (L2s) with proper oracle feed configuration /// @dev Both mainnet and L2s use the same 3 feeds (GAS->WEI, ETH->USD, UP->USD) - function _checkSuperOracle(uint64 chainId, address superGovernorAddr, address fixedPriceOracleAddr) internal { + function _checkSuperOracle(uint64 chainId, address superGovernorAddr, address fixedPriceOracleAddr, uint256 env) internal { address[] memory bases = new address[](3); address[] memory quotes = new address[](3); bytes32[] memory providers = new bytes32[](3); @@ -453,6 +453,22 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { if (UP_TOKEN_BASE.code.length == 0) { console2.log("[WARNING] UP_TOKEN_BASE not deployed - ensure UP token is deployed before actual deployment"); } + } else if (chainId == HYPEREVM_CHAIN_ID) { + // Use staging addresses when env == 2 + if (env == 2) { + gasOracle = ORACLE_GAS_TO_WEI_HYPEREVM_STAGING; + upToken = UP_TOKEN_HYPEREVM_STAGING; + if (UP_TOKEN_HYPEREVM_STAGING.code.length == 0) { + console2.log("[WARNING] UP_TOKEN_HYPEREVM_STAGING not deployed - ensure UpOFT is deployed before actual deployment"); + } + } else { + gasOracle = ORACLE_GAS_TO_WEI_HYPEREVM; + upToken = UP_TOKEN_HYPEREVM; + if (UP_TOKEN_HYPEREVM.code.length == 0) { + console2.log("[WARNING] UP_TOKEN_HYPEREVM not deployed - ensure UpOFT is deployed before actual deployment"); + } + } + ethUsdOracle = ORACLE_ETH_USD_HYPEREVM; } else { revert("Oracle addresses not configured for this chain"); } @@ -477,7 +493,7 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { bytes memory superOracleArgs = abi.encode(superGovernorAddr, bases, quotes, providers, feeds); - if (chainId == MAINNET_CHAIN_ID) { + if (chainId == MAINNET_CHAIN_ID || chainId == HYPEREVM_CHAIN_ID) { __checkContractWithBytecode( SUPER_ORACLE_KEY, __getSalt(SUPER_ORACLE_KEY), type(SuperOracle).creationCode, superOracleArgs ); @@ -712,7 +728,7 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { // L2: ETH->USD only (gas oracle and UP oracle not available) if (env != 1) { peripheryContracts.superOracle = - _deploySuperOracle(chainId, peripheryContracts.superGovernor, peripheryContracts.fixedPriceOracle); + _deploySuperOracle(chainId, peripheryContracts.superGovernor, peripheryContracts.fixedPriceOracle, env); } else { console2.log("[!] Skipping SuperOracle deployment for test environment"); } @@ -736,11 +752,13 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { /// @param chainId The chain ID to deploy on /// @param superGovernor The SuperGovernor address /// @param fixedPriceOracle The FixedPriceOracle address for UP/USD pricing + /// @param env The environment (0=prod, 2=staging) /// @return superOracle The deployed SuperOracle/SuperOracleL2 address function _deploySuperOracle( uint64 chainId, address superGovernor, - address fixedPriceOracle + address fixedPriceOracle, + uint256 env ) internal returns (address superOracle) @@ -771,6 +789,22 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { if (UP_TOKEN_BASE.code.length == 0) { console2.log("[WARNING] UP_TOKEN_BASE not deployed - ensure UP token is deployed before actual deployment"); } + } else if (chainId == HYPEREVM_CHAIN_ID) { + // Use staging addresses when env == 2 + if (env == 2) { + gasOracle = ORACLE_GAS_TO_WEI_HYPEREVM_STAGING; + upToken = UP_TOKEN_HYPEREVM_STAGING; + if (UP_TOKEN_HYPEREVM_STAGING.code.length == 0) { + console2.log("[WARNING] UP_TOKEN_HYPEREVM_STAGING not deployed - ensure UpOFT is deployed before actual deployment"); + } + } else { + gasOracle = ORACLE_GAS_TO_WEI_HYPEREVM; + upToken = UP_TOKEN_HYPEREVM; + if (UP_TOKEN_HYPEREVM.code.length == 0) { + console2.log("[WARNING] UP_TOKEN_HYPEREVM not deployed - ensure UpOFT is deployed before actual deployment"); + } + } + ethUsdOracle = ORACLE_ETH_USD_HYPEREVM; } else { revert("Oracle addresses not configured for this chain"); } @@ -793,7 +827,7 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { providers[2] = PROVIDER_SUPERFORM; feeds[2] = fixedPriceOracle; - if (chainId == MAINNET_CHAIN_ID) { + if (chainId == MAINNET_CHAIN_ID || chainId == HYPEREVM_CHAIN_ID) { superOracle = __deployContractIfNeeded( SUPER_ORACLE_KEY, chainId, @@ -914,7 +948,8 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { // Step 6: Configure uptime feed for L2 chains (Chainlink oracles may be stale during sequencer downtime) // Skip for test environment (env == 1) since oracles not deployed - if (env != 1 && chainId != MAINNET_CHAIN_ID) { + // Skip for HyperEVM (no sequencer uptime feed) + if (env != 1 && chainId != MAINNET_CHAIN_ID && chainId != HYPEREVM_CHAIN_ID) { console2.log("[Step 6] Configuring L2 sequencer uptime feed..."); SuperGovernor governor = SuperGovernor(peripheryContracts.superGovernor); @@ -961,6 +996,8 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { } console2.log("[Step 6] DONE - Configured uptime feeds for ETH/USD, GAS/WEI, and UP/USD oracles"); + } else if (chainId == HYPEREVM_CHAIN_ID) { + console2.log("[Step 6] SKIPPED - HyperEVM has no sequencer uptime feed"); } // NOTE: Governor roles are granted to the deployer initially via configuration.governor @@ -1045,7 +1082,7 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { // Verify oracle feeds return valid prices via SuperOracle integration // Skip for test environment (env == 1) since oracles may not be available on vnet if (env != 1) { - _verifyOracleFeeds(peripheryContracts.superOracle, chainId); + _verifyOracleFeeds(peripheryContracts.superOracle, chainId, env); } else { console2.log("[Config Check] Skipping oracle feed verification for test environment"); } @@ -1058,7 +1095,8 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { /// @dev Uses AVERAGE_PROVIDER to test the full oracle pipeline /// @param superOracleAddr The SuperOracle address /// @param chainId The chain ID for chain-specific UP token selection - function _verifyOracleFeeds(address superOracleAddr, uint64 chainId) internal view { + /// @param env The environment (0=prod, 2=staging) + function _verifyOracleFeeds(address superOracleAddr, uint64 chainId, uint256 env) internal view { console2.log(""); console2.log("=== Verifying Oracle Feeds via SuperOracle ==="); console2.log("SuperOracle address:", superOracleAddr); @@ -1072,6 +1110,8 @@ contract DeployV2Periphery is DeployV2Base, ConfigPeriphery { upToken = UP_TOKEN; } else if (chainId == BASE_CHAIN_ID) { upToken = UP_TOKEN_BASE; + } else if (chainId == HYPEREVM_CHAIN_ID) { + upToken = env == 2 ? UP_TOKEN_HYPEREVM_STAGING : UP_TOKEN_HYPEREVM; } else { revert("UP token not configured for this chain"); } diff --git a/script/GenerateHyperEVMCalldata.s.sol b/script/GenerateHyperEVMCalldata.s.sol new file mode 100644 index 000000000..3c690035a --- /dev/null +++ b/script/GenerateHyperEVMCalldata.s.sol @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import { Script, console2 } from "forge-std/Script.sol"; +import { OptionsBuilder } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol"; + +interface IOAppCore { + function setPeer(uint32 _eid, bytes32 _peer) external; +} + +interface IOAppOptionsType3 { + struct EnforcedOptionParam { + uint32 eid; + uint16 msgType; + bytes options; + } + + function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external; +} + +interface ILayerZeroEndpointV2 { + struct SetConfigParam { + uint32 eid; + uint32 configType; + bytes config; + } + + function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; + function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; + function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; +} + +/// @title GenerateHyperEVMCalldata +/// @notice Generates calldata for configuring ETH/Base -> HyperEVM OFT pathways +/// @dev Run with: forge script script/GenerateHyperEVMCalldata.s.sol -vvv +contract GenerateHyperEVMCalldata is Script { + using OptionsBuilder for bytes; + + // LayerZero constants + address constant LZ_ENDPOINT = 0x1a44076050125825900e736c501f859c50fE728c; + uint32 constant HYPEREVM_EID = 30367; + + // Gas limits + uint128 constant GAS_LIMIT = 300_000; + uint128 constant COMPOSE_GAS_LIMIT = 1_000_000; + + // Message types + uint16 constant SEND = 1; + uint16 constant SEND_AND_CALL = 2; + + // Config types + uint32 constant EXECUTOR_CONFIG_TYPE = 1; + uint32 constant ULN_CONFIG_TYPE = 2; + + // Ethereum libraries + address constant SEND_LIB_ETH = 0xbB2Ea70C9E858123480642Cf96acbcCE1372dCe1; + address constant RECEIVE_LIB_ETH = 0xc02Ab410f0734EFa3F14628780e6e695156024C2; + address constant DVN1_ETH = 0x589dEDbD617e0CBcB916A9223F4d1300c294236b; + address constant EXECUTOR_ETH = 0x173272739Bd7Aa6e4e214714048a9fE699453059; + + // Base libraries + address constant SEND_LIB_BASE = 0xB5320B0B3a13cC860893E2Bd79FCd7e13484Dda2; + address constant RECEIVE_LIB_BASE = 0xc70AB6f32772f59fBfc23889Caf4Ba3376C84bAf; + address constant DVN1_BASE = 0x9e059a54699a285714207b43B055483E78FAac25; + address constant EXECUTOR_BASE = 0x2CCA08ae69E0C44b18a57Ab2A87644234dAebaE4; + + // Prod OFT addresses + address constant ETH_ADAPTER = 0x722ff7C0665F4b1823c9C4cFcDF73A43de5865BD; + address constant BASE_OFT = 0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B; + address constant HYPEREVM_OFT = 0x642fFC3496AcA19106BAB7A42F1F221a329654fe; + + // ULN Config struct + struct UlnConfig { + uint64 confirmations; + uint8 requiredDVNCount; + uint8 optionalDVNCount; + uint8 optionalDVNThreshold; + address[] requiredDVNs; + address[] optionalDVNs; + } + + // Executor Config struct + struct ExecutorConfig { + uint32 maxMessageSize; + address executor; + } + + function run() public view { + console2.log("================================================================================"); + console2.log("CALLDATA FOR ETH/BASE -> HYPEREVM CONFIGURATION"); + console2.log("================================================================================"); + console2.log(""); + + _generateEthereumCalldata(); + _generateBaseCalldata(); + } + + function _generateEthereumCalldata() internal view { + console2.log("================== ETHEREUM TRANSACTIONS =================="); + console2.log("Target OFT Adapter:", ETH_ADAPTER); + console2.log("LZ Endpoint:", LZ_ENDPOINT); + console2.log(""); + + // 1. setPeer + console2.log("--- TX 1: setPeer on UpOFTAdapter ---"); + console2.log("To:", ETH_ADAPTER); + bytes memory setPeerCalldata = abi.encodeWithSelector( + IOAppCore.setPeer.selector, HYPEREVM_EID, bytes32(uint256(uint160(HYPEREVM_OFT))) + ); + console2.log("Calldata:"); + console2.logBytes(setPeerCalldata); + console2.log(""); + + // 2. setEnforcedOptions + console2.log("--- TX 2: setEnforcedOptions on UpOFTAdapter ---"); + console2.log("To:", ETH_ADAPTER); + bytes memory enforcedOptionsCalldata = _getEnforcedOptionsCalldata(HYPEREVM_EID); + console2.log("Calldata:"); + console2.logBytes(enforcedOptionsCalldata); + console2.log(""); + + // 3. setSendLibrary + console2.log("--- TX 3: setSendLibrary on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setSendLibCalldata = + abi.encodeWithSelector(ILayerZeroEndpointV2.setSendLibrary.selector, ETH_ADAPTER, HYPEREVM_EID, SEND_LIB_ETH); + console2.log("Calldata:"); + console2.logBytes(setSendLibCalldata); + console2.log(""); + + // 4. setReceiveLibrary + console2.log("--- TX 4: setReceiveLibrary on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setReceiveLibCalldata = abi.encodeWithSelector( + ILayerZeroEndpointV2.setReceiveLibrary.selector, + ETH_ADAPTER, + HYPEREVM_EID, + RECEIVE_LIB_ETH, + 0 // gracePeriod + ); + console2.log("Calldata:"); + console2.logBytes(setReceiveLibCalldata); + console2.log(""); + + // 5. setConfig for SendLib (Executor + ULN) + console2.log("--- TX 5: setConfig (SendLib) on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setSendConfigCalldata = _getSendConfigCalldata(ETH_ADAPTER, SEND_LIB_ETH, true); + console2.log("Calldata:"); + console2.logBytes(setSendConfigCalldata); + console2.log(""); + + // 6. setConfig for ReceiveLib (ULN only) + console2.log("--- TX 6: setConfig (ReceiveLib) on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setReceiveConfigCalldata = _getReceiveConfigCalldata(ETH_ADAPTER, RECEIVE_LIB_ETH, true); + console2.log("Calldata:"); + console2.logBytes(setReceiveConfigCalldata); + console2.log(""); + } + + function _generateBaseCalldata() internal view { + console2.log("================== BASE TRANSACTIONS =================="); + console2.log("Target OFT:", BASE_OFT); + console2.log("LZ Endpoint:", LZ_ENDPOINT); + console2.log(""); + + // 1. setPeer + console2.log("--- TX 1: setPeer on UpOFT ---"); + console2.log("To:", BASE_OFT); + bytes memory setPeerCalldata = abi.encodeWithSelector( + IOAppCore.setPeer.selector, HYPEREVM_EID, bytes32(uint256(uint160(HYPEREVM_OFT))) + ); + console2.log("Calldata:"); + console2.logBytes(setPeerCalldata); + console2.log(""); + + // 2. setEnforcedOptions + console2.log("--- TX 2: setEnforcedOptions on UpOFT ---"); + console2.log("To:", BASE_OFT); + bytes memory enforcedOptionsCalldata = _getEnforcedOptionsCalldata(HYPEREVM_EID); + console2.log("Calldata:"); + console2.logBytes(enforcedOptionsCalldata); + console2.log(""); + + // 3. setSendLibrary + console2.log("--- TX 3: setSendLibrary on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setSendLibCalldata = + abi.encodeWithSelector(ILayerZeroEndpointV2.setSendLibrary.selector, BASE_OFT, HYPEREVM_EID, SEND_LIB_BASE); + console2.log("Calldata:"); + console2.logBytes(setSendLibCalldata); + console2.log(""); + + // 4. setReceiveLibrary + console2.log("--- TX 4: setReceiveLibrary on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setReceiveLibCalldata = abi.encodeWithSelector( + ILayerZeroEndpointV2.setReceiveLibrary.selector, + BASE_OFT, + HYPEREVM_EID, + RECEIVE_LIB_BASE, + 0 // gracePeriod + ); + console2.log("Calldata:"); + console2.logBytes(setReceiveLibCalldata); + console2.log(""); + + // 5. setConfig for SendLib (Executor + ULN) + console2.log("--- TX 5: setConfig (SendLib) on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setSendConfigCalldata = _getSendConfigCalldata(BASE_OFT, SEND_LIB_BASE, false); + console2.log("Calldata:"); + console2.logBytes(setSendConfigCalldata); + console2.log(""); + + // 6. setConfig for ReceiveLib (ULN only) + console2.log("--- TX 6: setConfig (ReceiveLib) on LZ Endpoint ---"); + console2.log("To:", LZ_ENDPOINT); + bytes memory setReceiveConfigCalldata = _getReceiveConfigCalldata(BASE_OFT, RECEIVE_LIB_BASE, false); + console2.log("Calldata:"); + console2.logBytes(setReceiveConfigCalldata); + console2.log(""); + } + + function _getEnforcedOptionsCalldata(uint32 dstEid) internal view returns (bytes memory) { + bytes memory sendOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(GAS_LIMIT, 0); + + bytes memory sendAndCallOptions = + OptionsBuilder.newOptions().addExecutorLzReceiveOption(GAS_LIMIT, 0).addExecutorLzComposeOption( + 0, COMPOSE_GAS_LIMIT, 0 + ); + + IOAppOptionsType3.EnforcedOptionParam[] memory enforcedOptions = + new IOAppOptionsType3.EnforcedOptionParam[](2); + enforcedOptions[0] = + IOAppOptionsType3.EnforcedOptionParam({ eid: dstEid, msgType: SEND, options: sendOptions }); + enforcedOptions[1] = + IOAppOptionsType3.EnforcedOptionParam({ eid: dstEid, msgType: SEND_AND_CALL, options: sendAndCallOptions }); + + return abi.encodeWithSelector(IOAppOptionsType3.setEnforcedOptions.selector, enforcedOptions); + } + + function _getSendConfigCalldata( + address oapp, + address sendLib, + bool isEthereum + ) + internal + pure + returns (bytes memory) + { + address[] memory requiredDVNs = new address[](1); + requiredDVNs[0] = isEthereum ? DVN1_ETH : DVN1_BASE; + + address[] memory optionalDVNs = new address[](0); + + UlnConfig memory ulnConfig = UlnConfig({ + confirmations: isEthereum ? 15 : 10, + requiredDVNCount: 1, + optionalDVNCount: 0, + optionalDVNThreshold: 0, + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs + }); + + ExecutorConfig memory execConfig = + ExecutorConfig({ maxMessageSize: 10_000, executor: isEthereum ? EXECUTOR_ETH : EXECUTOR_BASE }); + + ILayerZeroEndpointV2.SetConfigParam[] memory params = new ILayerZeroEndpointV2.SetConfigParam[](2); + params[0] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: EXECUTOR_CONFIG_TYPE, + config: abi.encode(execConfig) + }); + params[1] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: ULN_CONFIG_TYPE, + config: abi.encode(ulnConfig) + }); + + return abi.encodeWithSelector(ILayerZeroEndpointV2.setConfig.selector, oapp, sendLib, params); + } + + function _getReceiveConfigCalldata( + address oapp, + address receiveLib, + bool isEthereum + ) + internal + pure + returns (bytes memory) + { + address[] memory requiredDVNs = new address[](1); + requiredDVNs[0] = isEthereum ? DVN1_ETH : DVN1_BASE; + + address[] memory optionalDVNs = new address[](0); + + UlnConfig memory ulnConfig = UlnConfig({ + confirmations: 1, // HyperEVM confirmations + requiredDVNCount: 1, + optionalDVNCount: 0, + optionalDVNThreshold: 0, + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs + }); + + ILayerZeroEndpointV2.SetConfigParam[] memory params = new ILayerZeroEndpointV2.SetConfigParam[](1); + params[0] = ILayerZeroEndpointV2.SetConfigParam({ + eid: HYPEREVM_EID, + configType: ULN_CONFIG_TYPE, + config: abi.encode(ulnConfig) + }); + + return abi.encodeWithSelector(ILayerZeroEndpointV2.setConfig.selector, oapp, receiveLib, params); + } +} diff --git a/script/SmokeTestV2Periphery.s.sol b/script/SmokeTestV2Periphery.s.sol index e36373487..61b252f54 100644 --- a/script/SmokeTestV2Periphery.s.sol +++ b/script/SmokeTestV2Periphery.s.sol @@ -186,18 +186,75 @@ contract SmokeTestV2Periphery is DeployV2Base, ConfigPeriphery { // Validate SuperGovernor is deployed require(peripheryContracts.superGovernor.code.length > 0, "SuperGovernor not deployed"); + console2.log("SuperGovernor address:", peripheryContracts.superGovernor); - // Get addresses from SuperGovernor + // Get addresses from SuperGovernor with detailed error handling SuperGovernor governor = SuperGovernor(peripheryContracts.superGovernor); - peripheryContracts.superVaultAggregator = governor.getAddress(governor.SUPER_VAULT_AGGREGATOR()); - peripheryContracts.superOracle = governor.getAddress(governor.SUPER_ORACLE()); - peripheryContracts.superBank = governor.getAddress(governor.SUPER_BANK()); + // Get role keys for logging + bytes32 aggregatorKey = governor.SUPER_VAULT_AGGREGATOR(); + bytes32 oracleKey = governor.SUPER_ORACLE(); + bytes32 bankKey = governor.SUPER_BANK(); + + console2.log("Looking up registered addresses in SuperGovernor..."); + console2.log(" SUPER_VAULT_AGGREGATOR key:", vm.toString(aggregatorKey)); + console2.log(" SUPER_ORACLE key:", vm.toString(oracleKey)); + console2.log(" SUPER_BANK key:", vm.toString(bankKey)); + + // Try to get each address with detailed error messages + peripheryContracts.superVaultAggregator = _safeGetAddress(governor, aggregatorKey, "SUPER_VAULT_AGGREGATOR"); + peripheryContracts.superOracle = _safeGetAddress(governor, oracleKey, "SUPER_ORACLE"); + peripheryContracts.superBank = _safeGetAddress(governor, bankKey, "SUPER_BANK"); peripheryContracts.ecdsappsOracle = governor.getActivePPSOracle(); + console2.log(" Active PPS Oracle:", peripheryContracts.ecdsappsOracle); + return peripheryContracts; } + /// @notice Safely get an address from SuperGovernor with detailed error logging + /// @param governor The SuperGovernor contract + /// @param key The address key to lookup + /// @param keyName Human-readable name of the key for logging + /// @return The address if found + function _safeGetAddress( + SuperGovernor governor, + bytes32 key, + string memory keyName + ) + internal + view + returns (address) + { + // Use low-level call to check if address exists without reverting + (bool success, bytes memory data) = address(governor).staticcall( + abi.encodeWithSelector(governor.getAddress.selector, key) + ); + + if (!success) { + console2.log(""); + console2.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + console2.log("ERROR: Failed to get address from SuperGovernor"); + console2.log(" Key name:", keyName); + console2.log(" Key hash:", vm.toString(key)); + console2.log(" SuperGovernor:", address(governor)); + console2.log(""); + console2.log("This usually means the address has NOT been registered"); + console2.log("in SuperGovernor after deployment."); + console2.log(""); + console2.log("To fix this, run the configuration script to register"); + console2.log("the contract address in SuperGovernor using setAddress()"); + console2.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + console2.log(""); + + revert(string.concat("CONTRACT_NOT_FOUND: ", keyName, " not registered in SuperGovernor")); + } + + address result = abi.decode(data, (address)); + console2.log(string.concat(" ", keyName, ":"), result); + return result; + } + /// @notice Smoke test to verify roles and configuration are set correctly post-deployment /// @param peripheryContracts The deployed periphery contract addresses /// @param chainId The chain ID for chain-specific oracle selection @@ -209,11 +266,11 @@ contract SmokeTestV2Periphery is DeployV2Base, ConfigPeriphery { SuperGovernor governor = SuperGovernor(peripheryContracts.superGovernor); // Verify all roles are configured correctly - // Skip for Base (8453) since roles haven't been transferred yet - if (chainId == BASE_CHAIN_ID) { - console2.log("[Role Check] SKIPPED - Roles not yet transferred on Base"); + // Skip for HyperEVM (999) since roles haven't been transferred yet + if (chainId == HYPEREVM_CHAIN_ID) { + console2.log("[Role Check] SKIPPED - Roles not yet transferred on HyperEVM"); } else { - _verifyRoles(governor); + _verifyRoles(governor, env); } // Verify active PPS oracle is set @@ -250,8 +307,8 @@ contract SmokeTestV2Periphery is DeployV2Base, ConfigPeriphery { require(validatorAddrs.length > 0, "SMOKE_TEST_FAILED: No validators configured"); require(quorum == INITIAL_VALIDATOR_QUORUM, "SMOKE_TEST_FAILED: Quorum mismatch"); - // Verify gas info is set for ECDSAPPSOracle (mainnet only) - _verifyGasInfo(governor, peripheryContracts.ecdsappsOracle, chainId); + // Verify gas info is set for ECDSAPPSOracle (mainnet only, skip for staging) + _verifyGasInfo(governor, peripheryContracts.ecdsappsOracle, chainId, env); // Verify oracle feeds return valid prices via SuperOracle integration // Skip for test environment (env == 1) since oracles may not be available on vnet @@ -285,65 +342,83 @@ contract SmokeTestV2Periphery is DeployV2Base, ConfigPeriphery { /// @notice Verify all roles are configured correctly on SuperGovernor /// @param governor The SuperGovernor contract - function _verifyRoles(SuperGovernor governor) internal view { + /// @param env Environment (0 = prod, 1 = test, 2 = staging) + function _verifyRoles(SuperGovernor governor, uint256 env) internal view { console2.log(""); console2.log("=== Verifying Role Configuration ==="); // Check admin roles are assigned to correct addresses (not deployer) console2.log("[Role Check] Deployer address:", configuration.deployer); - _verifyAdminRoles(governor); + _verifyAdminRoles(governor, env); - // Check configured role holders from configuration - console2.log(""); - console2.log("[Role Check] Configured role holders:"); - _verifyOperationalRoleHolders(governor); + // Skip operational role checks for staging (env == 2) since roles may not have been assigned + if (env == 2) { + console2.log(""); + console2.log("[Role Check] SKIPPED - Operational role checks skipped for staging"); + } else { + // Check configured role holders from configuration + console2.log(""); + console2.log("[Role Check] Configured role holders:"); + _verifyOperationalRoleHolders(governor); - // Verify deployer does NOT have operational roles - console2.log(""); - console2.log("[Role Check] Verifying deployer does NOT have operational roles:"); - _verifyDeployerNoOperationalRoles(governor); + // Verify deployer does NOT have operational roles + console2.log(""); + console2.log("[Role Check] Verifying deployer does NOT have operational roles:"); + _verifyDeployerNoOperationalRoles(governor); + } console2.log("=== Role Verification Complete ==="); } /// @notice Verify admin roles are assigned to correct addresses - function _verifyAdminRoles(SuperGovernor governor) internal view { + /// @param env Environment (0 = prod, 1 = test, 2 = staging) + function _verifyAdminRoles(SuperGovernor governor, uint256 env) internal view { // SUPER_GOVERNOR_ADDRESS should have DEFAULT_ADMIN_ROLE and SUPER_GOVERNOR_ROLE - bool superGovernorHasDefaultAdmin = - governor.hasRole(governor.DEFAULT_ADMIN_ROLE(), SUPER_GOVERNOR_ADDRESS); - bool superGovernorHasSuperGovernorRole = - governor.hasRole(governor.SUPER_GOVERNOR_ROLE(), SUPER_GOVERNOR_ADDRESS); - - console2.log("[Role Check] SUPER_GOVERNOR_ADDRESS:", SUPER_GOVERNOR_ADDRESS); - console2.log(" DEFAULT_ADMIN_ROLE:", superGovernorHasDefaultAdmin); - console2.log(" SUPER_GOVERNOR_ROLE:", superGovernorHasSuperGovernorRole); - - require( - superGovernorHasDefaultAdmin, "SMOKE_TEST_FAILED: SUPER_GOVERNOR_ADDRESS missing DEFAULT_ADMIN_ROLE" - ); - require( - superGovernorHasSuperGovernorRole, "SMOKE_TEST_FAILED: SUPER_GOVERNOR_ADDRESS missing SUPER_GOVERNOR_ROLE" - ); + // Skip for staging (env == 2) since roles may not have been transferred yet + if (env == 2) { + console2.log("[Role Check] SKIPPED - SUPER_GOVERNOR_ADDRESS role check skipped for staging"); + } else { + bool superGovernorHasDefaultAdmin = + governor.hasRole(governor.DEFAULT_ADMIN_ROLE(), SUPER_GOVERNOR_ADDRESS); + bool superGovernorHasSuperGovernorRole = + governor.hasRole(governor.SUPER_GOVERNOR_ROLE(), SUPER_GOVERNOR_ADDRESS); + + console2.log("[Role Check] SUPER_GOVERNOR_ADDRESS:", SUPER_GOVERNOR_ADDRESS); + console2.log(" DEFAULT_ADMIN_ROLE:", superGovernorHasDefaultAdmin); + console2.log(" SUPER_GOVERNOR_ROLE:", superGovernorHasSuperGovernorRole); + + require( + superGovernorHasDefaultAdmin, "SMOKE_TEST_FAILED: SUPER_GOVERNOR_ADDRESS missing DEFAULT_ADMIN_ROLE" + ); + require( + superGovernorHasSuperGovernorRole, "SMOKE_TEST_FAILED: SUPER_GOVERNOR_ADDRESS missing SUPER_GOVERNOR_ROLE" + ); + } // GOVERNOR address should have GOVERNOR_ROLE - bool governorHasGovernorRole = governor.hasRole(governor.GOVERNOR_ROLE(), GOVERNOR); - console2.log("[Role Check] GOVERNOR address:", GOVERNOR); - console2.log(" GOVERNOR_ROLE:", governorHasGovernorRole); - require(governorHasGovernorRole, "SMOKE_TEST_FAILED: GOVERNOR missing GOVERNOR_ROLE"); - - // Verify deployer does NOT have any admin roles anymore - bool deployerHasDefaultAdmin = governor.hasRole(governor.DEFAULT_ADMIN_ROLE(), configuration.deployer); - bool deployerHasSuperGovernor = governor.hasRole(governor.SUPER_GOVERNOR_ROLE(), configuration.deployer); - bool deployerHasGovernor = governor.hasRole(governor.GOVERNOR_ROLE(), configuration.deployer); - - console2.log("[Role Check] Verifying deployer does NOT have admin roles:"); - console2.log(" Deployer has DEFAULT_ADMIN_ROLE:", deployerHasDefaultAdmin); - console2.log(" Deployer has SUPER_GOVERNOR_ROLE:", deployerHasSuperGovernor); - console2.log(" Deployer has GOVERNOR_ROLE:", deployerHasGovernor); - - require(!deployerHasDefaultAdmin, "SMOKE_TEST_FAILED: Deployer should NOT have DEFAULT_ADMIN_ROLE"); - require(!deployerHasSuperGovernor, "SMOKE_TEST_FAILED: Deployer should NOT have SUPER_GOVERNOR_ROLE"); - require(!deployerHasGovernor, "SMOKE_TEST_FAILED: Deployer should NOT have GOVERNOR_ROLE"); + // Skip for staging (env == 2) since roles may not have been transferred yet + if (env == 2) { + console2.log("[Role Check] SKIPPED - GOVERNOR role check skipped for staging"); + } else { + bool governorHasGovernorRole = governor.hasRole(governor.GOVERNOR_ROLE(), GOVERNOR); + console2.log("[Role Check] GOVERNOR address:", GOVERNOR); + console2.log(" GOVERNOR_ROLE:", governorHasGovernorRole); + require(governorHasGovernorRole, "SMOKE_TEST_FAILED: GOVERNOR missing GOVERNOR_ROLE"); + + // Verify deployer does NOT have any admin roles anymore (only in prod) + bool deployerHasDefaultAdmin = governor.hasRole(governor.DEFAULT_ADMIN_ROLE(), configuration.deployer); + bool deployerHasSuperGovernor = governor.hasRole(governor.SUPER_GOVERNOR_ROLE(), configuration.deployer); + bool deployerHasGovernor = governor.hasRole(governor.GOVERNOR_ROLE(), configuration.deployer); + + console2.log("[Role Check] Verifying deployer does NOT have admin roles:"); + console2.log(" Deployer has DEFAULT_ADMIN_ROLE:", deployerHasDefaultAdmin); + console2.log(" Deployer has SUPER_GOVERNOR_ROLE:", deployerHasSuperGovernor); + console2.log(" Deployer has GOVERNOR_ROLE:", deployerHasGovernor); + + require(!deployerHasDefaultAdmin, "SMOKE_TEST_FAILED: Deployer should NOT have DEFAULT_ADMIN_ROLE"); + require(!deployerHasSuperGovernor, "SMOKE_TEST_FAILED: Deployer should NOT have SUPER_GOVERNOR_ROLE"); + require(!deployerHasGovernor, "SMOKE_TEST_FAILED: Deployer should NOT have GOVERNOR_ROLE"); + } } /// @notice Verify operational role holders have their roles @@ -414,9 +489,18 @@ contract SmokeTestV2Periphery is DeployV2Base, ConfigPeriphery { /// @param governor The SuperGovernor contract /// @param ecdsappsOracle The ECDSAPPSOracle address /// @param chainId The chain ID - function _verifyGasInfo(SuperGovernor governor, address ecdsappsOracle, uint64 chainId) internal view { + /// @param env Environment (0 = prod, 1 = test, 2 = staging) + function _verifyGasInfo(SuperGovernor governor, address ecdsappsOracle, uint64 chainId, uint256 env) internal view { console2.log(""); console2.log("=== Verifying Gas Info Configuration ==="); + + // Skip gas info verification for staging (env == 2) since it may not be configured + if (env == 2) { + console2.log("[Gas Check] SKIPPED - Gas info verification skipped for staging"); + console2.log("=== Gas Info Verification Complete ==="); + return; + } + console2.log("ECDSAPPSOracle address:", ecdsappsOracle); uint256 gasInfo = governor.getGasInfo(ecdsappsOracle); diff --git a/script/TransferSuperGovernorRole.s.sol b/script/TransferSuperGovernorRole.s.sol index b14b71c82..a6134bfbc 100644 --- a/script/TransferSuperGovernorRole.s.sol +++ b/script/TransferSuperGovernorRole.s.sol @@ -286,34 +286,34 @@ contract TransferSuperGovernorRole is DeployV2Base { } } - /// @notice Transfer FixedPriceOracle ownership to SuperGovernor + /// @notice Transfer FixedPriceOracle ownership to SUPER_GOVERNOR_ADDRESS function _transferFixedPriceOracleOwnership( uint64 chainId, uint256 env, string memory saltNamespace, - address superGovernorAddr + address /* superGovernorAddr */ ) internal { - console2.log("[Step 7] Transferring FixedPriceOracle ownership to SuperGovernor..."); + console2.log("[Step 7] Transferring FixedPriceOracle ownership to SUPER_GOVERNOR_ADDRESS..."); address fixedPriceOracleAddr = _getFixedPriceOracleAddress(chainId, env, saltNamespace); if (fixedPriceOracleAddr != address(0)) { FixedPriceOracle oracle = FixedPriceOracle(fixedPriceOracleAddr); address currentOwner = oracle.owner(); console2.log(" FixedPriceOracle address:", fixedPriceOracleAddr); console2.log(" Current owner:", currentOwner); - console2.log(" New owner (SuperGovernor):", superGovernorAddr); + console2.log(" New owner (SUPER_GOVERNOR_ADDRESS):", SUPER_GOVERNOR_ADDRESS); if (currentOwner == DEPLOYER) { - oracle.transferOwnership(superGovernorAddr); - console2.log("[Step 7] DONE - Transferred FixedPriceOracle ownership to SuperGovernor"); + oracle.transferOwnership(SUPER_GOVERNOR_ADDRESS); + console2.log("[Step 7] DONE - Transferred FixedPriceOracle ownership to SUPER_GOVERNOR_ADDRESS"); // Verify ownership transfer address newOwner = oracle.owner(); - require(newOwner == superGovernorAddr, "FixedPriceOracle ownership transfer failed"); + require(newOwner == SUPER_GOVERNOR_ADDRESS, "FixedPriceOracle ownership transfer failed"); console2.log("[Verify] FixedPriceOracle new owner:", newOwner); - } else if (currentOwner == superGovernorAddr) { - console2.log("[Step 7] SKIPPED - FixedPriceOracle already owned by SuperGovernor"); + } else if (currentOwner == SUPER_GOVERNOR_ADDRESS) { + console2.log("[Step 7] SKIPPED - FixedPriceOracle already owned by SUPER_GOVERNOR_ADDRESS"); } else { console2.log("[Step 7] WARNING - FixedPriceOracle owned by unexpected address:", currentOwner); } diff --git a/script/TransferSuperVaultBatchOperatorOwnership.s.sol b/script/TransferSuperVaultBatchOperatorOwnership.s.sol new file mode 100644 index 000000000..42fed4cce --- /dev/null +++ b/script/TransferSuperVaultBatchOperatorOwnership.s.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.30; + +import { DeployV2Base } from "./DeployV2Base.s.sol"; +import { SuperVaultBatchOperator } from "../src/SuperVault/SuperVaultBatchOperator.sol"; +import { DeterministicDeployerLib } from "lib/v2-core/src/vendor/nexus/DeterministicDeployerLib.sol"; +import { console2 } from "forge-std/console2.sol"; + +/// @title TransferSuperVaultBatchOperatorOwnership +/// @notice Script to transfer SuperVaultBatchOperator admin role to SUPER_GOVERNOR_ADDRESS +contract TransferSuperVaultBatchOperatorOwnership is DeployV2Base { + /*////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////*/ + + /// @notice Contract key for SuperVaultBatchOperator + string internal constant BATCH_OPERATOR_KEY = "SuperVaultBatchOperator"; + + /*////////////////////////////////////////////////////////////// + MAIN FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @notice Transfer admin role to SUPER_GOVERNOR_ADDRESS + /// @param env Environment (0 = prod, 2 = staging) + /// @param chainId Chain ID + /// @param batchOperatorAddr The deployed SuperVaultBatchOperator address + /// @param currentAdmin Current admin address (must match deployed operator's admin) + function run(uint256 env, uint64 chainId, address batchOperatorAddr, address currentAdmin) external broadcast(env) { + _setBaseConfiguration(env, ""); + + console2.log("====== Transfer SuperVaultBatchOperator Admin Role ======"); + console2.log("Chain ID:", chainId); + console2.log("Environment:", env); + console2.log("Batch Operator Address:", batchOperatorAddr); + console2.log("Current Admin:", currentAdmin); + console2.log("New Admin (SUPER_GOVERNOR_ADDRESS):", SUPER_GOVERNOR_ADDRESS); + console2.log(""); + + require(batchOperatorAddr.code.length > 0, "SuperVaultBatchOperator not deployed at given address"); + + SuperVaultBatchOperator batchOperator = SuperVaultBatchOperator(batchOperatorAddr); + bytes32 DEFAULT_ADMIN_ROLE = batchOperator.DEFAULT_ADMIN_ROLE(); + bytes32 OPERATOR_ROLE = batchOperator.OPERATOR_ROLE(); + + // Check current role state + console2.log("Batch Operator Address:", batchOperatorAddr); + + bool currentAdminHasAdmin = batchOperator.hasRole(DEFAULT_ADMIN_ROLE, currentAdmin); + bool newAdminHasAdmin = batchOperator.hasRole(DEFAULT_ADMIN_ROLE, SUPER_GOVERNOR_ADDRESS); + + console2.log("Current admin has DEFAULT_ADMIN_ROLE:", currentAdminHasAdmin); + console2.log("SUPER_GOVERNOR has DEFAULT_ADMIN_ROLE:", newAdminHasAdmin); + + // Check if transfer is complete (skip if so) + bool fullyTransferred = newAdminHasAdmin && !currentAdminHasAdmin; + + if (fullyTransferred) { + console2.log(""); + console2.log("=== SKIPPED: Admin Role Already Transferred ==="); + console2.log("SUPER_GOVERNOR_ADDRESS already has admin role and current admin has none."); + return; + } + + // Verify we can proceed (current admin must have admin role to grant/revoke) + require(currentAdminHasAdmin, "ADMIN_MISMATCH: Current admin does not have DEFAULT_ADMIN_ROLE"); + + // Transfer admin role to SUPER_GOVERNOR_ADDRESS + console2.log(""); + console2.log("Granting DEFAULT_ADMIN_ROLE to SUPER_GOVERNOR_ADDRESS..."); + + if (!newAdminHasAdmin) { + batchOperator.grantRole(DEFAULT_ADMIN_ROLE, SUPER_GOVERNOR_ADDRESS); + console2.log(" [+] Granted DEFAULT_ADMIN_ROLE"); + } else { + console2.log(" [=] DEFAULT_ADMIN_ROLE already granted"); + } + + // Revoke admin role from current admin + console2.log(""); + console2.log("Revoking DEFAULT_ADMIN_ROLE from current admin..."); + + if (currentAdminHasAdmin) { + batchOperator.revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); + console2.log(" [-] Revoked DEFAULT_ADMIN_ROLE"); + } else { + console2.log(" [=] DEFAULT_ADMIN_ROLE already revoked"); + } + + // Verify transfer + require( + batchOperator.hasRole(DEFAULT_ADMIN_ROLE, SUPER_GOVERNOR_ADDRESS), "TRANSFER_FAILED: New admin role mismatch" + ); + require(!batchOperator.hasRole(DEFAULT_ADMIN_ROLE, currentAdmin), "TRANSFER_FAILED: Old admin still has role"); + + console2.log(""); + console2.log("=== Transfer Complete ==="); + console2.log("New Admin:", SUPER_GOVERNOR_ADDRESS); + console2.log("Has DEFAULT_ADMIN_ROLE:", batchOperator.hasRole(DEFAULT_ADMIN_ROLE, SUPER_GOVERNOR_ADDRESS)); + console2.log("====== Admin Role Transfer Complete ======"); + } + + /// @notice Check current role status + /// @param env Environment (0 = prod, 2 = staging) + /// @param chainId Chain ID + /// @param batchOperatorAddr The deployed SuperVaultBatchOperator address + /// @param deployedAdmin Admin address used during deployment + function runCheck(uint256 env, uint64 chainId, address batchOperatorAddr, address deployedAdmin) external broadcast(env) { + _setBaseConfiguration(env, ""); + + console2.log("====== SuperVaultBatchOperator Role Check ======"); + console2.log("Chain ID:", chainId); + console2.log("Environment:", env); + console2.log("Batch Operator Address:", batchOperatorAddr); + console2.log("SUPER_GOVERNOR_ADDRESS:", SUPER_GOVERNOR_ADDRESS); + console2.log(""); + + if (batchOperatorAddr.code.length == 0) { + console2.log("Status: NOT DEPLOYED at given address"); + return; + } + + SuperVaultBatchOperator batchOperator = SuperVaultBatchOperator(batchOperatorAddr); + bytes32 DEFAULT_ADMIN_ROLE = batchOperator.DEFAULT_ADMIN_ROLE(); + bytes32 OPERATOR_ROLE = batchOperator.OPERATOR_ROLE(); + + // Get operator address for this environment + address operator = _getOperatorForEnv(env); + + console2.log("=== Role Status ==="); + console2.log("Deployer has DEFAULT_ADMIN_ROLE:", batchOperator.hasRole(DEFAULT_ADMIN_ROLE, deployedAdmin)); + console2.log("SUPER_GOVERNOR has DEFAULT_ADMIN_ROLE:", batchOperator.hasRole(DEFAULT_ADMIN_ROLE, SUPER_GOVERNOR_ADDRESS)); + console2.log("Operator has OPERATOR_ROLE:", batchOperator.hasRole(OPERATOR_ROLE, operator)); + console2.log(""); + + if (batchOperator.hasRole(DEFAULT_ADMIN_ROLE, SUPER_GOVERNOR_ADDRESS)) { + console2.log("Status: ADMIN ROLE ALREADY TRANSFERRED"); + } else if (batchOperator.hasRole(DEFAULT_ADMIN_ROLE, deployedAdmin)) { + console2.log("Status: ADMIN ROLE NEEDS TRANSFER"); + console2.log(" From:", deployedAdmin); + console2.log(" To:", SUPER_GOVERNOR_ADDRESS); + } else { + console2.log("Status: UNEXPECTED - Neither deployer nor SUPER_GOVERNOR has admin role"); + } + + console2.log(""); + console2.log("====== Check Complete ======"); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @notice Get operator address based on environment + /// @param env Environment (0 = prod, 2 = staging) + function _getOperatorForEnv(uint256 env) internal pure returns (address) { + if (env == 0) { + return BATCH_OPERATOR_PROD; + } else { + return BATCH_OPERATOR_STAGING; + } + } + + /// @notice Compute the deterministic address for SuperVaultBatchOperator + /// @param env Environment (0 = prod, 2 = staging) + /// @param admin Admin address + /// @param operator Operator address + function _computeAddress(uint256 env, address admin, address operator) internal view returns (address) { + bytes memory bytecode = __getBytecode(BATCH_OPERATOR_KEY, env); + require(bytecode.length > 0, "BYTECODE_NOT_FOUND"); + return DeterministicDeployerLib.computeAddress( + abi.encodePacked(bytecode, abi.encode(admin, operator)), __getSalt(BATCH_OPERATOR_KEY) + ); + } +} diff --git a/script/locked-bytecode-dev/ECDSAPPSOracle.standard-json-input.json b/script/locked-bytecode-dev/ECDSAPPSOracle.standard-json-input.json new file mode 100644 index 000000000..224c0ad4c --- /dev/null +++ b/script/locked-bytecode-dev/ECDSAPPSOracle.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/oracles/ECDSAPPSOracle.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { ECDSA } from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport { EIP712 } from \"@openzeppelin/contracts/utils/cryptography/EIP712.sol\";\n\n// Superform\nimport { ISuperGovernor } from \"../interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"../interfaces/SuperVault/ISuperVaultAggregator.sol\";\nimport { IECDSAPPSOracle } from \"../interfaces/oracles/IECDSAPPSOracle.sol\";\n\n/// @title ECDSAPPSOracle\n/// @author Superform Labs\n/// @notice PPS Oracle that validates price updates using ECDSA signatures\n/// @dev Implements the IECDSAPPSOracle interface for validating and forwarding PPS updates\ncontract ECDSAPPSOracle is IECDSAPPSOracle, EIP712 {\n using ECDSA for bytes32;\n\n /*//////////////////////////////////////////////////////////////\n STORAGE\n //////////////////////////////////////////////////////////////*/\n mapping(address _strategy => uint256 _nonce) public noncePerStrategy;\n\n // Maximum number of strategies to process in `batchForwardPPS`\n /// @notice Maximum number of strategies that can be processed in a single batch\n /// @dev Set to 300 to stay well below gas limits while allowing efficient batch updates.\n uint256 public constant MAX_STRATEGIES = 300;\n\n /// @notice The SuperGovernor contract for validator verification\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n /// @notice EIP-712 typehash for PPS update signatures\n /// @dev Defines the structure: UpdatePPS(address strategy, uint256 pps, uint256 timestamp, uint256 strategyNonce)\n /// - strategy: The strategy contract address\n /// - pps: The price-per-share value being signed\n /// - timestamp: The blockchain state timestamp this PPS represents\n /// - strategyNonce: Current nonce for this strategy (prevents replay attacks)\n /// This typehash MUST match the off-chain signing format exactly. Changing this typehash would\n /// invalidate all existing signatures. See Property 1 in security_properties.md for nonce details.\n bytes32 public constant UPDATE_PPS_TYPEHASH =\n keccak256(\"UpdatePPS(address strategy,uint256 pps,uint256 timestamp,uint256 strategyNonce)\");\n\n bytes32 private constant SUPER_VAULT_AGGREGATOR = keccak256(\"SUPER_VAULT_AGGREGATOR\");\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n /// @notice Initializes the ECDSAPPSOracle contract\n /// @param superGovernor_ Address of the SuperGovernor contract\n /// @param name_ EIP-712 domain name (e.g., \"SuperformOraclePPS\"). Used for domain separation.\n /// @param version_ EIP-712 domain version (e.g., \"1\"). Must match off-chain signing version.\n /// @dev The name_ and version_ parameters define the EIP-712 domain separator and cannot be changed\n /// after deployment. All validator signatures must be signed with matching domain parameters.\n constructor(address superGovernor_, string memory name_, string memory version_) EIP712(name_, version_) {\n if (superGovernor_ == address(0)) revert INVALID_VALIDATOR();\n\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc IECDSAPPSOracle\n function domainSeparator() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc IECDSAPPSOracle\n function updatePPS(UpdatePPSArgs calldata args) external {\n uint256 strategiesLength = args.strategies.length;\n\n if (strategiesLength == 0) revert ZERO_LENGTH_ARRAY();\n // Validate input array lengths\n if (\n strategiesLength != args.proofsArray.length || strategiesLength != args.ppss.length\n || strategiesLength != args.timestamps.length\n ) revert ARRAY_LENGTH_MISMATCH();\n\n if (strategiesLength > MAX_STRATEGIES) revert MAX_STRATEGIES_EXCEEDED();\n\n // Validate strategies are sorted and unique to prevent nonce burning\n // This prevents attackers from submitting duplicate strategies to skip nonces\n // Strategies must be in ascending order: strategies[i] < strategies[i+1]\n for (uint256 i = 1; i < strategiesLength; i++) {\n if (args.strategies[i] <= args.strategies[i - 1]) {\n revert STRATEGIES_NOT_SORTED_UNIQUE();\n }\n }\n\n uint256 cachedTotalValidators = SUPER_GOVERNOR.getValidatorsCount();\n\n // Early validation checks\n if (cachedTotalValidators == 0) revert INVALID_TOTAL_VALIDATORS();\n\n // Process strategies and collect valid entries\n ValidatedBatchData memory validatedData = _processBatchStrategies(args, strategiesLength);\n\n // Forward valid entries if any exist\n _forwardValidEntries(validatedData);\n }\n\n /// @inheritdoc IECDSAPPSOracle\n /// @dev Reverts immediately if duplicate signers are found or quorum is not met\n function validateProofs(IECDSAPPSOracle.ValidationParams memory params) external view {\n // derive transient values\n uint256 requiredQuorum = SUPER_GOVERNOR.getPPSOracleQuorum();\n\n _validateProofs(params, requiredQuorum);\n }\n\n /// @inheritdoc IECDSAPPSOracle\n /// @dev Reverts immediately if duplicate signers are found or quorum is not met\n function validateProofs(IECDSAPPSOracle.ValidationParams memory params, uint256 requiredQuorum) public view {\n _validateProofs(params, requiredQuorum);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Validates an array of proofs for a strategy's PPS update\n /// @dev Implements Property 1: Signature Validation & Nonce in Digest (security_properties.md)\n ///\n /// SECURITY GUARANTEES:\n /// 1. All signatures are EIP-712 typed structured data\n /// 2. Each signature includes the current nonce for the strategy (replay protection)\n /// 3. All signers must be registered validators (checked via SUPER_GOVERNOR)\n /// 4. All signers must be unique (enforced via ascending order check)\n /// 5. Quorum requirement must be met (M validators out of N total)\n ///\n /// SIGNATURE STRUCTURE:\n /// digest = EIP-712(strategy, pps, timestamp, noncePerStrategy[strategy])\n ///\n /// FAILURE MODES:\n /// - Reverts if quorum not met (QUORUM_NOT_MET)\n /// - Reverts if any signer is not a registered validator (INVALID_VALIDATOR)\n /// - Reverts if duplicate signers detected (INVALID_PROOF)\n /// - Reverts if signatures in wrong order (INVALID_PROOF)\n ///\n /// @param params Validation parameters containing strategy, proofs, pps, timestamp\n /// @param requiredQuorum Required number of validator signatures (M out of N)\n /// @dev Check for this being the active PPS Oracle already done by SuperVaultAggregator\n /// @dev Reverts immediately if duplicate signers are found or quorum is not met\n function _validateProofs(IECDSAPPSOracle.ValidationParams memory params, uint256 requiredQuorum) internal view {\n uint256 proofsLength = params.proofs.length;\n if (proofsLength == 0) revert ZERO_LENGTH_ARRAY();\n\n // Quorum from batch-snapshot\n if (proofsLength < requiredQuorum) revert QUORUM_NOT_MET();\n\n // [Property 1: Signature Validation & Nonce in Digest]\n // Build EIP-712 typed data digest that includes the current nonce for this strategy.\n // This binds the signature to a specific nonce value, preventing replay attacks.\n // Once a signature is used and the nonce increments, the same signature becomes invalid.\n bytes32 digest = _hashTypedDataV4(\n keccak256(\n abi.encodePacked(\n UPDATE_PPS_TYPEHASH,\n params.strategy,\n params.pps,\n params.timestamp,\n noncePerStrategy[params.strategy]\n )\n )\n );\n\n address lastSigner;\n // Process each proof\n for (uint256 i; i < proofsLength; i++) {\n // Recover the signer from the proof\n address signer = ECDSA.recover(digest, params.proofs[i]);\n\n // Verify the signer is a registered validator\n if (!SUPER_GOVERNOR.isValidator(signer)) revert INVALID_VALIDATOR();\n\n // Check for duplicates or improper ordering - signers must be in ascending order\n if (signer <= lastSigner) revert INVALID_PROOF();\n lastSigner = signer;\n }\n }\n\n /// @notice Processes batch strategies and returns valid entries\n /// @param args Batch update arguments\n /// @param strategiesLength Length of strategies array\n /// @return validatedData Struct containing all validated batch data\n function _processBatchStrategies(\n UpdatePPSArgs calldata args,\n uint256 strategiesLength\n )\n internal\n returns (ValidatedBatchData memory validatedData)\n {\n uint256 requiredQuorum = SUPER_GOVERNOR.getPPSOracleQuorum();\n uint256 validCount; // Plain local, starts at 0\n\n // -------- existing collection logic --------\n validatedData.strategies = new address[](strategiesLength);\n validatedData.ppss = new uint256[](strategiesLength);\n validatedData.timestamps = new uint256[](strategiesLength);\n validatedData.validatorSets = new uint256[](strategiesLength);\n\n for (uint256 i; i < strategiesLength; ++i) {\n bool isValid = _processIndividualStrategy(args, i, requiredQuorum);\n if (isValid) {\n validatedData.strategies[validCount] = args.strategies[i];\n validatedData.ppss[validCount] = args.ppss[i];\n validatedData.timestamps[validCount] = args.timestamps[i];\n validatedData.validatorSets[validCount] = args.proofsArray[i].length;\n unchecked {\n ++validCount;\n }\n }\n }\n\n // Resize to validCount - split into separate assembly blocks to avoid stack depth issues\n assembly (\"memory-safe\") {\n mstore(mload(add(validatedData, 0x00)), validCount) // strategies.length = validCount\n }\n assembly (\"memory-safe\") {\n mstore(mload(add(validatedData, 0x20)), validCount) // ppss.length = validCount\n }\n assembly (\"memory-safe\") {\n mstore(mload(add(validatedData, 0x40)), validCount) // timestamps.length = validCount\n }\n assembly (\"memory-safe\") {\n mstore(mload(add(validatedData, 0x60)), validCount) // validatorSets.length = validCount\n }\n }\n\n /// @notice Processes an individual strategy in the batch\n /// @param args Batch update arguments\n /// @param index Index of the strategy to process\n /// @param requiredQuorum Required quorum for validation\n /// @return isValid True if the strategy was processed successfully\n function _processIndividualStrategy(\n UpdatePPSArgs calldata args,\n uint256 index,\n uint256 requiredQuorum\n )\n internal\n returns (bool isValid)\n {\n address _strategy = args.strategies[index];\n\n // Use self-call + interface for try/catch (update interface signature accordingly)\n try IECDSAPPSOracle(address(this))\n .validateProofs(\n IECDSAPPSOracle.ValidationParams({\n strategy: _strategy,\n proofs: args.proofsArray[index],\n pps: args.ppss[index],\n timestamp: args.timestamps[index]\n }),\n requiredQuorum\n ) {\n emit PPSValidated(_strategy, args.ppss[index], args.timestamps[index], msg.sender);\n } catch Error(string memory reason) {\n emit ProofValidationFailed(_strategy, reason);\n return false;\n } catch (bytes memory lowLevelData) {\n emit ProofValidationFailedLowLevel(_strategy, lowLevelData);\n return false;\n }\n\n return true;\n }\n\n /// @notice Forwards valid entries to SuperVaultAggregator\n /// @param validatedData Struct containing validated batch data\n function _forwardValidEntries(ValidatedBatchData memory validatedData) internal {\n uint256 count = validatedData.strategies.length;\n\n // Only forward if there are valid entries\n if (count > 0) {\n try ISuperVaultAggregator(SUPER_GOVERNOR.getAddress(SUPER_VAULT_AGGREGATOR))\n .forwardPPS(\n ISuperVaultAggregator.ForwardPPSArgs({\n strategies: validatedData.strategies,\n ppss: validatedData.ppss,\n timestamps: validatedData.timestamps,\n updateAuthority: msg.sender\n })\n ) {\n // [Property 2: Nonce-Based Replay Protection]\n // See security_properties.md Property 2 for full specification.\n //\n // CRITICAL DESIGN DECISION: Increment nonce ONLY after successful forwarding (try block succeeds).\n //\n // Nonces increment when forwardPPS() returns normally (no revert), which includes:\n // 1. ✓ Legitimate PPS updates that are accepted and stored\n // 2. ✓ Business logic rejections using 'return' or 'continue' (not 'revert')\n // Examples: rate limits exceeded, deviation threshold failures, insufficient upkeep\n //\n // Nonces preserved when forwardPPS() reverts (catch blocks), allowing retry:\n // 3. ✗ Contract reverts (system errors)\n // 4. ✗ Out of gas conditions\n // 5. ✗ Network/RPC failures\n for (uint256 i; i < count; ++i) {\n noncePerStrategy[validatedData.strategies[i]]++;\n }\n } \n // [Property 3: Limited Retry Capability]\n // When forwardPPS() reverts (catch blocks), nonces remain unchanged.\n // This allows retrying with the same signatures after external failures resolve.\n // Retry possible for: contract reverts, out of gas, network failures.\n // Retry NOT possible for: business logic rejections (return/continue) that don't revert.\n catch Error(string memory reason) {\n emit BatchForwardPPSFailed(reason);\n } catch (bytes memory lowLevelData) {\n emit BatchForwardPPSFailedLowLevel(lowLevelData);\n }\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS\n }\n\n /**\n * @dev The signature derives the `address(0)`.\n */\n error ECDSAInvalidSignature();\n\n /**\n * @dev The signature has an invalid length.\n */\n error ECDSAInvalidSignatureLength(uint256 length);\n\n /**\n * @dev The signature has an S value that is in the upper half order.\n */\n error ECDSAInvalidSignatureS(bytes32 s);\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n * and a bytes32 providing additional information about the error.\n *\n * If no error is returned, then the address can be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n */\n function tryRecover(\n bytes32 hash,\n bytes memory signature\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly (\"memory-safe\") {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n unchecked {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n // We do not check for an overflow here since the shift operation results in 0 or 1.\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n */\n function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS, s);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature, bytes32(0));\n }\n\n return (signer, RecoverError.NoError, bytes32(0));\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n */\n function _throwError(RecoverError error, bytes32 errorArg) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert ECDSAInvalidSignature();\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert ECDSAInvalidSignatureLength(uint256(errorArg));\n } else if (error == RecoverError.InvalidSignatureS) {\n revert ECDSAInvalidSignatureS(errorArg);\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.20;\n\nimport {MessageHashUtils} from \"./MessageHashUtils.sol\";\nimport {ShortStrings, ShortString} from \"../ShortStrings.sol\";\nimport {IERC5267} from \"../../interfaces/IERC5267.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain\n * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the\n * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.\n *\n * @custom:oz-upgrades-unsafe-allow state-variable-immutable\n */\nabstract contract EIP712 is IERC5267 {\n using ShortStrings for *;\n\n bytes32 private constant TYPE_HASH =\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _cachedDomainSeparator;\n uint256 private immutable _cachedChainId;\n address private immutable _cachedThis;\n\n bytes32 private immutable _hashedName;\n bytes32 private immutable _hashedVersion;\n\n ShortString private immutable _name;\n ShortString private immutable _version;\n // slither-disable-next-line constable-states\n string private _nameFallback;\n // slither-disable-next-line constable-states\n string private _versionFallback;\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n _name = name.toShortStringWithFallback(_nameFallback);\n _version = version.toShortStringWithFallback(_versionFallback);\n _hashedName = keccak256(bytes(name));\n _hashedVersion = keccak256(bytes(version));\n\n _cachedChainId = block.chainid;\n _cachedDomainSeparator = _buildDomainSeparator();\n _cachedThis = address(this);\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _cachedThis && block.chainid == _cachedChainId) {\n return _cachedDomainSeparator;\n } else {\n return _buildDomainSeparator();\n }\n }\n\n function _buildDomainSeparator() private view returns (bytes32) {\n return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\n /// @inheritdoc IERC5267\n function eip712Domain()\n public\n view\n virtual\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n )\n {\n return (\n hex\"0f\", // 01111\n _EIP712Name(),\n _EIP712Version(),\n block.chainid,\n address(this),\n bytes32(0),\n new uint256[](0)\n );\n }\n\n /**\n * @dev The name parameter for the EIP712 domain.\n *\n * NOTE: By default this function reads _name which is an immutable value.\n * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).\n */\n // solhint-disable-next-line func-name-mixedcase\n function _EIP712Name() internal view returns (string memory) {\n return _name.toStringWithFallback(_nameFallback);\n }\n\n /**\n * @dev The version parameter for the EIP712 domain.\n *\n * NOTE: By default this function reads _version which is an immutable value.\n * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).\n */\n // solhint-disable-next-line func-name-mixedcase\n function _EIP712Version() internal view returns (string memory) {\n return _version.toStringWithFallback(_versionFallback);\n }\n}\n"},"src/interfaces/ISuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n/// @notice Enum representing different types of fees that can be managed\nenum FeeType {\n REVENUE_SHARE,\n PERFORMANCE_FEE_SHARE\n}\n/// @title ISuperGovernor\n/// @author Superform Labs\n/// @notice Interface for the SuperGovernor contract\n/// @dev Central registry for all deployed contracts in the Superform periphery\n\ninterface ISuperGovernor is IAccessControl {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Structure containing Merkle root data for a hook\n struct HookMerkleRootData {\n bytes32 currentRoot; // Current active Merkle root for the hook\n bytes32 proposedRoot; // Proposed new Merkle root (zero if no proposal exists)\n uint256 effectiveTime; // Timestamp when the proposed root becomes effective\n }\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when trying to access a contract that is not registered\n error CONTRACT_NOT_FOUND();\n /// @notice Thrown when providing an invalid address (typically zero address)\n error INVALID_ADDRESS();\n /// @notice Thrown when a hook is not approved but expected to be\n error HOOK_NOT_APPROVED();\n /// @notice Thrown when an invalid fee value is proposed (must be <= BPS_MAX)\n error INVALID_FEE_VALUE();\n /// @notice Thrown when no proposed fee exists but one is expected\n error NO_PROPOSED_FEE(FeeType feeType);\n /// @notice Thrown when timelock period has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when a validator is already registered\n error VALIDATOR_ALREADY_REGISTERED();\n /// @notice Thrown when trying to change active PPS oracle directly\n error MUST_USE_TIMELOCK_FOR_CHANGE();\n /// @notice Thrown when a SuperBank hook Merkle root is not registered but expected to be\n /// @dev This error is defined here for use by other contracts in the system (SuperVaultStrategy,\n /// SuperVaultAggregator, ECDSAPPSOracle)\n error INVALID_TIMESTAMP();\n /// @notice Thrown when attempting to set an invalid quorum value (typically zero)\n error INVALID_QUORUM();\n /// @notice Thrown when validator and public key array lengths don't match\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when trying to set validator config with an empty validator array\n error EMPTY_VALIDATOR_ARRAY();\n /// @notice Thrown when no active PPS oracle is set but one is required\n error NO_ACTIVE_PPS_ORACLE();\n /// @notice Thrown when no proposed PPS oracle exists but one is expected\n error NO_PROPOSED_PPS_ORACLE();\n /// @notice Error thrown when manager takeovers are frozen\n error MANAGER_TAKEOVERS_FROZEN();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error NO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error ZERO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed minimum staleness exists but one is expected\n error NO_PROPOSED_MIN_STALENESS();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when there's no pending change but one is expected\n error NO_PENDING_CHANGE();\n /// @notice Thrown when the super oracle is not found\n error SUPER_ORACLE_NOT_FOUND();\n /// @notice Thrown when the up token is not found\n error UP_NOT_FOUND();\n /// @notice Thrown when the upkeep token is not found\n error UPKEEP_TOKEN_NOT_FOUND();\n /// @notice Thrown when the gas info is invalid\n error INVALID_GAS_INFO();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an address is set in the registry\n /// @param key The key used to reference the address\n /// @param oldValue The old address value\n /// @param value The address value\n event AddressSet(bytes32 indexed key, address indexed oldValue, address indexed value);\n\n /// @notice Emitted when a hook is approved\n /// @param hook The address of the approved hook\n event HookApproved(address indexed hook);\n\n /// @notice Emitted when validator configuration is set\n /// @param version The version of the configuration\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys (for signature verification)\n /// @param quorum The quorum required for validator consensus\n /// @param offchainConfig Offchain configuration data\n event ValidatorConfigSet(\n uint256 version, address[] validators, bytes[] validatorPublicKeys, uint256 quorum, bytes offchainConfig\n );\n\n /// @notice Emitted when a hook is removed\n /// @param hook The address of the removed hook\n event HookRemoved(address indexed hook);\n\n /// @notice Emitted when a new fee is proposed\n /// @param feeType The type of fee being proposed\n /// @param value The proposed fee value (in basis points)\n /// @param effectiveTime The timestamp when the fee will be effective\n event FeeProposed(FeeType indexed feeType, uint256 value, uint256 effectiveTime);\n\n /// @notice Emitted when a fee is updated\n /// @param feeType The type of fee being updated\n /// @param value The new fee value (in basis points)\n event FeeUpdated(FeeType indexed feeType, uint256 value);\n\n /// @notice Emitted when a new SuperBank hook Merkle root is proposed\n /// @param hook The hook address for which the Merkle root is being proposed\n /// @param newRoot The new Merkle root\n /// @param effectiveTime The timestamp when the new root will be effective\n event SuperBankHookMerkleRootProposed(address indexed hook, bytes32 newRoot, uint256 effectiveTime);\n\n /// @notice Emitted when the SuperBank hook Merkle root is updated.\n /// @param hook The address of the hook for which the Merkle root was updated.\n /// @param newRoot The new Merkle root.\n event SuperBankHookMerkleRootUpdated(address indexed hook, bytes32 newRoot);\n\n /// @notice Emitted when an active PPS oracle is initially set\n /// @param oracle The address of the set oracle\n event ActivePPSOracleSet(address indexed oracle);\n\n /// @notice Emitted when a new PPS oracle is proposed\n /// @param oracle The address of the proposed oracle\n /// @param effectiveTime The timestamp when the proposal will be effective\n event ActivePPSOracleProposed(address indexed oracle, uint256 effectiveTime);\n\n /// @notice Emitted when the active PPS oracle is changed\n /// @param oldOracle The address of the previous oracle\n /// @param newOracle The address of the new oracle\n event ActivePPSOracleChanged(address indexed oldOracle, address indexed newOracle);\n\n /// @notice Event emitted when manager takeovers are permanently frozen\n event ManagerTakeoversFrozen();\n\n /// @notice Emitted when a change to upkeep payments status is proposed\n /// @param enabled The proposed status (enabled/disabled)\n /// @param effectiveTime The timestamp when the status change will be effective\n event UpkeepPaymentsChangeProposed(bool enabled, uint256 effectiveTime);\n\n /// @notice Emitted when upkeep payments status is changed\n /// @param enabled The new status (enabled/disabled)\n event UpkeepPaymentsChanged(bool enabled);\n\n /// @notice Emitted when a new minimum staleness is proposed\n /// @param newMinStaleness The proposed minimum staleness value\n /// @param effectiveTime The timestamp when the new value will be effective\n event MinStalenessProposed(uint256 newMinStaleness, uint256 effectiveTime);\n\n /// @notice Emitted when the minimum staleness is changed\n /// @param newMinStaleness The new minimum staleness value\n event MinStalenessChanged(uint256 newMinStaleness);\n\n /// @notice Emitted when gas info is set\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n event GasInfoSet(address indexed oracle, uint256 gasIncreasePerEntryBatch);\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets an address in the registry\n /// @param key The key to associate with the address\n /// @param value The address value\n function setAddress(bytes32 key, address value) external;\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Change the primary manager for a strategy\n /// @dev Only SuperGovernor can call this function directly\n /// @param strategy The strategy address\n /// @param newManager The new primary manager address\n /// @param feeRecipient The new fee recipient address\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Resets the high-water mark PPS to the current PPS\n /// @dev Only SuperGovernor can call this function\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value for the given strategy\n /// @param strategy Address of the strategy to reset the high-water mark for\n function resetHighWaterMark(address strategy) external;\n\n /// @notice Permanently freezes all manager takeovers globally\n function freezeManagerTakeover() external;\n\n /// @notice Changes the hooks root update timelock duration\n /// @param newTimelock New timelock duration in seconds\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes a new global hooks Merkle root\n /// @dev Only GOVERNOR_ROLE can call this function\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Sets veto status for global hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Sets veto status for a strategy-specific hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param strategy Address of the strategy to affect\n /// @param vetoed Whether to veto (true) or unveto (false) the strategy hooks root\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Sets the maximum staleness period for all oracle feeds\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleMaxStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness period for a specific oracle feed\n /// @param feed The address of the feed to set staleness for\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness periods for multiple oracle feeds in batch\n /// @param feeds The addresses of the feeds to set staleness for\n /// @param newMaxStalenessList The new maximum staleness periods in seconds\n function setOracleFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Queues an oracle update for execution after timelock period\n /// @param bases Base asset addresses\n /// @param quotes Quote asset addresses\n /// @param providers Provider identifiers\n /// @param feeds Feed addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Executes a previously queued oracle update after timelock has expired\n function executeOracleUpdate() external;\n\n /// @notice Queues a provider removal for execution after timelock period\n /// @param providers The providers to remove\n function queueOracleProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Sets uptime feeds for multiple data oracles in batch (Layer 2 only)\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Registers a hook for use in SuperVaults\n /// @param hook The address of the hook to register\n function registerHook(address hook) external;\n\n /// @notice Unregisters a hook from the approved list\n /// @param hook The address of the hook to unregister\n function unregisterHook(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the validator configuration for the protocol\n /// @dev This function atomically updates all validator configuration including quorum.\n /// The entire validator set is replaced (not incrementally updated).\n /// Version must be managed externally for cross-chain synchronization.\n /// Quorum updates require providing the full validator list.\n /// @param version The version number for the configuration (for cross-chain sync)\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys for signature verification\n /// @param quorum The number of validators required for consensus\n /// @param offchainConfig Offchain configuration data (emitted but not stored)\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the active PPS oracle (only if there is no active oracle yet)\n /// @param oracle Address of the PPS oracle to set as active\n function setActivePPSOracle(address oracle) external;\n\n /// @notice Proposes a new active PPS oracle (when there is already an active one)\n /// @param oracle Address of the PPS oracle to propose as active\n function proposeActivePPSOracle(address oracle) external;\n\n /// @notice Executes a previously proposed PPS oracle change after timelock has expired\n function executeActivePPSOracleChange() external;\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new fee value\n /// @param feeType The type of fee to propose\n /// @param value The proposed fee value (in basis points)\n function proposeFee(FeeType feeType, uint256 value) external;\n\n /// @notice Executes a previously proposed fee update after timelock has expired\n /// @param feeType The type of ffee to execute the update for\n function executeFeeUpdate(FeeType feeType) external;\n\n /// @notice Executes an upkeep claim on `SuperVaultAggregator`\n /// @param amount The amount to claim\n function executeUpkeepClaim(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets gas info for an oracle\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external;\n\n /// @notice Proposes a change to upkeep payments enabled status\n /// @param enabled The proposed enabled status\n function proposeUpkeepPaymentsChange(bool enabled) external;\n\n /// @notice Executes a previously proposed upkeep payments status change\n function executeUpkeepPaymentsChange() external;\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new minimum staleness value to prevent maxStaleness from being set too low\n /// @param newMinStaleness The proposed new minimum staleness value in seconds\n function proposeMinStaleness(uint256 newMinStaleness) external;\n\n /// @notice Executes a previously proposed minimum staleness change after timelock has expired\n function executeMinStalenessChange() external;\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to update the Merkle root for.\n /// @param proposedRoot The proposed new Merkle root.\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external;\n\n /// @notice Executes a previously proposed Merkle root update for a specific hook if the effective time has passed.\n /// @param hook The address of the hook to execute the update for.\n function executeSuperBankHookMerkleRootUpdate(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice The identifier of the role that grants access to critical governance functions\n function SUPER_GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to daily operations like hooks and validators\n function GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to bank management functions\n function BANK_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to gas management functions\n function GAS_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to oracle management functions\n function ORACLE_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to guardian functions\n function GUARDIAN_ROLE() external view returns (bytes32);\n\n /// @notice Gets an address from the registry\n /// @param key The key of the address to get\n /// @return The address value\n function getAddress(bytes32 key) external view returns (address);\n\n /// @notice Checks if manager takeovers are frozen\n /// @return True if manager takeovers are frozen, false otherwise\n function isManagerTakeoverFrozen() external view returns (bool);\n\n /// @notice Checks if a hook is registered\n /// @param hook The address of the hook to check\n /// @return True if the hook is registered, false otherwise\n function isHookRegistered(address hook) external view returns (bool);\n\n /// @notice Gets all registered hooks\n /// @return An array of registered hook addresses\n function getRegisteredHooks() external view returns (address[] memory);\n\n /// @notice Checks if an address is an approved validator\n /// @param validator The address to check\n /// @return True if the address is an approved validator, false otherwise\n function isValidator(address validator) external view returns (bool);\n\n /// @notice Checks if an address has the guardian role\n /// @param guardian Address to check\n /// @return true if the address has the GUARDIAN_ROLE\n function isGuardian(address guardian) external view returns (bool);\n\n /// @notice Returns the complete validator configuration\n /// @return version The current configuration version number\n /// @return validators Array of all registered validator addresses\n /// @return validatorPublicKeys Array of validator public keys\n /// @return quorum The number of validators required for consensus\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum);\n\n /// @notice Returns all registered validators\n /// @return List of validator addresses\n function getValidators() external view returns (address[] memory);\n\n /// @notice Returns the number of registered validators (O(1))\n function getValidatorsCount() external view returns (uint256);\n\n /// @notice Returns a validator address by index (0 … count-1)\n /// @param index The index into the validators set\n /// @return validator The validator address at the given index\n function getValidatorAt(uint256 index) external view returns (address validator);\n\n /// @notice Gets the proposed active PPS oracle and its effective time\n /// @return proposedOracle The proposed oracle address\n /// @return effectiveTime The timestamp when the proposed oracle will become effective\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime);\n\n /// @notice Gets the current quorum requirement for the active PPS Oracle\n /// @return The current quorum requirement\n function getPPSOracleQuorum() external view returns (uint256);\n\n /// @notice Gets the active PPS oracle\n /// @return The active PPS oracle address\n function getActivePPSOracle() external view returns (address);\n\n /// @notice Checks if an address is the current active PPS oracle\n /// @param oracle The address to check\n /// @return True if the address is the active PPS oracle, false otherwise\n function isActivePPSOracle(address oracle) external view returns (bool);\n\n /// @notice Gets the current fee value for a specific fee type\n /// @param feeType The type of fee to get\n /// @return The current fee value (in basis points)\n function getFee(FeeType feeType) external view returns (uint256);\n\n /// @notice Gets the current upkeep cost for an entry\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256);\n\n /// @notice Gets the proposed upkeep cost per update and its effective time\n /// @notice Gets the current minimum staleness value\n /// @return The current minimum staleness value in seconds\n function getMinStaleness() external view returns (uint256);\n\n /// @notice Gets the proposed minimum staleness value and its effective time\n /// @return proposedMinStaleness The proposed new minimum staleness value\n /// @return effectiveTime The timestamp when the new value will become effective\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime);\n\n /// @notice Returns the current Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to get the Merkle root for.\n /// @return The Merkle root for the hook's allowed targets.\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32);\n\n /// @notice Gets the proposed Merkle root and its effective time for a specific hook.\n /// @param hook The address of the hook to get the proposed Merkle root for.\n /// @return proposedRoot The proposed Merkle root.\n /// @return effectiveTime The timestamp when the proposed root will become effective.\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime);\n\n /// @notice Checks if upkeep payments are currently enabled\n /// @return enabled True if upkeep payments are enabled\n function isUpkeepPaymentsEnabled() external view returns (bool);\n\n /// @notice Gets the proposed upkeep payments status and effective time\n /// @return enabled The proposed status\n /// @return effectiveTime The timestamp when the change becomes effective\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime);\n\n /// @notice Gets the SUP strategy ID\n /// @return The ID of the SUP strategy vault\n function SUP_STRATEGY() external view returns (bytes32);\n\n /// @notice Gets the UP ID\n /// @return The ID of the UP token\n function UP() external view returns (bytes32);\n\n /// @notice Gets the UPKEEP_TOKEN ID\n /// @return The ID of the UPKEEP_TOKEN (used for upkeep payments, can be UP on mainnet or WETH/USDC on L2s)\n function UPKEEP_TOKEN() external view returns (bytes32);\n\n /// @notice Gets the Treasury ID\n /// @return The ID for the Treasury in the registry\n function TREASURY() external view returns (bytes32);\n\n /// @notice Gets the SuperOracle ID\n /// @return The ID for the SuperOracle in the registry\n function SUPER_ORACLE() external view returns (bytes32);\n\n /// @notice Gets the ECDSA PPS Oracle ID\n /// @return The ID for the ECDSA PPS Oracle in the registry\n function ECDSAPPSORACLE() external view returns (bytes32);\n\n /// @notice Gets the SuperVaultAggregator ID\n /// @return The ID for the SuperVaultAggregator in the registry\n function SUPER_VAULT_AGGREGATOR() external view returns (bytes32);\n\n /// @notice Gets the SuperBank ID\n /// @return The ID for the SuperBank in the registry\n function SUPER_BANK() external view returns (bytes32);\n\n /// @notice Gets the gas info for a specific SuperVault PPS Oracle\n /// @param oracle_ The address of the oracle to get gas info for\n /// @return The gas info for the specified oracle\n function getGasInfo(address oracle_) external view returns (uint256);\n\n /// @notice Cancels a previously proposed oracle provider removal\n function cancelOracleProviderRemoval() external;\n\n /// @notice Executes a previously proposed oracle provider removal after timelock has expired\n function executeOracleProviderRemoval() external;\n}\n"},"src/interfaces/SuperVault/ISuperVaultAggregator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { ISuperVaultStrategy } from \"../SuperVault/ISuperVaultStrategy.sol\";\n\n/// @title ISuperVaultAggregator\n/// @author Superform Labs\n/// @notice Interface for the SuperVaultAggregator contract\n/// @dev Registry and PPS oracle for all SuperVaults\ninterface ISuperVaultAggregator {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for forwarding PPS updates to avoid stack too deep errors\n /// @param strategy Address of the strategy being updated\n /// @param isExempt Whether the update is exempt from paying upkeep\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp when the value was generated\n /// @param upkeepCost Amount of upkeep tokens to charge if not exempt\n struct PPSUpdateData {\n address strategy;\n bool isExempt;\n uint256 pps;\n uint256 timestamp;\n uint256 upkeepCost;\n }\n\n /// @notice Local variables for vault creation to avoid stack too deep\n /// @param currentNonce Current vault creation nonce\n /// @param salt Salt for deterministic proxy creation\n /// @param initialPPS Initial price-per-share value\n struct VaultCreationLocalVars {\n uint256 currentNonce;\n bytes32 salt;\n uint256 initialPPS;\n }\n\n /// @notice Strategy configuration and state data\n /// @param pps Current price-per-share value\n /// @param lastUpdateTimestamp Last time PPS was updated\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param isPaused Whether the strategy is paused\n /// @param mainManager Address of the primary manager controlling the strategy\n /// @param secondaryManagers Set of secondary managers that can manage the strategy\n struct StrategyData {\n uint256 pps; // Slot 0: 32 bytes\n uint256 lastUpdateTimestamp; // Slot 1: 32 bytes\n uint256 minUpdateInterval; // Slot 2: 32 bytes\n uint256 maxStaleness; // Slot 3: 32 bytes\n // Packed slot 4: saves 2 storage slots (~4000 gas per read)\n address mainManager; // 20 bytes\n bool ppsStale; // 1 byte\n bool isPaused; // 1 byte\n bool hooksRootVetoed; // 1 byte\n uint72 __gap1; // 9 bytes padding\n EnumerableSet.AddressSet secondaryManagers;\n // Manager change proposal data\n address proposedManager;\n address proposedFeeRecipient;\n uint256 managerChangeEffectiveTime;\n // Hook validation data\n bytes32 managerHooksRoot;\n // Hook root update proposal data\n bytes32 proposedHooksRoot;\n uint256 hooksRootEffectiveTime;\n // PPS Verification thresholds\n uint256 deviationThreshold; // Threshold for abs(new - current) / current\n // Banned global leaves mapping\n mapping(bytes32 => bool) bannedLeaves; // Mapping of leaf hash to banned status\n // Min update interval proposal data\n uint256 proposedMinUpdateInterval;\n uint256 minUpdateIntervalEffectiveTime;\n uint256 lastUnpauseTimestamp; // Timestamp of last unpause (for skim timelock)\n }\n\n /// @notice Parameters for creating a new SuperVault trio\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param mainManager Address of the vault mainManager\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param feeConfig Fee configuration for the vault\n struct VaultCreationParams {\n address asset;\n string name;\n string symbol;\n address mainManager;\n address[] secondaryManagers;\n uint256 minUpdateInterval;\n uint256 maxStaleness;\n ISuperVaultStrategy.FeeConfig feeConfig;\n }\n\n /// @notice Struct to hold cached hook validation state variables to avoid stack too deep\n /// @param globalHooksRootVetoed Cached global hooks root veto status\n /// @param globalHooksRoot Cached global hooks root\n /// @param strategyHooksRootVetoed Cached strategy hooks root veto status\n /// @param strategyRoot Cached strategy hooks root\n struct HookValidationCache {\n bool globalHooksRootVetoed;\n bytes32 globalHooksRoot;\n bool strategyHooksRootVetoed;\n bytes32 strategyRoot;\n }\n\n /// @notice Arguments for validating a hook to avoid stack too deep\n /// @param hookAddress Address of the hook contract\n /// @param hookArgs Encoded arguments for the hook operation\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n struct ValidateHookArgs {\n address hookAddress;\n bytes hookArgs;\n bytes32[] globalProof;\n bytes32[] strategyProof;\n }\n\n /// @notice Two-step upkeep withdrawal request\n /// @param amount Amount to withdraw (full balance at time of request)\n /// @param effectiveTime When withdrawal can be executed (timestamp + 24h)\n struct UpkeepWithdrawalRequest {\n uint256 amount;\n uint256 effectiveTime;\n }\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when a new vault trio is created\n /// @param vault Address of the created SuperVault\n /// @param strategy Address of the created SuperVaultStrategy\n /// @param escrow Address of the created SuperVaultEscrow\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param nonce The nonce used for vault creation\n event VaultDeployed(\n address indexed vault,\n address indexed strategy,\n address escrow,\n address asset,\n string name,\n string symbol,\n uint256 indexed nonce\n );\n\n /// @notice Emitted when a PPS value is updated\n /// @param strategy Address of the strategy\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp of the update\n event PPSUpdated(address indexed strategy, uint256 pps, uint256 timestamp);\n\n /// @notice Emitted when a strategy is paused due to missed updates\n /// @param strategy Address of the paused strategy\n event StrategyPaused(address indexed strategy);\n\n /// @notice Emitted when a strategy is unpaused\n /// @param strategy Address of the unpaused strategy\n event StrategyUnpaused(address indexed strategy);\n\n /// @notice Emitted when a strategy validation check fails but execution continues\n /// @param strategy Address of the strategy that failed the check\n /// @param reason String description of which check failed\n event StrategyCheckFailed(address indexed strategy, string reason);\n\n /// @notice Emitted when upkeep tokens are deposited\n /// @param strategy Address of the strategy\n /// @param depositor Address of the depositor\n /// @param amount Amount of upkeep tokens deposited\n event UpkeepDeposited(address indexed strategy, address indexed depositor, uint256 amount);\n\n /// @notice Emitted when upkeep tokens are withdrawn\n /// @param strategy Address of the strategy\n /// @param withdrawer Address of the withdrawer (main manager of the strategy)\n /// @param amount Amount of upkeep tokens withdrawn\n event UpkeepWithdrawn(address indexed strategy, address indexed withdrawer, uint256 amount);\n\n /// @notice Emitted when an upkeep withdrawal is proposed (start of 24h timelock)\n /// @param strategy Address of the strategy\n /// @param mainManager Address of the main manager who proposed the withdrawal\n /// @param amount Amount of upkeep tokens to withdraw\n /// @param effectiveTime Timestamp when withdrawal can be executed\n event UpkeepWithdrawalProposed(\n address indexed strategy, address indexed mainManager, uint256 amount, uint256 effectiveTime\n );\n\n /// @notice Emitted when a pending upkeep withdrawal is cancelled (e.g., during governance takeover)\n /// @param strategy Address of the strategy\n event UpkeepWithdrawalCancelled(address indexed strategy);\n\n /// @notice Emitted when upkeep tokens are spent for validation\n /// @param strategy Address of the strategy\n /// @param amount Amount of upkeep tokens spent\n /// @param balance Current balance of the strategy\n /// @param claimableUpkeep Amount of upkeep tokens claimable\n event UpkeepSpent(address indexed strategy, uint256 amount, uint256 balance, uint256 claimableUpkeep);\n\n /// @notice Emitted when a secondary manager is added to a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager added\n event SecondaryManagerAdded(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a secondary manager is removed from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager removed\n event SecondaryManagerRemoved(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a primary manager is changed\n /// @param strategy Address of the strategy\n /// @param oldManager Address of the old primary manager\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n event PrimaryManagerChanged(\n address indexed strategy, address indexed oldManager, address indexed newManager, address feeRecipient\n );\n\n /// @notice Emitted when a change to primary manager is proposed by a secondary manager\n /// @param strategy Address of the strategy\n /// @param proposer Address of the secondary manager who made the proposal\n /// @param newManager Address of the proposed new primary manager\n /// @param effectiveTime Timestamp when the proposal can be executed\n event PrimaryManagerChangeProposed(\n address indexed strategy,\n address indexed proposer,\n address indexed newManager,\n address feeRecipient,\n uint256 effectiveTime\n );\n\n /// @notice Emitted when a primary manager change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledManager Address of the manager that was proposed\n event PrimaryManagerChangeCancelled(address indexed strategy, address indexed cancelledManager);\n\n /// @notice Emitted when the High Water Mark for a strategy is reset to PPS\n /// @param strategy Address of the strategy\n /// @param newHWM The new High Water Mark (PPS)\n event HighWaterMarkReset(address indexed strategy, uint256 indexed newHWM);\n\n /// @notice Emitted when a PPS update is stale (Validators could get slashed for innactivity)\n /// @param strategy Address of the strategy\n /// @param updateAuthority Address of the update authority\n /// @param timestamp Timestamp of the stale update\n event StaleUpdate(address indexed strategy, address indexed updateAuthority, uint256 timestamp);\n\n /// @notice Emitted when the global hooks Merkle root is being updated\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event GlobalHooksRootUpdateProposed(bytes32 indexed root, uint256 effectiveTime);\n\n /// @notice Emitted when the global hooks Merkle root is updated\n /// @param oldRoot Previous root value\n /// @param newRoot New root value\n event GlobalHooksRootUpdated(bytes32 indexed oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is updated\n /// @param strategy Address of the strategy\n /// @param oldRoot Previous root value (may be zero)\n /// @param newRoot New root value\n event StrategyHooksRootUpdated(address indexed strategy, bytes32 oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the account proposing the new root\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event StrategyHooksRootUpdateProposed(\n address indexed strategy, address indexed proposer, bytes32 root, uint256 effectiveTime\n );\n\n /// @notice Emitted when a proposed global hooks root update is vetoed by SuperGovernor\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event GlobalHooksRootVetoStatusChanged(bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's hooks Merkle root veto status changes\n /// @param strategy Address of the strategy\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event StrategyHooksRootVetoStatusChanged(address indexed strategy, bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's deviation threshold is updated\n /// @param strategy Address of the strategy\n /// @param deviationThreshold New deviation threshold (abs diff/current)\n event DeviationThresholdUpdated(address indexed strategy, uint256 deviationThreshold);\n\n /// @notice Emitted when the hooks root update timelock is changed\n /// @param newTimelock New timelock duration in seconds\n event HooksRootUpdateTimelockChanged(uint256 newTimelock);\n\n /// @notice Emitted when global leaves status is changed for a strategy\n /// @param strategy Address of the strategy\n /// @param leaves Array of leaf hashes that had their status changed\n /// @param statuses Array of new banned statuses (true = banned, false = allowed)\n event GlobalLeavesStatusChanged(address indexed strategy, bytes32[] leaves, bool[] statuses);\n\n /// @notice Emitted when upkeep is claimed\n /// @param superBank Address of the superBank\n /// @param amount Amount of upkeep claimed\n event UpkeepClaimed(address indexed superBank, uint256 amount);\n\n /// @notice Emitted when PPS update is too frequent (before minUpdateInterval)\n event UpdateTooFrequent();\n\n /// @notice Emitted when PPS update timestamp is not monotonically increasing\n event TimestampNotMonotonic();\n\n /// @notice Emitted when PPS update is rejected due to stale signature after unpause\n event StaleSignatureAfterUnpause(\n address indexed strategy, uint256 signatureTimestamp, uint256 lastUnpauseTimestamp\n );\n\n /// @notice Emitted when a strategy does not have enough upkeep balance\n event InsufficientUpkeep(address indexed strategy, address indexed strategyAddr, uint256 balance, uint256 cost);\n\n /// @notice Emitted when the provided timestamp is too large\n event ProvidedTimestampExceedsBlockTimestamp(\n address indexed strategy, uint256 argsTimestamp, uint256 blockTimestamp\n );\n\n /// @notice Emitted when a strategy is unknown\n event UnknownStrategy(address indexed strategy);\n\n /// @notice Emitted when the old primary manager is removed from the strategy\n /// @dev This can happen because of reaching the max number of secondary managers\n event OldPrimaryManagerRemoved(address indexed strategy, address indexed oldManager);\n\n /// @notice Emitted when a strategy's PPS is stale\n event StrategyPPSStale(address indexed strategy);\n\n /// @notice Emitted when a strategy's PPS is reset\n event StrategyPPSStaleReset(address indexed strategy);\n\n /// @notice Emitted when PPS is updated after performance fee skimming\n /// @param strategy Address of the strategy\n /// @param oldPPS Previous price-per-share value\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee skimmed that caused the PPS update\n /// @param timestamp Timestamp of the update\n event PPSUpdatedAfterSkim(\n address indexed strategy, uint256 oldPPS, uint256 newPPS, uint256 feeAmount, uint256 timestamp\n );\n\n /// @notice Emitted when a change to minUpdateInterval is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the manager who made the proposal\n /// @param newMinUpdateInterval The proposed new minimum update interval\n /// @param effectiveTime Timestamp when the proposal can be executed\n event MinUpdateIntervalChangeProposed(\n address indexed strategy, address indexed proposer, uint256 newMinUpdateInterval, uint256 effectiveTime\n );\n\n /// @notice Emitted when a minUpdateInterval change is executed\n /// @param strategy Address of the strategy\n /// @param oldMinUpdateInterval Previous minimum update interval\n /// @param newMinUpdateInterval New minimum update interval\n event MinUpdateIntervalChanged(\n address indexed strategy, uint256 oldMinUpdateInterval, uint256 newMinUpdateInterval\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is rejected due to validation failure\n /// @param strategy Address of the strategy\n /// @param proposedInterval The proposed interval that was rejected\n /// @param currentMaxStaleness The current maxStaleness value that caused rejection\n event MinUpdateIntervalChangeRejected(\n address indexed strategy, uint256 proposedInterval, uint256 currentMaxStaleness\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledInterval The proposed interval that was cancelled\n event MinUpdateIntervalChangeCancelled(address indexed strategy, uint256 cancelledInterval);\n\n /// @notice Emitted when a PPS update is rejected because strategy is paused\n /// @param strategy Address of the paused strategy\n event PPSUpdateRejectedStrategyPaused(address indexed strategy);\n\n /*///////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when address provided is zero\n error ZERO_ADDRESS();\n /// @notice Thrown when amount provided is zero\n error ZERO_AMOUNT();\n /// @notice Thrown when vault creation parameters are invalid (empty name or symbol)\n error INVALID_VAULT_PARAMS();\n /// @notice Thrown when array length is zero\n error ZERO_ARRAY_LENGTH();\n /// @notice Thrown when array length is zero\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when asset is invalid\n error INVALID_ASSET();\n /// @notice Thrown when insufficient upkeep balance for operation\n error INSUFFICIENT_UPKEEP();\n /// @notice Thrown when caller is not authorized\n error CALLER_NOT_AUTHORIZED();\n /// @notice Thrown when caller is not an approved PPS oracle\n error UNAUTHORIZED_PPS_ORACLE();\n /// @notice Thrown when caller is not authorized for update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n /// @notice Thrown when strategy address is not a known SuperVault strategy\n error UNKNOWN_STRATEGY();\n /// @notice Thrown when trying to unpause a strategy that is not paused\n error STRATEGY_NOT_PAUSED();\n /// @notice Thrown when trying to pause a strategy that is already paused\n error STRATEGY_ALREADY_PAUSED();\n /// @notice Thrown when array index is out of bounds\n error INDEX_OUT_OF_BOUNDS();\n /// @notice Thrown when attempting to add a manager that already exists\n error MANAGER_ALREADY_EXISTS();\n /// @notice Thrown when attempting to add a manager that is the primary manager\n error SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n /// @notice Thrown when there is no pending global hooks root change\n error NO_PENDING_GLOBAL_ROOT_CHANGE();\n /// @notice Thrown when attempting to execute a hooks root change before timelock has elapsed\n error ROOT_UPDATE_NOT_READY();\n /// @notice Thrown when a provided hook fails Merkle proof validation\n error HOOK_VALIDATION_FAILED();\n /// @notice Thrown when manager is not found\n error MANAGER_NOT_FOUND();\n /// @notice Thrown when there is no pending manager change proposal\n error NO_PENDING_MANAGER_CHANGE();\n /// @notice Thrown when caller is not authorized to update settings\n error UNAUTHORIZED_CALLER();\n /// @notice Thrown when the timelock for a proposed change has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when an array length is invalid\n error INVALID_ARRAY_LENGTH();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when arrays have mismatched lengths\n error MISMATCHED_ARRAY_LENGTHS();\n /// @notice Thrown when timestamp is invalid\n error INVALID_TIMESTAMP(uint256 index);\n /// @notice Thrown when too many secondary managers are added\n error TOO_MANY_SECONDARY_MANAGERS();\n /// @notice Thrown when upkeep withdrawal timelock has not passed yet\n error UPKEEP_WITHDRAWAL_NOT_READY();\n /// @notice Thrown when no pending upkeep withdrawal request exists\n error UPKEEP_WITHDRAWAL_NOT_FOUND();\n /// @notice PPS must decrease after skimming fees\n error PPS_MUST_DECREASE_AFTER_SKIM();\n /// @notice PPS deduction is larger than the maximum allowed fee rate\n error PPS_DEDUCTION_TOO_LARGE();\n /// @notice Thrown when no minUpdateInterval change proposal is pending\n error NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n /// @notice Thrown when minUpdateInterval >= maxStaleness\n error MIN_UPDATE_INTERVAL_TOO_HIGH();\n /// @notice Thrown when trying to update PPS while strategy is paused\n error STRATEGY_PAUSED();\n /// @notice Thrown when trying to update PPS while PPS is stale\n error PPS_STALE();\n\n /*//////////////////////////////////////////////////////////////\n VAULT CREATION\n //////////////////////////////////////////////////////////////*/\n /// @notice Creates a new SuperVault trio (SuperVault, SuperVaultStrategy, SuperVaultEscrow)\n /// @param params Parameters for the new vault creation\n /// @return superVault Address of the created SuperVault\n /// @return strategy Address of the created SuperVaultStrategy\n /// @return escrow Address of the created SuperVaultEscrow\n function createVault(VaultCreationParams calldata params)\n external\n returns (address superVault, address strategy, address escrow);\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for batch forwarding PPS updates\n /// @param strategies Array of strategy addresses\n /// @param ppss Array of price-per-share values\n /// @param timestamps Array of timestamps when values were generated\n /// @param updateAuthority Address of the update authority\n struct ForwardPPSArgs {\n address[] strategies;\n uint256[] ppss;\n uint256[] timestamps;\n address updateAuthority;\n }\n\n /// @notice Batch forwards validated PPS updates to multiple strategies\n /// @param args Struct containing all batch PPS update parameters\n function forwardPPS(ForwardPPSArgs calldata args) external;\n\n /// @notice Updates PPS directly after performance fee skimming\n /// @dev Only callable by the strategy contract itself (msg.sender must be a registered strategy)\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee that was skimmed (for event logging)\n function updatePPSAfterSkim(uint256 newPPS, uint256 feeAmount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Deposits upkeep tokens for strategy upkeep\n /// @dev The upkeep token is configurable per chain (UP on mainnet, WETH on L2s, etc.)\n /// @param strategy Address of the strategy to deposit for\n /// @param amount Amount of upkeep tokens to deposit\n function depositUpkeep(address strategy, uint256 amount) external;\n\n /// @notice Proposes withdrawal of upkeep tokens from strategy upkeep balance (starts 24h timelock)\n /// @dev Only the main manager can propose. Withdraws full balance at time of proposal.\n /// @param strategy Address of the strategy to withdraw from\n function proposeWithdrawUpkeep(address strategy) external;\n\n /// @notice Executes a pending upkeep withdrawal after 24h timelock\n /// @dev Anyone can execute, but funds go to the main manager of the strategy\n /// @param strategy Address of the strategy to withdraw from\n function executeWithdrawUpkeep(address strategy) external;\n\n /// @notice Claims upkeep tokens from the contract\n /// @param amount Amount of upkeep tokens to claim\n function claimUpkeep(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n PAUSE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Manually pauses a strategy\n /// @param strategy Address of the strategy to pause\n function pauseStrategy(address strategy) external;\n\n /// @notice Manually unpauses a strategy\n /// @param strategy Address of the strategy to unpause\n function unpauseStrategy(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER MANAGEMENT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Adds a secondary manager to a strategy\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to add\n function addSecondaryManager(address strategy, address manager) external;\n\n /// @notice Removes a secondary manager from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to remove\n function removeSecondaryManager(address strategy, address manager) external;\n\n /// @notice Changes the primary manager of a strategy immediately (only callable by SuperGovernor)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Proposes a change to the primary manager (callable by secondary managers)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the proposed new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function proposeChangePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Cancels a pending primary manager change proposal\n /// @dev Only the current primary manager can cancel the proposal\n /// @param strategy Address of the strategy\n function cancelChangePrimaryManager(address strategy) external;\n\n /// @notice Executes a previously proposed change to the primary manager after timelock\n /// @param strategy Address of the strategy\n function executeChangePrimaryManager(address strategy) external;\n\n /// @notice Resets the strategy's performance-fee high-water mark to PPS\n /// @dev Only callable by SuperGovernor\n /// @param strategy Address of the strategy\n function resetHighWaterMark(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK VALIDATION FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets a new hooks root update timelock duration\n /// @param newTimelock The new timelock duration in seconds\n function setHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes an update to the global hooks Merkle root\n /// @dev Only callable by SUPER_GOVERNOR\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed global hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeGlobalHooksRootUpdate() external;\n\n /// @notice Proposes an update to a strategy-specific hooks Merkle root\n /// @dev Only callable by the main manager for the strategy\n /// @param strategy Address of the strategy\n /// @param newRoot New Merkle root for strategy-specific hooks\n function proposeStrategyHooksRoot(address strategy, bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed strategy hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n /// @param strategy Address of the strategy whose root update to execute\n function executeStrategyHooksRootUpdate(address strategy) external;\n\n /// @notice Set veto status for the global hooks root\n /// @dev Only callable by SuperGovernor\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Set veto status for a strategy-specific hooks root\n /// @notice Sets the veto status of a strategy's hooks Merkle root\n /// @param strategy Address of the strategy\n /// @param vetoed Whether to veto (true) or unveto (false)\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Updates the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @param deviationThreshold_ New deviation threshold (abs diff/current ratio, scaled by 1e18)\n function updateDeviationThreshold(address strategy, uint256 deviationThreshold_) external;\n\n /// @notice Changes the banned status of global leaves for a specific strategy\n /// @dev Only callable by the primary manager of the strategy\n /// @param leaves Array of leaf hashes to change status for\n /// @param statuses Array of banned statuses (true = banned, false = allowed)\n /// @param strategy Address of the strategy to change banned leaves for\n function changeGlobalLeavesStatus(bytes32[] memory leaves, bool[] memory statuses, address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MIN UPDATE INTERVAL MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Proposes a change to the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @param newMinUpdateInterval The proposed new minimum update interval (in seconds)\n /// @dev Only the main manager can propose. Must be less than maxStaleness\n function proposeMinUpdateIntervalChange(address strategy, uint256 newMinUpdateInterval) external;\n\n /// @notice Executes a previously proposed minUpdateInterval change after timelock\n /// @param strategy Address of the strategy whose minUpdateInterval to update\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Cancels a pending minUpdateInterval change proposal\n /// @param strategy Address of the strategy\n /// @dev Only the main manager can cancel\n function cancelMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Gets the proposed minUpdateInterval and effective time\n /// @param strategy Address of the strategy\n /// @return proposedInterval The proposed minimum update interval\n /// @return effectiveTime The timestamp when the proposed interval becomes effective\n function getProposedMinUpdateInterval(address strategy)\n external\n view\n returns (uint256 proposedInterval, uint256 effectiveTime);\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the current vault creation nonce\n /// @dev This nonce is incremented every time a new vault is created\n /// @return Current vault creation nonce\n function getCurrentNonce() external view returns (uint256);\n\n /// @notice Check if the global hooks root is currently vetoed\n /// @return vetoed True if the global hooks root is vetoed\n function isGlobalHooksRootVetoed() external view returns (bool vetoed);\n\n /// @notice Check if a strategy hooks root is currently vetoed\n /// @param strategy Address of the strategy to check\n /// @return vetoed True if the strategy hooks root is vetoed\n function isStrategyHooksRootVetoed(address strategy) external view returns (bool vetoed);\n\n /// @notice Gets the current hooks root update timelock duration\n /// @return The current timelock duration in seconds\n function getHooksRootUpdateTimelock() external view returns (uint256);\n\n /// @notice Gets the current PPS (price-per-share) for a strategy\n /// @param strategy Address of the strategy\n /// @return pps Current price-per-share value\n function getPPS(address strategy) external view returns (uint256 pps);\n\n /// @notice Gets the last update timestamp for a strategy's PPS\n /// @param strategy Address of the strategy\n /// @return timestamp Last update timestamp\n function getLastUpdateTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @return interval Minimum time between updates\n function getMinUpdateInterval(address strategy) external view returns (uint256 interval);\n\n /// @notice Gets the maximum staleness period for a strategy\n /// @param strategy Address of the strategy\n /// @return staleness Maximum time allowed between updates\n function getMaxStaleness(address strategy) external view returns (uint256 staleness);\n\n /// @notice Gets the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @return deviationThreshold The current deviation threshold (abs diff/current ratio, scaled by 1e18)\n function getDeviationThreshold(address strategy) external view returns (uint256 deviationThreshold);\n\n /// @notice Checks if a strategy is currently paused\n /// @param strategy Address of the strategy\n /// @return isPaused True if paused, false otherwise\n function isStrategyPaused(address strategy) external view returns (bool isPaused);\n\n /// @notice Checks if a strategy's PPS is stale\n /// @dev PPS is automatically set to stale when the strategy is paused due to\n /// lack of upkeep payment in `SuperVaultAggregator`\n /// @param strategy Address of the strategy\n /// @return isStale True if stale, false otherwise\n function isPPSStale(address strategy) external view returns (bool isStale);\n\n /// @notice Gets the last unpause timestamp for a strategy\n /// @param strategy Address of the strategy\n /// @return timestamp Last unpause timestamp (0 if never unpaused)\n function getLastUnpauseTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the current upkeep balance for a strategy\n /// @param strategy Address of the strategy\n /// @return balance Current upkeep balance in upkeep tokens\n function getUpkeepBalance(address strategy) external view returns (uint256 balance);\n\n /// @notice Gets the main manager for a strategy\n /// @param strategy Address of the strategy\n /// @return manager Address of the main manager\n function getMainManager(address strategy) external view returns (address manager);\n\n /// @notice Gets pending primary manager change details\n /// @param strategy Address of the strategy\n /// @return proposedManager Address of the proposed new manager (address(0) if no pending change)\n /// @return effectiveTime Timestamp when the change can be executed (0 if no pending change)\n function getPendingManagerChange(address strategy)\n external\n view\n returns (address proposedManager, uint256 effectiveTime);\n\n /// @notice Checks if an address is the main manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isMainManager True if the address is the main manager, false otherwise\n function isMainManager(address manager, address strategy) external view returns (bool isMainManager);\n\n /// @notice Gets all secondary managers for a strategy\n /// @param strategy Address of the strategy\n /// @return secondaryManagers Array of secondary manager addresses\n function getSecondaryManagers(address strategy) external view returns (address[] memory secondaryManagers);\n\n /// @notice Checks if an address is a secondary manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isSecondaryManager True if the address is a secondary manager, false otherwise\n function isSecondaryManager(address manager, address strategy) external view returns (bool isSecondaryManager);\n\n /// @dev Internal helper function to check if an address is any kind of manager (primary or secondary)\n /// @param manager Address to check\n /// @param strategy The strategy to check against\n /// @return True if the address is either the primary manager or a secondary manager\n function isAnyManager(address manager, address strategy) external view returns (bool);\n\n /// @notice Gets all created SuperVaults\n /// @return Array of SuperVault addresses\n function getAllSuperVaults() external view returns (address[] memory);\n\n /// @notice Gets a SuperVault by index\n /// @param index The index of the SuperVault\n /// @return The SuperVault address at the given index\n function superVaults(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultStrategies\n /// @return Array of SuperVaultStrategy addresses\n function getAllSuperVaultStrategies() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultStrategy by index\n /// @param index The index of the SuperVaultStrategy\n /// @return The SuperVaultStrategy address at the given index\n function superVaultStrategies(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultEscrows\n /// @return Array of SuperVaultEscrow addresses\n function getAllSuperVaultEscrows() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultEscrow by index\n /// @param index The index of the SuperVaultEscrow\n /// @return The SuperVaultEscrow address at the given index\n function superVaultEscrows(uint256 index) external view returns (address);\n\n /// @notice Validates a hook against both global and strategy-specific Merkle roots\n /// @param strategy Address of the strategy\n /// @param args Arguments for hook validation\n /// @return isValid True if the hook is valid against either root\n function validateHook(address strategy, ValidateHookArgs calldata args) external view returns (bool isValid);\n\n /// @notice Batch validates multiple hooks against Merkle roots\n /// @param strategy Address of the strategy\n /// @param argsArray Array of hook validation arguments\n /// @return validHooks Array of booleans indicating which hooks are valid\n function validateHooks(\n address strategy,\n ValidateHookArgs[] calldata argsArray\n )\n external\n view\n returns (bool[] memory validHooks);\n\n /// @notice Gets the current global hooks Merkle root\n /// @return root The current global hooks Merkle root\n function getGlobalHooksRoot() external view returns (bytes32 root);\n\n /// @notice Gets the proposed global hooks root and effective time\n /// @return root The proposed global hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedGlobalHooksRoot() external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Checks if the global hooks root is active (timelock period has passed)\n /// @return isActive True if the global hooks root is active\n function isGlobalHooksRootActive() external view returns (bool);\n\n /// @notice Gets the hooks Merkle root for a specific strategy\n /// @param strategy Address of the strategy\n /// @return root The strategy-specific hooks Merkle root\n function getStrategyHooksRoot(address strategy) external view returns (bytes32 root);\n\n /// @notice Gets the proposed strategy hooks root and effective time\n /// @param strategy Address of the strategy\n /// @return root The proposed strategy hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedStrategyHooksRoot(address strategy) external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Gets the total number of SuperVaults\n /// @return count The total number of SuperVaults\n function getSuperVaultsCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultStrategies\n /// @return count The total number of SuperVaultStrategies\n function getSuperVaultStrategiesCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultEscrows\n /// @return count The total number of SuperVaultEscrows\n function getSuperVaultEscrowsCount() external view returns (uint256);\n}\n"},"src/interfaces/oracles/IECDSAPPSOracle.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ECDSAPPSOracle\n/// @author Superform Labs\n/// @notice Interface for PPS oracles that provide price-per-share updates\n/// @dev All PPS oracle implementations must conform to this interface\ninterface IECDSAPPSOracle {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when the proof is invalid or cannot be verified\n error INVALID_PROOF();\n /// @notice Thrown when a validator is not registered or authorized\n error INVALID_VALIDATOR();\n /// @notice Thrown when the quorum of validators is not met\n error QUORUM_NOT_MET();\n /// @notice Thrown when the input arrays have different lengths\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when the input array is empty\n error ZERO_LENGTH_ARRAY();\n /// @notice Thrown when the timestamp in the proof is invalid\n error INVALID_TIMESTAMP();\n /// @notice Thrown when the deviation from previous PPS is too high\n error HIGH_PPS_DEVIATION();\n /// @notice Thrown when the totalValidators doesn't match the actual total number of validators\n error INVALID_TOTAL_VALIDATORS();\n /// @notice Thrown when the gas provided is insufficient for external calls\n error INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n /// @notice Thrown when the number of strategies exceeds the maximum allowed\n error MAX_STRATEGIES_EXCEEDED();\n /// @notice Thrown when strategies are not sorted in ascending order or contain duplicates\n error STRATEGIES_NOT_SORTED_UNIQUE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when a PPS update is validated and forwarded\n /// @param strategy Address of the strategy\n /// @param pps The validated price-per-share value\n /// @param timestamp Timestamp when the value was generated\n /// @param sender Address that submitted the update\n event PPSValidated(address indexed strategy, uint256 pps, uint256 timestamp, address indexed sender);\n\n /// @notice Emitted when proof validation failed\n /// @param strategy Address of the strategy\n /// @param reason Revert reason\n event ProofValidationFailed(address indexed strategy, string reason);\n\n /// @notice Emitted when proof validation failed\n /// @param strategy Address of the strategy\n /// @param data Revert encoded data\n event ProofValidationFailedLowLevel(address indexed strategy, bytes data);\n\n /// @notice Emitted when batch forward PPS failed\n /// @param reason Revert reason\n event BatchForwardPPSFailed(string reason);\n\n /// @notice Emitted when batch forward PPS failed\n /// @param lowLevelData Revert encoded data\n event BatchForwardPPSFailedLowLevel(bytes lowLevelData);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Parameters for validating PPS proofs\n /// @param strategy Address of the strategy\n /// @param proofs Array of cryptographic proofs\n /// @param pps Price-per-share value\n /// @param timestamp Timestamp when the value was generated\n struct ValidationParams {\n address strategy;\n bytes[] proofs;\n uint256 pps;\n uint256 timestamp;\n }\n\n /// @notice Arguments for batch updating PPS for multiple strategies\n /// @param strategies Array of strategy addresses\n /// @param proofsArray Array of arrays of cryptographic proofs (one array of proofs per strategy)\n /// @param ppss Array of price-per-share values\n /// @param timestamps The time and therefore the blockchain(s) state(s) (plural important) this PPS refers to\n struct UpdatePPSArgs {\n address[] strategies;\n bytes[][] proofsArray;\n uint256[] ppss;\n uint256[] timestamps;\n }\n\n /// @notice Struct to avoid stack too deep errors in batch processing\n struct ValidatedBatchData {\n address[] strategies;\n uint256[] ppss;\n uint256[] timestamps;\n uint256[] validatorSets;\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Returns the current nonce\n /// @param strategy_ Address of the strategy\n /// @return The current nonce\n function noncePerStrategy(address strategy_) external view returns (uint256);\n\n /// @notice Returns the EIP-712 domain separator for this contract\n /// @return The domain separator used for signature validation\n /// @dev The domain separator is derived from:\n /// - Contract name (set in constructor)\n /// - Contract version (set in constructor)\n /// - Chain ID (from block.chainid)\n /// - Contract address (address(this))\n /// Off-chain signers MUST use this exact domain separator when creating signatures.\n /// The domain separator is computed on-demand using EIP-712's _domainSeparatorV4(),\n /// which handles chain ID changes (e.g., after hard forks).\n /// See EIP-712 specification: https://eips.ethereum.org/EIPS/eip-712\n function domainSeparator() external view returns (bytes32);\n\n /// @notice Returns the signature typehash\n /// @return The typehash\n function UPDATE_PPS_TYPEHASH() external view returns (bytes32);\n\n /// @notice Validates an array of proofs for a strategy's PPS update\n /// @param params Validation parameters\n function validateProofs(IECDSAPPSOracle.ValidationParams memory params) external view;\n\n /// @notice Validates an array of proofs for a strategy's PPS update\n /// @param params Validation parameters\n /// @param requiredQuorum Required quorum for validation\n function validateProofs(IECDSAPPSOracle.ValidationParams memory params, uint256 requiredQuorum) external view;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Updates the PPS for multiple strategies in a batch\n /// @param args Struct containing all parameters for batch PPS update\n function updatePPS(UpdatePPSArgs calldata args) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing a bytes32 `messageHash` with\n * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n * keccak256, although any bytes32 value can be safely used because the final digest will\n * be re-hashed.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing an arbitrary `message` with\n * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n return\n keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x00` (data with intended validator).\n *\n * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n * `validator` address. Then hashing the result.\n *\n * See {ECDSA-recover}.\n */\n function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n }\n\n /**\n * @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.\n */\n function toDataWithIntendedValidatorHash(\n address validator,\n bytes32 messageHash\n ) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, hex\"19_00\")\n mstore(0x02, shl(96, validator))\n mstore(0x16, messageHash)\n digest := keccak256(0x00, 0x36)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).\n *\n * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n *\n * See {ECDSA-recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n mstore(ptr, hex\"19_01\")\n mstore(add(ptr, 0x02), domainSeparator)\n mstore(add(ptr, 0x22), structHash)\n digest := keccak256(ptr, 0x42)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/ShortStrings.sol)\n\npragma solidity ^0.8.20;\n\nimport {StorageSlot} from \"./StorageSlot.sol\";\n\n// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |\n// | length | 0x BB |\ntype ShortString is bytes32;\n\n/**\n * @dev This library provides functions to convert short memory strings\n * into a `ShortString` type that can be used as an immutable variable.\n *\n * Strings of arbitrary length can be optimized using this library if\n * they are short enough (up to 31 bytes) by packing them with their\n * length (1 byte) in a single EVM word (32 bytes). Additionally, a\n * fallback mechanism can be used for every other case.\n *\n * Usage example:\n *\n * ```solidity\n * contract Named {\n * using ShortStrings for *;\n *\n * ShortString private immutable _name;\n * string private _nameFallback;\n *\n * constructor(string memory contractName) {\n * _name = contractName.toShortStringWithFallback(_nameFallback);\n * }\n *\n * function name() external view returns (string memory) {\n * return _name.toStringWithFallback(_nameFallback);\n * }\n * }\n * ```\n */\nlibrary ShortStrings {\n // Used as an identifier for strings longer than 31 bytes.\n bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;\n\n error StringTooLong(string str);\n error InvalidShortString();\n\n /**\n * @dev Encode a string of at most 31 chars into a `ShortString`.\n *\n * This will trigger a `StringTooLong` error is the input string is too long.\n */\n function toShortString(string memory str) internal pure returns (ShortString) {\n bytes memory bstr = bytes(str);\n if (bstr.length > 31) {\n revert StringTooLong(str);\n }\n return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));\n }\n\n /**\n * @dev Decode a `ShortString` back to a \"normal\" string.\n */\n function toString(ShortString sstr) internal pure returns (string memory) {\n uint256 len = byteLength(sstr);\n // using `new string(len)` would work locally but is not memory safe.\n string memory str = new string(32);\n assembly (\"memory-safe\") {\n mstore(str, len)\n mstore(add(str, 0x20), sstr)\n }\n return str;\n }\n\n /**\n * @dev Return the length of a `ShortString`.\n */\n function byteLength(ShortString sstr) internal pure returns (uint256) {\n uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;\n if (result > 31) {\n revert InvalidShortString();\n }\n return result;\n }\n\n /**\n * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.\n */\n function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {\n if (bytes(value).length < 32) {\n return toShortString(value);\n } else {\n StorageSlot.getStringSlot(store).value = value;\n return ShortString.wrap(FALLBACK_SENTINEL);\n }\n }\n\n /**\n * @dev Decode a string that was encoded to `ShortString` or written to storage using {toShortStringWithFallback}.\n */\n function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {\n if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {\n return toString(value);\n } else {\n return store;\n }\n }\n\n /**\n * @dev Return the length of a string that was encoded to `ShortString` or written to storage using\n * {toShortStringWithFallback}.\n *\n * WARNING: This will return the \"byte length\" of the string. This may not reflect the actual length in terms of\n * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.\n */\n function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {\n if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {\n return byteLength(value);\n } else {\n return bytes(store).length;\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)\n\npragma solidity >=0.4.16;\n\ninterface IERC5267 {\n /**\n * @dev MAY be emitted to signal that the domain could have changed.\n */\n event EIP712DomainChanged();\n\n /**\n * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n * signature.\n */\n function eip712Domain()\n external\n view\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n );\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\nimport {Math} from \"../math/Math.sol\";\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * The following types are supported:\n *\n * - `bytes32` (`Bytes32Set`) since v3.3.0\n * - `address` (`AddressSet`) since v3.3.0\n * - `uint256` (`UintSet`) since v3.3.0\n * - `string` (`StringSet`) since v5.4.0\n * - `bytes` (`BytesSet`) since v5.4.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that\n * using it may render the function uncallable if the set grows to the point where clearing it consumes too much\n * gas to fit in a block.\n */\n function _clear(Set storage set) private {\n uint256 len = _length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {\n unchecked {\n end = Math.min(end, _length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes32[] memory result = new bytes32[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(Bytes32Set storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(AddressSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(UintSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n struct StringSet {\n // Storage of set values\n string[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(string value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(StringSet storage set, string memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(StringSet storage set, string memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n string memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(StringSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(StringSet storage set, string memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(StringSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(StringSet storage set, uint256 index) internal view returns (string memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set) internal view returns (string[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n string[] memory result = new string[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n struct BytesSet {\n // Storage of set values\n bytes[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(BytesSet storage set, bytes memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(BytesSet storage set, bytes memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(BytesSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(BytesSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set) internal view returns (bytes[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes[] memory result = new bytes[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n}\n"},"src/interfaces/SuperVault/ISuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { ISuperHook, Execution } from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n/// @title ISuperVaultStrategy\n/// @author Superform Labs\n/// @notice Interface for SuperVault strategy implementation that manages yield sources and executes strategies\ninterface ISuperVaultStrategy {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n error ZERO_LENGTH();\n error INVALID_HOOK();\n error ZERO_ADDRESS();\n error ACCESS_DENIED();\n error INVALID_AMOUNT();\n error OPERATION_FAILED();\n error INVALID_TIMESTAMP();\n error REQUEST_NOT_FOUND();\n error INVALID_ARRAY_LENGTH();\n error ACTION_TYPE_DISALLOWED();\n error YIELD_SOURCE_NOT_FOUND();\n error YIELD_SOURCE_ALREADY_EXISTS();\n error INVALID_PERFORMANCE_FEE_BPS();\n error MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n error MANAGER_NOT_AUTHORIZED();\n error INVALID_PPS();\n error INVALID_VAULT();\n error INVALID_ASSET();\n error OPERATIONS_BLOCKED_BY_VETO();\n error HOOK_VALIDATION_FAILED();\n error STRATEGY_PAUSED();\n error NO_PROPOSAL();\n error INVALID_REDEEM_SLIPPAGE_BPS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n error STALE_PPS();\n error PPS_EXPIRED();\n error INVALID_PPS_EXPIRY_THRESHOLD();\n error BOUNDS_EXCEEDED(uint256 minAllowed, uint256 maxAllowed, uint256 actual);\n error INSUFFICIENT_LIQUIDITY();\n error CONTROLLERS_NOT_SORTED_UNIQUE();\n error ZERO_SHARE_FULFILLMENT_DISALLOWED();\n error NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n error SKIM_TIMELOCK_ACTIVE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event SuperGovernorSet(address indexed superGovernor);\n event Initialized(address indexed vault);\n event YieldSourceAdded(address indexed source, address indexed oracle);\n event YieldSourceOracleUpdated(address indexed source, address indexed oldOracle, address indexed newOracle);\n event YieldSourceRemoved(address indexed source);\n\n event VaultFeeConfigUpdated(uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient);\n event VaultFeeConfigProposed(\n uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient, uint256 effectiveTime\n );\n event HooksExecuted(address[] hooks);\n event RedeemRequestPlaced(address indexed controller, address indexed owner, uint256 shares);\n event RedeemRequestClaimed(address indexed controller, address indexed receiver, uint256 assets, uint256 shares);\n event RedeemRequestsFulfilled(address[] controllers, uint256 processedShares, uint256 currentPPS);\n event RedeemRequestCanceled(address indexed controller, uint256 shares);\n event RedeemCancelRequestPlaced(address indexed controller);\n event RedeemCancelRequestFulfilled(address indexed controller, uint256 shares);\n event HookExecuted(\n address indexed hook,\n address indexed prevHook,\n address indexed targetedYieldSource,\n bool usePrevHookAmount,\n bytes hookCalldata\n );\n\n event PPSUpdated(uint256 newPPS, uint256 calculationBlock);\n event FeeRecipientChanged(address indexed newRecipient);\n event ManagementFeePaid(address indexed controller, address indexed recipient, uint256 feeAssets, uint256 feeBps);\n event DepositHandled(address indexed controller, uint256 assets, uint256 shares);\n event RedeemClaimable(\n address indexed controller, uint256 assetsFulfilled, uint256 sharesFulfilled, uint256 averageWithdrawPrice\n );\n event RedeemSlippageSet(address indexed controller, uint16 slippageBps);\n\n event PPSExpirationProposed(uint256 currentProposedThreshold, uint256 ppsExpiration, uint256 effectiveTime);\n event PPSExpiryThresholdUpdated(uint256 ppsExpiration);\n event PPSExpiryThresholdProposalCanceled();\n\n /// @notice Emitted when the high-water mark PPS is updated after fee collection\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n /// @param previousPps The PPS before fee collection\n /// @param profit The total profit above HWM (in assets)\n /// @param feeCollected The total fee collected (in assets)\n event HWMPPSUpdated(uint256 newHwmPps, uint256 previousPps, uint256 profit, uint256 feeCollected);\n\n /// @notice Emitted when the high-water mark PPS is reset\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n event HighWaterMarkReset(uint256 newHwmPps);\n\n /// @notice Emitted when performance fees are skimmed\n /// @param totalFee The total fee collected (in assets)\n /// @param superformFee The fee collected for Superform (in assets)\n event PerformanceFeeSkimmed(uint256 totalFee, uint256 superformFee);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n struct FeeConfig {\n uint256 performanceFeeBps; // On profit at fulfill time\n uint256 managementFeeBps; // Entry fee on deposit/mint (asset-side)\n address recipient; // Fee sink (entry + performance)\n }\n\n /// @notice Structure for hook execution arguments\n struct ExecuteArgs {\n /// @notice Array of hooks to execute\n address[] hooks;\n /// @notice Calldata for each hook (must match hooks array length)\n bytes[] hookCalldata;\n /// @notice Expected output amounts or output shares\n uint256[] expectedAssetsOrSharesOut;\n /// @notice Global Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] globalProofs;\n /// @notice Strategy-specific Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] strategyProofs;\n }\n\n struct YieldSource {\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice Comprehensive information about a yield source including its address and configuration\n struct YieldSourceInfo {\n address sourceAddress; // Address of the yield source\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice State specific to asynchronous redeem requests\n struct SuperVaultState {\n // Cancellation\n bool pendingCancelRedeemRequest;\n uint256 claimableCancelRedeemRequest;\n // Redeems\n uint256 pendingRedeemRequest; // Shares requested\n uint256 maxWithdraw; // Assets claimable after fulfillment\n uint256 averageRequestPPS; // Average PPS at the time of redeem request\n uint256 averageWithdrawPrice; // Average price for claimable assets\n uint16 redeemSlippageBps; // User-defined slippage tolerance in BPS for redeem fulfillment\n }\n\n struct ExecutionVars {\n bool success;\n address targetedYieldSource;\n uint256 outAmount;\n ISuperHook hookContract;\n Execution[] executions;\n }\n\n struct FulfillRedeemVars {\n uint256 totalRequestedShares;\n uint256 totalNetAssetsOut;\n uint256 currentPPS;\n uint256 strategyBalance;\n }\n\n /*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n enum Operation {\n RedeemRequest,\n CancelRedeemRequest,\n ClaimCancelRedeem,\n ClaimRedeem\n }\n\n /// @notice Action types for yield source management\n enum YieldSourceAction {\n Add, // 0: Add a new yield source\n UpdateOracle, // 1: Update an existing yield source's oracle\n Remove // 2: Remove a yield source\n }\n\n /// @notice Action types for PPS expiration threshold management\n enum PPSExpirationAction {\n Propose, // 0: Propose a new PPS expiration threshold\n Execute, // 1: Execute the proposed threshold update\n Cancel // 2: Cancel the pending threshold proposal\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the strategy with required parameters\n /// @param vaultAddress Address of the associated SuperVault\n /// @param feeConfigData Fee configuration\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external;\n\n /// @notice Execute a 4626 deposit by processing assets.\n /// @param controller The controller address\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @return sharesNet The amount of net shares to mint\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet);\n\n /// @notice Execute a 4626 mint by processing shares.\n /// @param controller The controller address\n /// @param sharesNet The amount of shares to mint\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @param assetsNet The amount of net assets that strategy will receive\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external;\n\n /// @notice Quotes the amount of assets that will be received for a given amount of shares.\n /// @param shares The amount of shares to mint\n /// @return assetsGross The amount of gross assets that will be received\n /// @return assetsNet The amount of net assets that will be received\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet);\n\n /// @notice Execute async redeem requests (redeem, cancel, claim).\n /// @param op The operation type (RedeemRequest, CancelRedeem, ClaimRedeem)\n /// @param controller The controller address\n /// @param receiver The receiver address\n /// @param amount The amount of assets or shares\n function handleOperations7540(Operation op, address controller, address receiver, uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Execute hooks for general strategy management (rebalancing, etc.).\n /// @param args Execution arguments containing hooks, calldata, proofs, expectations.\n function executeHooks(ExecuteArgs calldata args) external payable;\n\n /// @notice Fulfills pending cancel redeem requests by making shares claimable\n /// @dev Processes all controllers with pending cancellation flags\n /// @dev Can only be called by authorized managers\n /// @param controllers Array of controller addresses with pending cancel requests\n function fulfillCancelRedeemRequests(address[] memory controllers) external;\n\n /// @notice Fulfills pending redeem requests with exact total assets per controller (pre-fee).\n /// @dev PRE: Off-chain sort/unique controllers. Call executeHooks(sum(totalAssetsOut)) first.\n /// @dev Social: totalAssetsOut[i] = theoreticalGross[i] (full). Selective: totalAssetsOut[i] < theoreticalGross[i].\n /// @dev NOTE: totalAssetsOut includes fees - actual net amount received is calculated internally after fee\n /// deduction. @param controllers Ordered/unique controllers with pending requests.\n /// @param totalAssetsOut Total PRE-FEE assets available for each controller[i] (from executeHooks).\n function fulfillRedeemRequests(address[] calldata controllers, uint256[] calldata totalAssetsOut) external;\n\n /// @notice Skim performance fees based on per-share High Water Mark (PPS-based)\n /// @dev Can be called by any manager when vault PPS has grown above HWM PPS\n /// @dev Uses PPS growth to calculate profit: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev HWM is only updated during this function, not during deposits/redemptions\n function skimPerformanceFee() external;\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Manage a single yield source: add, update oracle, or remove\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle (used for adding/updating, ignored for removal)\n /// @param actionType Type of action (see YieldSourceAction enum)\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external;\n\n /// @notice Batch manage multiple yield sources in a single transaction\n /// @param sources Array of yield source addresses\n /// @param oracles Array of oracle addresses (used for adding/updating, ignored for removal)\n /// @param actionTypes Array of action types (see YieldSourceAction enum)\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external;\n\n /// @notice Change the fee recipient when the primary manager is changed\n /// @param newRecipient New fee recipient\n function changeFeeRecipient(address newRecipient) external;\n\n /// @notice Propose or execute a hook root update\n /// @notice Propose changes to vault-specific fee configuration\n /// @param performanceFeeBps New performance fee in basis points\n /// @param managementFeeBps New management fee in basis points\n /// @param recipient New fee recipient\n /// @dev IMPORTANT: Before executing the proposed update (via executeVaultFeeConfigUpdate),\n /// manager should call skimPerformanceFee() to collect performance fees on existing profits\n /// under the current fee structure to avoid losing profit or incorrect fee calculations.\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external;\n\n /// @notice Execute the proposed vault fee configuration update after timelock\n /// @dev IMPORTANT: Manager should call skimPerformanceFee() before executing this update\n /// to collect performance fees on existing profits under the current fee structure.\n /// Otherwise, profit earned under the old fee percentage will be lost or incorrectly calculated.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// to avoid incorrect fee calculations with the new fee structure.\n function executeVaultFeeConfigUpdate() external;\n\n /// @notice Reset the high-water mark PPS to the current PPS\n /// @dev This function is only callable by Aggregator\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// @param newHwmPps The new high-water mark PPS value\n function resetHighWaterMark(uint256 newHwmPps) external;\n\n /// @notice Manage PPS expiry threshold\n /// @param action Type of action (see PPSExpirationAction enum)\n /// @param ppsExpiration The new PPS expiry threshold\n function managePPSExpiration(PPSExpirationAction action, uint256 ppsExpiration) external;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set the slippage tolerance for all future redeem request fulfillments, until reset using this function\n /// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)\n function setRedeemSlippage(uint16 slippageBps) external;\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Get the vault info\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals);\n\n /// @notice Get the fee configurations\n function getConfigInfo() external view returns (FeeConfig memory feeConfig);\n\n /// @notice Returns the currently stored PPS value.\n function getStoredPPS() external view returns (uint256);\n\n /// @notice Get a yield source's configuration\n function getYieldSource(address source) external view returns (YieldSource memory);\n\n /// @notice Get all yield sources with their information\n /// @return Array of YieldSourceInfo structs\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory);\n\n /// @notice Get all yield source addresses\n /// @return Array of yield source addresses\n function getYieldSources() external view returns (address[] memory);\n\n /// @notice Get the count of yield sources\n /// @return Number of yield sources\n function getYieldSourcesCount() external view returns (uint256);\n\n /// @notice Check if a yield source exists\n /// @param source Address of the yield source\n /// @return True if the yield source exists\n function containsYieldSource(address source) external view returns (bool);\n\n /// @notice Get the average withdraw price for a controller\n /// @param controller The controller address\n /// @return averageWithdrawPrice The average withdraw price\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice);\n\n /// @notice Get the super vault state for a controller\n /// @param controller The controller address\n /// @return state The super vault state\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state);\n\n /// @notice Get the pending redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return pendingShares The amount of shares pending redemption\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares);\n\n /// @notice Get the pending cancellation for a redeem request for a controller\n /// @param controller The controller address\n /// @return isPending True if the redeem request is pending cancellation\n function pendingCancelRedeemRequest(address controller) external view returns (bool isPending);\n\n /// @notice Get the claimable cancel redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return claimableShares The amount of shares claimable\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares);\n\n /// @notice Get the claimable withdraw amount (assets) for a controller\n /// @param controller The controller address\n /// @return claimableAssets The amount of assets claimable\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets);\n\n /// @notice Preview exact redeem fulfillment for off-chain calculation\n /// @param controller The controller address to preview\n /// @return shares Pending redeem shares\n /// @return theoreticalAssets Theoretical assets at current PPS\n /// @return minAssets Minimum acceptable assets (slippage floor)\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets);\n\n /// @notice Batch preview exact redeem fulfillment for multiple controllers\n /// @dev Efficiently batches multiple previewExactRedeem calls to reduce RPC overhead\n /// @param controllers Array of controller addresses to preview\n /// @return totalTheoAssets Total theoretical assets across all controllers\n /// @return individualAssets Array of theoretical assets per controller\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets);\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev Returns 0 if totalSupply is 0 or currentPPS <= hwmPPS\n function vaultUnrealizedProfit() external view returns (uint256);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Strings.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SafeCast} from \"./math/SafeCast.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n using SafeCast for *;\n\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n uint8 private constant ADDRESS_LENGTH = 20;\n uint256 private constant SPECIAL_CHARS_LOOKUP =\n (1 << 0x08) | // backspace\n (1 << 0x09) | // tab\n (1 << 0x0a) | // newline\n (1 << 0x0c) | // form feed\n (1 << 0x0d) | // carriage return\n (1 << 0x22) | // double quote\n (1 << 0x5c); // backslash\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n /**\n * @dev The string being parsed contains characters that are not in scope of the given base.\n */\n error StringsInvalidChar();\n\n /**\n * @dev The string being parsed is not a properly formatted address.\n */\n error StringsInvalidAddressFormat();\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n assembly (\"memory-safe\") {\n ptr := add(add(buffer, 0x20), length)\n }\n while (true) {\n ptr--;\n assembly (\"memory-safe\") {\n mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toStringSigned(int256 value) internal pure returns (string memory) {\n return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n * representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal\n * representation, according to EIP-55.\n */\n function toChecksumHexString(address addr) internal pure returns (string memory) {\n bytes memory buffer = bytes(toHexString(addr));\n\n // hash the hex part of buffer (skip length + 2 bytes, length 40)\n uint256 hashValue;\n assembly (\"memory-safe\") {\n hashValue := shr(96, keccak256(add(buffer, 0x22), 40))\n }\n\n for (uint256 i = 41; i > 1; --i) {\n // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)\n if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {\n // case shift by xoring with 0x20\n buffer[i] ^= 0x20;\n }\n hashValue >>= 4;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `bytes` buffer to its ASCII `string` hexadecimal representation.\n */\n function toHexString(bytes memory input) internal pure returns (string memory) {\n unchecked {\n bytes memory buffer = new bytes(2 * input.length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 0; i < input.length; ++i) {\n uint8 v = uint8(input[i]);\n buffer[2 * i + 2] = HEX_DIGITS[v >> 4];\n buffer[2 * i + 3] = HEX_DIGITS[v & 0xf];\n }\n return string(buffer);\n }\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input) internal pure returns (uint256) {\n return parseUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n uint256 result = 0;\n for (uint256 i = begin; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 9) return (false, 0);\n result *= 10;\n result += chr;\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `int256`.\n *\n * Requirements:\n * - The string must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input) internal pure returns (int256) {\n return parseInt(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {\n (bool success, int256 value) = tryParseInt(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if\n * the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {\n return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);\n }\n\n uint256 private constant ABS_MIN_INT256 = 2 ** 255;\n\n /**\n * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character or if the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, int256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseIntUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseIntUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, int256 value) {\n bytes memory buffer = bytes(input);\n\n // Check presence of a negative sign.\n bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n bool positiveSign = sign == bytes1(\"+\");\n bool negativeSign = sign == bytes1(\"-\");\n uint256 offset = (positiveSign || negativeSign).toUint();\n\n (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);\n\n if (absSuccess && absValue < ABS_MIN_INT256) {\n return (true, negativeSign ? -int256(absValue) : int256(absValue));\n } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {\n return (true, type(int256).min);\n } else return (false, 0);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input) internal pure returns (uint256) {\n return parseHexUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseHexUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an\n * invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseHexUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseHexUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n // skip 0x prefix if present\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 offset = hasPrefix.toUint() * 2;\n\n uint256 result = 0;\n for (uint256 i = begin + offset; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 15) return (false, 0);\n result *= 16;\n unchecked {\n // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).\n // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.\n result += chr;\n }\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as an `address`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input) internal pure returns (address) {\n return parseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {\n (bool success, address value) = tryParseAddress(input, begin, end);\n if (!success) revert StringsInvalidAddressFormat();\n return value;\n }\n\n /**\n * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly\n * formatted address. See {parseAddress-string} requirements.\n */\n function tryParseAddress(string memory input) internal pure returns (bool success, address value) {\n return tryParseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly\n * formatted address. See {parseAddress-string-uint256-uint256} requirements.\n */\n function tryParseAddress(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, address value) {\n if (end > bytes(input).length || begin > end) return (false, address(0));\n\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 expectedLength = 40 + hasPrefix.toUint() * 2;\n\n // check that input is the correct length\n if (end - begin == expectedLength) {\n // length guarantees that this does not overflow, and value is at most type(uint160).max\n (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);\n return (s, address(uint160(v)));\n } else {\n return (false, address(0));\n }\n }\n\n function _tryParseChr(bytes1 chr) private pure returns (uint8) {\n uint8 value = uint8(chr);\n\n // Try to parse `chr`:\n // - Case 1: [0-9]\n // - Case 2: [a-f]\n // - Case 3: [A-F]\n // - otherwise not supported\n unchecked {\n if (value > 47 && value < 58) value -= 48;\n else if (value > 96 && value < 103) value -= 87;\n else if (value > 64 && value < 71) value -= 55;\n else return type(uint8).max;\n }\n\n return value;\n }\n\n /**\n * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.\n *\n * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.\n *\n * NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of\n * RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode\n * characters that are not in this range, but other tooling may provide different results.\n */\n function escapeJSON(string memory input) internal pure returns (string memory) {\n bytes memory buffer = bytes(input);\n bytes memory output = new bytes(2 * buffer.length); // worst case scenario\n uint256 outputLength = 0;\n\n for (uint256 i; i < buffer.length; ++i) {\n bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));\n if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {\n output[outputLength++] = \"\\\\\";\n if (char == 0x08) output[outputLength++] = \"b\";\n else if (char == 0x09) output[outputLength++] = \"t\";\n else if (char == 0x0a) output[outputLength++] = \"n\";\n else if (char == 0x0c) output[outputLength++] = \"f\";\n else if (char == 0x0d) output[outputLength++] = \"r\";\n else if (char == 0x5c) output[outputLength++] = \"\\\\\";\n else if (char == 0x22) {\n // solhint-disable-next-line quotes\n output[outputLength++] = '\"';\n }\n } else {\n output[outputLength++] = char;\n }\n }\n // write the actual length and deallocate unused memory\n assembly (\"memory-safe\") {\n mstore(output, outputLength)\n mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))\n }\n\n return string(output);\n }\n\n /**\n * @dev Reads a bytes32 from a bytes array without bounds checking.\n *\n * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the\n * assembly block as such would prevent some optimizations.\n */\n function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {\n // This is not memory safe in the general case, but all calls to this private function are within bounds.\n assembly (\"memory-safe\") {\n value := mload(add(add(buffer, 0x20), offset))\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Arrays.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n using SlotDerivation for bytes32;\n using StorageSlot for bytes32;\n\n /**\n * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n uint256[] memory array,\n function(uint256, uint256) pure returns (bool) comp\n ) internal pure returns (uint256[] memory) {\n _quickSort(_begin(array), _end(array), comp);\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n */\n function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n sort(array, Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of address (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n address[] memory array,\n function(address, address) pure returns (bool) comp\n ) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of address in increasing order.\n */\n function sort(address[] memory array) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n bytes32[] memory array,\n function(bytes32, bytes32) pure returns (bool) comp\n ) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n */\n function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n * at end (exclusive). Sorting follows the `comp` comparator.\n *\n * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n *\n * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n * be used only if the limits are within a memory array.\n */\n function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n unchecked {\n if (end - begin < 0x40) return;\n\n // Use first element as pivot\n uint256 pivot = _mload(begin);\n // Position where the pivot should be at the end of the loop\n uint256 pos = begin;\n\n for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n if (comp(_mload(it), pivot)) {\n // If the value stored at the iterator's position comes before the pivot, we increment the\n // position of the pivot and move the value there.\n pos += 0x20;\n _swap(pos, it);\n }\n }\n\n _swap(begin, pos); // Swap pivot into place\n _quickSort(begin, pos, comp); // Sort the left side of the pivot\n _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first element of `array`.\n */\n function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := add(array, 0x20)\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n * that comes just after the last element of the array.\n */\n function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n unchecked {\n return _begin(array) + array.length * 0x20;\n }\n }\n\n /**\n * @dev Load memory word (as a uint256) at location `ptr`.\n */\n function _mload(uint256 ptr) private pure returns (uint256 value) {\n assembly {\n value := mload(ptr)\n }\n }\n\n /**\n * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n */\n function _swap(uint256 ptr1, uint256 ptr2) private pure {\n assembly {\n let value1 := mload(ptr1)\n let value2 := mload(ptr2)\n mstore(ptr1, value2)\n mstore(ptr2, value1)\n }\n }\n\n /// @dev Helper: low level cast address memory array to uint256 memory array\n function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast address comp function to uint256 comp function\n function _castToUint256Comp(\n function(address, address) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n function _castToUint256Comp(\n function(bytes32, bytes32) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /**\n * @dev Searches a sorted `array` and returns the first index that contains\n * a value greater or equal to `element`. If no such index exists (i.e. all\n * values in the array are strictly less than `element`), the array length is\n * returned. Time complexity O(log n).\n *\n * NOTE: The `array` is expected to be sorted in ascending order, and to\n * contain no repeated elements.\n *\n * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n * support for repeated elements in the array. The {lowerBound} function should\n * be used instead.\n */\n function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n return low - 1;\n } else {\n return low;\n }\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value greater or equal than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n */\n function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value strictly greater than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n */\n function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {lowerBound}, but with an array in memory.\n */\n function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {upperBound}, but with an array in memory.\n */\n function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getAddressSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytes32Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getUint256Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytesSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getStringSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(address[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(string[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"lib/v2-core/src/interfaces/ISuperHook.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { Execution } from \"modulekit/accounts/erc7579/lib/ExecutionLib.sol\";\n\n/**\n * @title SuperHook System\n * @author Superform Labs\n * @notice The hook system provides a modular and composable way to execute operations on assets\n * @dev The hook system architecture consists of several interfaces that work together:\n * - ISuperHook: The base interface all hooks implement, with lifecycle methods\n * - ISuperHookResult: Provides execution results and output information\n * - Specialized interfaces (ISuperHookOutflow, ISuperHookLoans, etc.) for specific behaviors\n *\n * Hooks are executed in sequence, where each hook can access the results from previous hooks.\n * The three main types of hooks are:\n * - NONACCOUNTING: Utility hooks that don't update the accounting system\n * - INFLOW: Hooks that process deposits or additions to positions\n * - OUTFLOW: Hooks that process withdrawals or reductions to positions\n */\ninterface ISuperLockableHook {\n /// @notice The vault bank address used to lock SuperPositions\n /// @dev Only relevant for cross-chain operations where positions are locked\n /// @return The vault bank address, or address(0) if not applicable\n function vaultBank() external view returns (address);\n\n /// @notice The destination chain ID for cross-chain operations\n /// @dev Used to identify the target chain for cross-chain position transfers\n /// @return The destination chain ID, or 0 if not a cross-chain operation\n function dstChainId() external view returns (uint256);\n}\n\ninterface ISuperHookSetter {\n /// @notice Sets the output amount for the hook\n /// @dev Used for updating `outAmount` when fees were deducted\n /// @param outAmount The amount of tokens processed by the hook\n /// @param caller The caller address for context identification\n function setOutAmount(uint256 outAmount, address caller) external;\n}\n/// @title ISuperHookInspector\n/// @author Superform Labs\n/// @notice Interface for the SuperHookInspector contract that manages hook inspection\n\ninterface ISuperHookInspector {\n /// @notice Inspect the hook\n /// @param data The hook data to inspect\n /// @return argsEncoded The arguments of the hook encoded\n function inspect(bytes calldata data) external view returns (bytes memory argsEncoded);\n}\n\n/// @title ISuperHookResult\n/// @author Superform Labs\n/// @notice Interface that exposes the result of a hook execution\n/// @dev All hooks must implement this interface to provide standardized access to execution results.\n/// These results are used by subsequent hooks in the execution chain and by the executor.\ninterface ISuperHookResult {\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The type of hook\n /// @dev Used to determine how accounting should process this hook's results\n /// @return The hook type (NONACCOUNTING, INFLOW, or OUTFLOW)\n function hookType() external view returns (ISuperHook.HookType);\n\n /// @notice The SuperPosition (SP) token associated with this hook\n /// @dev For vault hooks, this would be the tokenized position representing shares\n /// @return The address of the SP token, or address(0) if not applicable\n function spToken() external view returns (address);\n\n /// @notice The underlying asset token being processed\n /// @dev For most hooks, this is the actual token being deposited or withdrawn\n /// @return The address of the asset token, or address(0) for native assets\n function asset() external view returns (address);\n\n /// @notice The amount of tokens processed by the hook in a given caller context, subject to fees after update\n /// @dev This is the primary output value used by subsequent hooks\n /// @param caller The caller address for context identification\n /// @return The amount of tokens (assets or shares) processed\n function getOutAmount(address caller) external view returns (uint256);\n}\n\n/// @title ISuperHookContextAware\n/// @author Superform Labs\n/// @notice Interface for hooks that can use previous hook results in their execution\n/// @dev Enables contextual awareness and data flow between hooks in a chain\ninterface ISuperHookContextAware {\n /// @notice Determines if this hook should use the amount from the previous hook\n /// @dev Used to create hook chains where output from one hook becomes input to the next\n /// @param data The hook-specific data containing configuration\n /// @return True if the hook should use the previous hook's output amount\n function decodeUsePrevHookAmount(bytes memory data) external pure returns (bool);\n}\n\n/// @title ISuperHookInflowOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that handle both inflows and outflows\n/// @dev Provides standardized amount extraction for both deposit and withdrawal operations\ninterface ISuperHookInflowOutflow {\n /// @notice Extracts the amount from the hook's calldata\n /// @dev Used to determine the quantity of assets or shares being processed\n /// @param data The hook-specific calldata containing the amount\n /// @return The amount of tokens to process\n function decodeAmount(bytes memory data) external pure returns (uint256);\n}\n\n/// @title ISuperHookOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that specifically handle outflows (withdrawals)\n/// @dev Provides additional functionality needed only for outflow operations\ninterface ISuperHookOutflow {\n /// @notice Replace the amount in the calldata\n /// @param data The data to replace the amount in\n /// @param amount The amount to replace\n /// @return data The data with the replaced amount\n function replaceCalldataAmount(bytes memory data, uint256 amount) external pure returns (bytes memory);\n}\n\n/// @title ISuperHookResultOutflow\n/// @author Superform Labs\n/// @notice Extended result interface for outflow hook operations\n/// @dev Extends the base result interface with outflow-specific information\ninterface ISuperHookResultOutflow is ISuperHookResult {\n /// @notice The amount of shares consumed during outflow processing\n /// @dev Used for cost basis calculation in the accounting system\n /// @return The amount of shares consumed from the user's position\n function usedShares() external view returns (uint256);\n}\n\n/// @title ISuperHookLoans\n/// @author Superform Labs\n/// @notice Interface for hooks that interact with lending protocols\n/// @dev Extends context awareness to enable loan operations within hook chains\ninterface ISuperHookLoans is ISuperHookContextAware {\n /// @notice Gets the address of the token being borrowed\n /// @dev Used to identify which asset is being borrowed from the lending protocol\n /// @param data The hook-specific data containing loan information\n /// @return The address of the borrowed token\n function getLoanTokenAddress(bytes memory data) external pure returns (address);\n\n /// @notice Gets the address of the token used as collateral\n /// @dev Used to identify which asset is being used to secure the loan\n /// @param data The hook-specific data containing collateral information\n /// @return The address of the collateral token\n function getCollateralTokenAddress(bytes memory data) external view returns (address);\n\n /// @notice Gets the current loan token balance for an account\n /// @dev Used to track outstanding loan amounts\n /// @param account The account to check the loan balance for\n /// @param data The hook-specific data containing loan parameters\n /// @return The amount of tokens currently borrowed\n function getLoanTokenBalance(address account, bytes memory data) external view returns (uint256);\n\n /// @notice Gets the current collateral token balance for an account\n /// @dev Used to track collateral positions\n /// @param account The account to check the collateral balance for\n /// @param data The hook-specific data containing collateral parameters\n /// @return The amount of tokens currently used as collateral\n function getCollateralTokenBalance(address account, bytes memory data) external view returns (uint256);\n}\n\n/// @title ISuperHookAsyncCancelations\n/// @author Superform Labs\n/// @notice Interface for hooks that can cancel asynchronous operations\n/// @dev Used to handle cancellation of pending operations that haven't completed\ninterface ISuperHookAsyncCancelations {\n /// @notice Types of cancellations that can be performed\n /// @dev Distinguishes between different operation types that can be canceled\n enum CancelationType {\n NONE, // Not a cancelation hook\n INFLOW, // Cancels a pending deposit operation\n OUTFLOW // Cancels a pending withdrawal operation\n\n }\n\n /// @notice Identifies the type of async operation this hook can cancel\n /// @dev Used to verify the hook is appropriate for the operation being canceled\n /// @return asyncType The type of cancellation this hook performs\n function isAsyncCancelHook() external pure returns (CancelationType asyncType);\n}\n\n/// @title ISuperHook\n/// @author Superform Labs\n/// @notice The core hook interface that all hooks must implement\n/// @dev Defines the lifecycle methods and execution flow for the hook system\n/// Hooks are executed in sequence with results passed between them\ninterface ISuperHook {\n /*//////////////////////////////////////////////////////////////\n\n ENUMS\n //////////////////////////////////////////////////////////////*/\n /// @notice Defines the possible types of hooks in the system\n /// @dev Used to determine how the hook affects accounting and what operations it performs\n enum HookType {\n NONACCOUNTING, // Hook doesn't affect accounting (e.g., a swap or bridge)\n INFLOW, // Hook processes deposits or positions being added\n OUTFLOW // Hook processes withdrawals or positions being removed\n\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Builds the execution array for the hook operation\n /// @dev This is the core method where hooks define their on-chain interactions\n /// The returned executions are a sequence of contract calls to perform\n /// No state changes should occur in this method\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform executions for (usually an ERC7579 account)\n /// @param data The hook-specific parameters and configuration data\n /// @return executions Array of Execution structs defining calls to make\n function build(\n address prevHook,\n address account,\n bytes calldata data\n )\n external\n view\n returns (Execution[] memory executions);\n\n /*//////////////////////////////////////////////////////////////\n PUBLIC METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Prepares the hook for execution\n /// @dev Called before the main execution, used to validate inputs and set execution context\n /// This method may perform state changes to set up the hook's execution state\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform operations for\n /// @param data The hook-specific parameters and configuration data\n function preExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Finalizes the hook after execution\n /// @dev Called after the main execution, used to update hook state and calculate results\n /// Sets output values (outAmount, usedShares, etc.) for subsequent hooks\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account operations were performed for\n /// @param data The hook-specific parameters and configuration data\n function postExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Returns the specific subtype identification for this hook\n /// @dev Used to categorize hooks beyond the basic HookType\n /// For example, a hook might be of type INFLOW but subtype VAULT_DEPOSIT\n /// @return A bytes32 identifier for the specific hook functionality\n function subtype() external view returns (bytes32);\n\n /// @notice Resets hook mutexes\n /// @param caller The caller address for context identification\n function resetExecutionState(address caller) external;\n\n /// @notice Sets the caller address that initiated the execution\n /// @dev Used for security validation between preExecute and postExecute calls\n /// @param caller The caller address for context identification\n function setExecutionContext(address caller) external;\n\n /// @notice Returns the execution nonce for the current execution context\n /// @dev Used to ensure unique execution contexts and prevent replay attacks\n /// @return The execution nonce\n function executionNonce() external view returns (uint256);\n\n /// @notice Returns the last caller registered by `setExecutionContext`\n /// @return The last caller address\n function lastCaller() external view returns (address);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));\n }\n }\n\n /**\n * @dev Returns the largest of two signed numbers.\n */\n function max(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two signed numbers.\n */\n function min(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two signed numbers without overflow.\n * The result is rounded towards zero.\n */\n function average(int256 a, int256 b) internal pure returns (int256) {\n // Formula from the book \"Hacker's Delight\"\n int256 x = (a & b) + ((a ^ b) >> 1);\n return x + (int256(uint256(x) >> 255) & (a ^ b));\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // Formula from the \"Bit Twiddling Hacks\" by Sean Eron Anderson.\n // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,\n // taking advantage of the most significant (or \"sign\" bit) in two's complement representation.\n // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,\n // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).\n int256 mask = n >> 255;\n\n // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.\n return uint256((n + mask) ^ mask);\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Comparators.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n function lt(uint256 a, uint256 b) internal pure returns (bool) {\n return a < b;\n }\n\n function gt(uint256 a, uint256 b) internal pure returns (bool) {\n return a > b;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using StorageSlot for bytes32;\n * using SlotDerivation for bytes32;\n *\n * // Declare a namespace\n * string private constant _NAMESPACE = \"\"; // eg. OpenZeppelin.Slot\n *\n * function setValueInNamespace(uint256 key, address newValue) internal {\n * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n * }\n *\n * function getValueInNamespace(uint256 key) internal view returns (address) {\n * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n /**\n * @dev Derive an ERC-7201 slot from a string (namespace).\n */\n function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n assembly (\"memory-safe\") {\n mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n slot := and(keccak256(0x00, 0x20), not(0xff))\n }\n }\n\n /**\n * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n */\n function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n unchecked {\n return bytes32(uint256(slot) + pos);\n }\n }\n\n /**\n * @dev Derive the location of the first element in an array from the slot where the length is stored.\n */\n function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, slot)\n result := keccak256(0x00, 0x20)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, and(key, shr(96, not(0))))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, iszero(iszero(key)))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n// Types\nimport { Execution } from \"../../common/interfaces/IERC7579Account.sol\";\n\n/**\n * Helper Library for decoding Execution calldata\n * malloc for memory allocation is bad for gas. use this assembly instead\n */\nlibrary ExecutionLib {\n error ERC7579DecodingError();\n\n /**\n * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.\n * @dev code is copied from solady's LibERC7579.sol\n * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146\n * Credits to Vectorized and the Solady Team\n */\n function decodeBatch(bytes calldata executionCalldata)\n internal\n pure\n returns (Execution[] calldata executionBatch)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let u := calldataload(executionCalldata.offset)\n let s := add(executionCalldata.offset, u)\n let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)\n executionBatch.offset := add(s, 0x20)\n executionBatch.length := calldataload(s)\n if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if executionBatch.length {\n // Perform bounds checks on the decoded `executionBatch`.\n // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.\n for { let i := executionBatch.length } 1 { } {\n i := sub(i, 1)\n let p := calldataload(add(executionBatch.offset, shl(5, i)))\n let c := add(executionBatch.offset, p)\n let q := calldataload(add(c, 0x40))\n let o := add(c, q)\n // forgefmt: disable-next-item\n if or(shr(64, or(calldataload(o), or(p, q))),\n or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if iszero(i) { break }\n }\n }\n }\n }\n\n function encodeBatch(Execution[] memory executions)\n internal\n pure\n returns (bytes memory callData)\n {\n callData = abi.encode(executions);\n }\n\n function decodeSingle(bytes calldata executionCalldata)\n internal\n pure\n returns (address target, uint256 value, bytes calldata callData)\n {\n target = address(bytes20(executionCalldata[0:20]));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n function encodeSingle(\n address target,\n uint256 value,\n bytes memory callData\n )\n internal\n pure\n returns (bytes memory userOpCalldata)\n {\n userOpCalldata = abi.encodePacked(target, value, callData);\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n/* solhint-disable no-unused-import */\n\n// Types\nimport { CallType, ExecType, ModeCode } from \"../lib/ModeLib.sol\";\n\n// Structs\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\ninterface IERC7579Account {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by ERC-4337 EntryPoint.sol\n * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @dev Ensure adequate authorization control: i.e. onlyExecutorModule\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function executeFromExecutor(\n ModeCode mode,\n bytes calldata executionCalldata\n )\n external\n payable\n returns (bytes[] memory returnData);\n\n /**\n * @dev ERC-1271 isValidSignature\n * This function is intended to be used to validate a smart account signature\n * and may forward the call to a validator module\n *\n * @param hash The hash of the data that is signed\n * @param data The data that is signed\n */\n function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);\n\n /**\n * @dev installs a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be required on the module during `onInstall`\n * initialization.\n */\n function installModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata initData\n )\n external\n payable;\n\n /**\n * @dev uninstalls a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be required on the module during `onUninstall`\n * de-initialization.\n */\n function uninstallModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata deInitData\n )\n external\n payable;\n\n /**\n * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)\n * @param encodedMode the encoded mode\n */\n function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);\n\n /**\n * Function to check if the account supports installation of a certain module type Id\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n\n /**\n * Function to check if the account has a certain module installed\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * Note: keep in mind that some contracts can be multiple module types at the same time. It\n * thus may be necessary to query multiple module types\n * @param module the module address\n * @param additionalContext additional context data that the smart account may interpret to\n * identifiy conditions under which the module is installed.\n * usually this is not necessary, but for some special hooks that\n * are stored in mappings, this param might be needed\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n )\n external\n view\n returns (bool);\n\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n * the accountId should be structured like so:\n * \"vendorname.accountname.semver\"\n */\n function accountId() external view returns (string memory accountImplementationId);\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/lib/ModeLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title ModeLib\n * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat)\n * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode\n * encoding is used.\n * Function Signature of execute function:\n * function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and\n * context.\n * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that\n * implement\n * more complex execution modes may use the entire bytes32.\n *\n * |--------------------------------------------------------------------|\n * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload |\n * |--------------------------------------------------------------------|\n * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes |\n * |--------------------------------------------------------------------|\n *\n * CALLTYPE: 1 byte\n * CallType is used to determine how the executeCalldata paramter of the execute function has to be\n * decoded.\n * It can be either single, batch or delegatecall. In the future different calls could be added.\n * CALLTYPE can be used by a validation module to determine how to decode .\n *\n * EXECTYPE: 1 byte\n * ExecType is used to determine how the account should handle the execution.\n * It can indicate if the execution should revert on failure or continue execution.\n * In the future more execution modes may be added.\n * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in\n * a batch fails, the entire batch is reverted\n *\n * UNUSED: 4 bytes\n * Unused bytes are reserved for future use.\n *\n * ModeSelector: bytes4\n * The \"optional\" mode selector can be used by account vendors, to implement custom behavior in\n * their accounts.\n * the way a ModeSelector is to be calculated is bytes4(keccak256(\"vendorname.featurename\"))\n * this is to prevent collisions between different vendors, while allowing innovation and the\n * development of new features without coordination between ERC-7579 implementing accounts\n *\n * ModePayload: 22 bytes\n * Mode payload is used to pass additional data to the smart account execution, this may be\n * interpreted depending on the ModeSelector\n *\n * ExecutionCallData: n bytes\n * single, delegatecall or batch exec abi.encoded as bytes\n */\n\n// Custom type for improved developer experience\ntype ModeCode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ModeSelector is bytes4;\n\ntype ModePayload is bytes22;\n\n// Default CallType\nCallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n// Batched CallType\nCallType constant CALLTYPE_BATCH = CallType.wrap(0x01);\nCallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);\n// @dev Implementing delegatecall is OPTIONAL!\n// implement delegatecall with extreme care.\nCallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n// @dev default behavior is to revert on failure\n// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure\n// Since this is value 0x00, no additional encoding is required for simple accounts\nExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n// @dev account may elect to change execution behavior. For example \"try exec\" / \"allow fail\"\nExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\nModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));\n// Example declaration of a custom mode selector\nModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256(\"default.mode.offset\")));\n\n/**\n * @dev ModeLib is a helper library to encode/decode ModeCodes\n */\nlibrary ModeLib {\n function decode(ModeCode mode)\n internal\n pure\n returns (\n CallType _calltype,\n ExecType _execType,\n ModeSelector _modeSelector,\n ModePayload _modePayload\n )\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _calltype := mode\n _execType := shl(8, mode)\n _modeSelector := shl(48, mode)\n _modePayload := shl(80, mode)\n }\n }\n\n function encode(\n CallType callType,\n ExecType execType,\n ModeSelector mode,\n ModePayload payload\n )\n internal\n pure\n returns (ModeCode)\n {\n return ModeCode.wrap(\n bytes32(\n abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)\n )\n );\n }\n\n function encodeSimpleBatch() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function encodeSimpleSingle() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function getCallType(ModeCode mode) internal pure returns (CallType calltype) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n calltype := mode\n }\n }\n}\n\nusing { eqModeSelector as == } for ModeSelector global;\nusing { eqCallType as == } for CallType global;\nusing { neqCallType as != } for CallType global;\nusing { eqExecType as == } for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction neqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/FixedPriceOracle.standard-json-input.json b/script/locked-bytecode-dev/FixedPriceOracle.standard-json-input.json new file mode 100644 index 000000000..1f65da9eb --- /dev/null +++ b/script/locked-bytecode-dev/FixedPriceOracle.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/oracles/FixedPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.30;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/// @title FixedPriceOracle\n/// @notice A Chainlink-compatible oracle that returns a fixed price set by the admin\n/// @dev Used as a temporary UP/USD oracle. Always returns block.timestamp for updatedAt\n/// to avoid staleness issues with oracle consumers.\ncontract FixedPriceOracle is Ownable {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Thrown when trying to set a zero price\n error INVALID_PRICE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Emitted when the fixed price is updated\n /// @param oldPrice The previous price\n /// @param newPrice The new price\n event PriceUpdated(int256 oldPrice, int256 newPrice);\n\n /// @notice Emitted when decimals are updated\n /// @param oldDecimals The previous decimals\n /// @param newDecimals The new decimals\n event DecimalsUpdated(uint8 oldDecimals, uint8 newDecimals);\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The fixed price to return\n int256 private _answer;\n\n /// @notice The number of decimals for the price\n uint8 private _decimals;\n\n /// @notice Description of the oracle\n string private constant DESCRIPTION = \"Fixed Price Oracle\";\n\n /// @notice Version of the oracle\n uint256 private constant VERSION = 1;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the oracle with a fixed price and decimals\n /// @param initialPrice The initial fixed price (must be > 0)\n /// @param decimals_ The number of decimals (typically 8 for USD pairs)\n /// @param owner_ The owner who can update the price\n constructor(int256 initialPrice, uint8 decimals_, address owner_) Ownable(owner_) {\n if (initialPrice <= 0) revert INVALID_PRICE();\n _answer = initialPrice;\n _decimals = decimals_;\n }\n\n /*//////////////////////////////////////////////////////////////\n ADMIN FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Sets the fixed price\n /// @param newPrice The new price to set (must be > 0)\n function setPrice(int256 newPrice) external onlyOwner {\n if (newPrice <= 0) revert INVALID_PRICE();\n int256 oldPrice = _answer;\n _answer = newPrice;\n emit PriceUpdated(oldPrice, newPrice);\n }\n\n /// @notice Sets the decimals\n /// @param newDecimals The new decimals value\n function setDecimals(uint8 newDecimals) external onlyOwner {\n uint8 oldDecimals = _decimals;\n _decimals = newDecimals;\n emit DecimalsUpdated(oldDecimals, newDecimals);\n }\n\n /*//////////////////////////////////////////////////////////////\n CHAINLINK INTERFACE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the number of decimals\n /// @return The decimals value\n function decimals() external view returns (uint8) {\n return _decimals;\n }\n\n /// @notice Returns the description of this oracle\n /// @return The description string\n function description() external pure returns (string memory) {\n return DESCRIPTION;\n }\n\n /// @notice Returns the version of this oracle\n /// @return The version number\n function version() external pure returns (uint256) {\n return VERSION;\n }\n\n /// @notice Returns data for a specific round\n /// @dev Always returns the current fixed price with current timestamp\n /// @param _roundId The round ID (ignored, always returns current data)\n /// @return roundId The round ID (always 1)\n /// @return answer The fixed price\n /// @return startedAt The current block timestamp\n /// @return updatedAt The current block timestamp (prevents staleness issues)\n /// @return answeredInRound The round ID (always 1)\n function getRoundData(uint80 _roundId)\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)\n {\n return (_roundId, _answer, block.timestamp, block.timestamp, _roundId);\n }\n\n /// @notice Returns the latest round data\n /// @dev Always returns block.timestamp for updatedAt to avoid staleness issues\n /// @return roundId The round ID (always 1)\n /// @return answer The fixed price\n /// @return startedAt The current block timestamp\n /// @return updatedAt The current block timestamp (prevents staleness issues)\n /// @return answeredInRound The round ID (always 1)\n function latestRoundData()\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)\n {\n return (1, _answer, block.timestamp, block.timestamp, 1);\n }\n\n /// @notice Returns the latest answer\n /// @return The fixed price as uint256\n function latestAnswer() external view returns (uint256) {\n // Safe cast: _answer is always > 0 (enforced in constructor and setPrice)\n // forge-lint: disable-next-line(unsafe-typecast)\n return uint256(_answer);\n }\n\n /// @notice Returns the timestamp for a round\n /// @dev Always returns current block timestamp\n /// @param _roundId The round ID (ignored)\n /// @return The current block timestamp\n function getTimestamp(uint256 _roundId) external view returns (uint256) {\n // Silence unused parameter warning\n _roundId;\n return block.timestamp;\n }\n\n /// @notice Returns the current phase ID\n /// @return Always returns 1\n function phaseId() external pure returns (uint16) {\n return 1;\n }\n\n /// @notice Returns the aggregator for a phase\n /// @dev Returns this contract's address for phase 1, zero otherwise\n /// @param _phaseId The phase ID\n /// @return The aggregator address\n function phaseAggregators(uint16 _phaseId) external view returns (address) {\n if (_phaseId == 1) return address(this);\n return address(0);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperBank.standard-json-input.json b/script/locked-bytecode-dev/SuperBank.standard-json-input.json new file mode 100644 index 000000000..5859d34fb --- /dev/null +++ b/script/locked-bytecode-dev/SuperBank.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperBank.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n// Superform\nimport { ISuperBank } from \"./interfaces/ISuperBank.sol\";\nimport { ISuperGovernor, FeeType } from \"./interfaces/ISuperGovernor.sol\";\nimport { Bank } from \"./Bank.sol\";\n\n/// @title SuperBank\n/// @notice Compounds protocol revenue into UP and distributes it to sUP and treasury.\ncontract SuperBank is ISuperBank, Bank {\n using SafeERC20 for IERC20;\n using Math for uint256;\n\n uint256 private constant BPS_PRECISION = 10_000;\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n constructor(address superGovernor_) {\n if (superGovernor_ == address(0)) revert INVALID_ADDRESS();\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n }\n\n modifier onlyBankManager() {\n _onlyBankManager();\n _;\n }\n\n function _onlyBankManager() internal view {\n if (!IAccessControl(address(SUPER_GOVERNOR)).hasRole(SUPER_GOVERNOR.BANK_MANAGER_ROLE(), msg.sender)) {\n revert INVALID_BANK_MANAGER();\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n // Receive function to accept direct ETH transfers if needed for hooks/executions\n receive() external payable { }\n\n /// @inheritdoc ISuperBank\n function distribute(uint256 upAmount) external onlyBankManager {\n if (upAmount == 0) revert ZERO_AMOUNT();\n\n // Cache SUPER_GOVERNOR reference to reduce external calls\n ISuperGovernor gov = SUPER_GOVERNOR;\n\n // Get UP token address from SuperGovernor\n address upToken = gov.getAddress(gov.UP());\n\n // Validate early before fetching more addresses\n if (IERC20(upToken).balanceOf(address(this)) < upAmount) revert INVALID_UP_AMOUNT_TO_DISTRIBUTE();\n\n // Get revenue share percentage from SuperGovernor\n uint256 revenueShare = gov.getFee(FeeType.REVENUE_SHARE);\n\n // Validate revenue share is within bounds\n if (revenueShare > BPS_PRECISION) revert INVALID_REVENUE_SHARE();\n\n // Get remaining addresses after validation\n address supStrategyVault = gov.getAddress(gov.SUP_STRATEGY());\n address treasury = gov.getAddress(gov.TREASURY());\n\n // Calculate amounts for sUP and Treasury\n uint256 supAmount = upAmount.mulDiv(revenueShare, BPS_PRECISION, Math.Rounding.Ceil);\n uint256 treasuryAmount = upAmount - supAmount;\n\n // Direct usage instead of intermediate IERC20 variable\n if (supAmount > 0) {\n IERC20(upToken).safeTransfer(supStrategyVault, supAmount);\n }\n\n if (treasuryAmount > 0) {\n IERC20(upToken).safeTransfer(treasury, treasuryAmount);\n }\n\n emit RevenueDistributed(upToken, supStrategyVault, treasury, supAmount, treasuryAmount);\n }\n\n /// @inheritdoc ISuperBank\n function executeHooks(ISuperBank.HookExecutionData calldata executionData) external payable onlyBankManager {\n _executeHooks(executionData);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n function _getMerkleRootForHook(address hookAddress) internal view override returns (bytes32) {\n return SUPER_GOVERNOR.getSuperBankHookMerkleRoot(hookAddress);\n }\n\n function _isHookRegistered(address hookAddress) internal view override returns (bool) {\n return SUPER_GOVERNOR.isHookRegistered(hookAddress);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"src/interfaces/ISuperBank.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IHookExecutionData } from \"./IHookExecutionData.sol\";\n\n/// @title ISuperBank\n/// @author Superform Labs\n/// @notice Interface for SuperBank, which compounds protocol revenue into sUP by executing registered hooks.\ninterface ISuperBank is IHookExecutionData {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Error thrown when an invalid address is provided.\n error INVALID_ADDRESS();\n /// @notice Error thrown when a transfer fails.\n error TRANSFER_FAILED();\n /// @notice Error thrown when an invalid UP amount is provided.\n error INVALID_UP_AMOUNT_TO_DISTRIBUTE();\n /// @notice Error thrown when an invalid bank manager is provided.\n error INVALID_BANK_MANAGER();\n /// @notice Error thrown when revenue share exceeds maximum allowed (BPS_PRECISION).\n error INVALID_REVENUE_SHARE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when revenue is distributed to sUP and Treasury.\n /// @param upToken The address of the UP token.\n /// @param supStrategyVault The address of the sUP strategy.\n /// @param treasury The address of the Treasury.\n /// @param supAmount The amount sent to sUP.\n /// @param treasuryAmount The amount sent to Treasury.\n event RevenueDistributed(\n address indexed upToken,\n address indexed supStrategyVault,\n address indexed treasury,\n uint256 supAmount,\n uint256 treasuryAmount\n );\n\n /*//////////////////////////////////////////////////////////////\n FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Executes a batch of hooks, verifying each with a Merkle proof.\n /// @dev Each hook is verified against a Merkle root from SuperGovernor.\n /// @dev Hooks must implement the ISuperHook interface (preExecute, build, postExecute).\n /// @param executionData HookExecutionData struct containing arrays of hooks, data, and Merkle proofs.\n function executeHooks(HookExecutionData calldata executionData) external payable;\n\n /// @notice Distributes UP tokens based on governance-agreed revenue share.\n /// @dev Transfers X% (REVENUE_SHARE) of UP tokens to sUP, and the remainder to Superform Treasury.\n /// @param upAmount The amount of UP tokens to distribute.\n function distribute(uint256 upAmount) external;\n}\n"},"src/interfaces/ISuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n/// @notice Enum representing different types of fees that can be managed\nenum FeeType {\n REVENUE_SHARE,\n PERFORMANCE_FEE_SHARE\n}\n/// @title ISuperGovernor\n/// @author Superform Labs\n/// @notice Interface for the SuperGovernor contract\n/// @dev Central registry for all deployed contracts in the Superform periphery\n\ninterface ISuperGovernor is IAccessControl {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Structure containing Merkle root data for a hook\n struct HookMerkleRootData {\n bytes32 currentRoot; // Current active Merkle root for the hook\n bytes32 proposedRoot; // Proposed new Merkle root (zero if no proposal exists)\n uint256 effectiveTime; // Timestamp when the proposed root becomes effective\n }\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when trying to access a contract that is not registered\n error CONTRACT_NOT_FOUND();\n /// @notice Thrown when providing an invalid address (typically zero address)\n error INVALID_ADDRESS();\n /// @notice Thrown when a hook is not approved but expected to be\n error HOOK_NOT_APPROVED();\n /// @notice Thrown when an invalid fee value is proposed (must be <= BPS_MAX)\n error INVALID_FEE_VALUE();\n /// @notice Thrown when no proposed fee exists but one is expected\n error NO_PROPOSED_FEE(FeeType feeType);\n /// @notice Thrown when timelock period has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when a validator is already registered\n error VALIDATOR_ALREADY_REGISTERED();\n /// @notice Thrown when trying to change active PPS oracle directly\n error MUST_USE_TIMELOCK_FOR_CHANGE();\n /// @notice Thrown when a SuperBank hook Merkle root is not registered but expected to be\n /// @dev This error is defined here for use by other contracts in the system (SuperVaultStrategy,\n /// SuperVaultAggregator, ECDSAPPSOracle)\n error INVALID_TIMESTAMP();\n /// @notice Thrown when attempting to set an invalid quorum value (typically zero)\n error INVALID_QUORUM();\n /// @notice Thrown when validator and public key array lengths don't match\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when trying to set validator config with an empty validator array\n error EMPTY_VALIDATOR_ARRAY();\n /// @notice Thrown when no active PPS oracle is set but one is required\n error NO_ACTIVE_PPS_ORACLE();\n /// @notice Thrown when no proposed PPS oracle exists but one is expected\n error NO_PROPOSED_PPS_ORACLE();\n /// @notice Error thrown when manager takeovers are frozen\n error MANAGER_TAKEOVERS_FROZEN();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error NO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error ZERO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed minimum staleness exists but one is expected\n error NO_PROPOSED_MIN_STALENESS();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when there's no pending change but one is expected\n error NO_PENDING_CHANGE();\n /// @notice Thrown when the super oracle is not found\n error SUPER_ORACLE_NOT_FOUND();\n /// @notice Thrown when the up token is not found\n error UP_NOT_FOUND();\n /// @notice Thrown when the upkeep token is not found\n error UPKEEP_TOKEN_NOT_FOUND();\n /// @notice Thrown when the gas info is invalid\n error INVALID_GAS_INFO();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an address is set in the registry\n /// @param key The key used to reference the address\n /// @param oldValue The old address value\n /// @param value The address value\n event AddressSet(bytes32 indexed key, address indexed oldValue, address indexed value);\n\n /// @notice Emitted when a hook is approved\n /// @param hook The address of the approved hook\n event HookApproved(address indexed hook);\n\n /// @notice Emitted when validator configuration is set\n /// @param version The version of the configuration\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys (for signature verification)\n /// @param quorum The quorum required for validator consensus\n /// @param offchainConfig Offchain configuration data\n event ValidatorConfigSet(\n uint256 version, address[] validators, bytes[] validatorPublicKeys, uint256 quorum, bytes offchainConfig\n );\n\n /// @notice Emitted when a hook is removed\n /// @param hook The address of the removed hook\n event HookRemoved(address indexed hook);\n\n /// @notice Emitted when a new fee is proposed\n /// @param feeType The type of fee being proposed\n /// @param value The proposed fee value (in basis points)\n /// @param effectiveTime The timestamp when the fee will be effective\n event FeeProposed(FeeType indexed feeType, uint256 value, uint256 effectiveTime);\n\n /// @notice Emitted when a fee is updated\n /// @param feeType The type of fee being updated\n /// @param value The new fee value (in basis points)\n event FeeUpdated(FeeType indexed feeType, uint256 value);\n\n /// @notice Emitted when a new SuperBank hook Merkle root is proposed\n /// @param hook The hook address for which the Merkle root is being proposed\n /// @param newRoot The new Merkle root\n /// @param effectiveTime The timestamp when the new root will be effective\n event SuperBankHookMerkleRootProposed(address indexed hook, bytes32 newRoot, uint256 effectiveTime);\n\n /// @notice Emitted when the SuperBank hook Merkle root is updated.\n /// @param hook The address of the hook for which the Merkle root was updated.\n /// @param newRoot The new Merkle root.\n event SuperBankHookMerkleRootUpdated(address indexed hook, bytes32 newRoot);\n\n /// @notice Emitted when an active PPS oracle is initially set\n /// @param oracle The address of the set oracle\n event ActivePPSOracleSet(address indexed oracle);\n\n /// @notice Emitted when a new PPS oracle is proposed\n /// @param oracle The address of the proposed oracle\n /// @param effectiveTime The timestamp when the proposal will be effective\n event ActivePPSOracleProposed(address indexed oracle, uint256 effectiveTime);\n\n /// @notice Emitted when the active PPS oracle is changed\n /// @param oldOracle The address of the previous oracle\n /// @param newOracle The address of the new oracle\n event ActivePPSOracleChanged(address indexed oldOracle, address indexed newOracle);\n\n /// @notice Event emitted when manager takeovers are permanently frozen\n event ManagerTakeoversFrozen();\n\n /// @notice Emitted when a change to upkeep payments status is proposed\n /// @param enabled The proposed status (enabled/disabled)\n /// @param effectiveTime The timestamp when the status change will be effective\n event UpkeepPaymentsChangeProposed(bool enabled, uint256 effectiveTime);\n\n /// @notice Emitted when upkeep payments status is changed\n /// @param enabled The new status (enabled/disabled)\n event UpkeepPaymentsChanged(bool enabled);\n\n /// @notice Emitted when a new minimum staleness is proposed\n /// @param newMinStaleness The proposed minimum staleness value\n /// @param effectiveTime The timestamp when the new value will be effective\n event MinStalenessProposed(uint256 newMinStaleness, uint256 effectiveTime);\n\n /// @notice Emitted when the minimum staleness is changed\n /// @param newMinStaleness The new minimum staleness value\n event MinStalenessChanged(uint256 newMinStaleness);\n\n /// @notice Emitted when gas info is set\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n event GasInfoSet(address indexed oracle, uint256 gasIncreasePerEntryBatch);\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets an address in the registry\n /// @param key The key to associate with the address\n /// @param value The address value\n function setAddress(bytes32 key, address value) external;\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Change the primary manager for a strategy\n /// @dev Only SuperGovernor can call this function directly\n /// @param strategy The strategy address\n /// @param newManager The new primary manager address\n /// @param feeRecipient The new fee recipient address\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Resets the high-water mark PPS to the current PPS\n /// @dev Only SuperGovernor can call this function\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value for the given strategy\n /// @param strategy Address of the strategy to reset the high-water mark for\n function resetHighWaterMark(address strategy) external;\n\n /// @notice Permanently freezes all manager takeovers globally\n function freezeManagerTakeover() external;\n\n /// @notice Changes the hooks root update timelock duration\n /// @param newTimelock New timelock duration in seconds\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes a new global hooks Merkle root\n /// @dev Only GOVERNOR_ROLE can call this function\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Sets veto status for global hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Sets veto status for a strategy-specific hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param strategy Address of the strategy to affect\n /// @param vetoed Whether to veto (true) or unveto (false) the strategy hooks root\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Sets the maximum staleness period for all oracle feeds\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleMaxStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness period for a specific oracle feed\n /// @param feed The address of the feed to set staleness for\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness periods for multiple oracle feeds in batch\n /// @param feeds The addresses of the feeds to set staleness for\n /// @param newMaxStalenessList The new maximum staleness periods in seconds\n function setOracleFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Queues an oracle update for execution after timelock period\n /// @param bases Base asset addresses\n /// @param quotes Quote asset addresses\n /// @param providers Provider identifiers\n /// @param feeds Feed addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Executes a previously queued oracle update after timelock has expired\n function executeOracleUpdate() external;\n\n /// @notice Queues a provider removal for execution after timelock period\n /// @param providers The providers to remove\n function queueOracleProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Sets uptime feeds for multiple data oracles in batch (Layer 2 only)\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Registers a hook for use in SuperVaults\n /// @param hook The address of the hook to register\n function registerHook(address hook) external;\n\n /// @notice Unregisters a hook from the approved list\n /// @param hook The address of the hook to unregister\n function unregisterHook(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the validator configuration for the protocol\n /// @dev This function atomically updates all validator configuration including quorum.\n /// The entire validator set is replaced (not incrementally updated).\n /// Version must be managed externally for cross-chain synchronization.\n /// Quorum updates require providing the full validator list.\n /// @param version The version number for the configuration (for cross-chain sync)\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys for signature verification\n /// @param quorum The number of validators required for consensus\n /// @param offchainConfig Offchain configuration data (emitted but not stored)\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the active PPS oracle (only if there is no active oracle yet)\n /// @param oracle Address of the PPS oracle to set as active\n function setActivePPSOracle(address oracle) external;\n\n /// @notice Proposes a new active PPS oracle (when there is already an active one)\n /// @param oracle Address of the PPS oracle to propose as active\n function proposeActivePPSOracle(address oracle) external;\n\n /// @notice Executes a previously proposed PPS oracle change after timelock has expired\n function executeActivePPSOracleChange() external;\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new fee value\n /// @param feeType The type of fee to propose\n /// @param value The proposed fee value (in basis points)\n function proposeFee(FeeType feeType, uint256 value) external;\n\n /// @notice Executes a previously proposed fee update after timelock has expired\n /// @param feeType The type of ffee to execute the update for\n function executeFeeUpdate(FeeType feeType) external;\n\n /// @notice Executes an upkeep claim on `SuperVaultAggregator`\n /// @param amount The amount to claim\n function executeUpkeepClaim(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets gas info for an oracle\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external;\n\n /// @notice Proposes a change to upkeep payments enabled status\n /// @param enabled The proposed enabled status\n function proposeUpkeepPaymentsChange(bool enabled) external;\n\n /// @notice Executes a previously proposed upkeep payments status change\n function executeUpkeepPaymentsChange() external;\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new minimum staleness value to prevent maxStaleness from being set too low\n /// @param newMinStaleness The proposed new minimum staleness value in seconds\n function proposeMinStaleness(uint256 newMinStaleness) external;\n\n /// @notice Executes a previously proposed minimum staleness change after timelock has expired\n function executeMinStalenessChange() external;\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to update the Merkle root for.\n /// @param proposedRoot The proposed new Merkle root.\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external;\n\n /// @notice Executes a previously proposed Merkle root update for a specific hook if the effective time has passed.\n /// @param hook The address of the hook to execute the update for.\n function executeSuperBankHookMerkleRootUpdate(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice The identifier of the role that grants access to critical governance functions\n function SUPER_GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to daily operations like hooks and validators\n function GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to bank management functions\n function BANK_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to gas management functions\n function GAS_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to oracle management functions\n function ORACLE_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to guardian functions\n function GUARDIAN_ROLE() external view returns (bytes32);\n\n /// @notice Gets an address from the registry\n /// @param key The key of the address to get\n /// @return The address value\n function getAddress(bytes32 key) external view returns (address);\n\n /// @notice Checks if manager takeovers are frozen\n /// @return True if manager takeovers are frozen, false otherwise\n function isManagerTakeoverFrozen() external view returns (bool);\n\n /// @notice Checks if a hook is registered\n /// @param hook The address of the hook to check\n /// @return True if the hook is registered, false otherwise\n function isHookRegistered(address hook) external view returns (bool);\n\n /// @notice Gets all registered hooks\n /// @return An array of registered hook addresses\n function getRegisteredHooks() external view returns (address[] memory);\n\n /// @notice Checks if an address is an approved validator\n /// @param validator The address to check\n /// @return True if the address is an approved validator, false otherwise\n function isValidator(address validator) external view returns (bool);\n\n /// @notice Checks if an address has the guardian role\n /// @param guardian Address to check\n /// @return true if the address has the GUARDIAN_ROLE\n function isGuardian(address guardian) external view returns (bool);\n\n /// @notice Returns the complete validator configuration\n /// @return version The current configuration version number\n /// @return validators Array of all registered validator addresses\n /// @return validatorPublicKeys Array of validator public keys\n /// @return quorum The number of validators required for consensus\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum);\n\n /// @notice Returns all registered validators\n /// @return List of validator addresses\n function getValidators() external view returns (address[] memory);\n\n /// @notice Returns the number of registered validators (O(1))\n function getValidatorsCount() external view returns (uint256);\n\n /// @notice Returns a validator address by index (0 … count-1)\n /// @param index The index into the validators set\n /// @return validator The validator address at the given index\n function getValidatorAt(uint256 index) external view returns (address validator);\n\n /// @notice Gets the proposed active PPS oracle and its effective time\n /// @return proposedOracle The proposed oracle address\n /// @return effectiveTime The timestamp when the proposed oracle will become effective\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime);\n\n /// @notice Gets the current quorum requirement for the active PPS Oracle\n /// @return The current quorum requirement\n function getPPSOracleQuorum() external view returns (uint256);\n\n /// @notice Gets the active PPS oracle\n /// @return The active PPS oracle address\n function getActivePPSOracle() external view returns (address);\n\n /// @notice Checks if an address is the current active PPS oracle\n /// @param oracle The address to check\n /// @return True if the address is the active PPS oracle, false otherwise\n function isActivePPSOracle(address oracle) external view returns (bool);\n\n /// @notice Gets the current fee value for a specific fee type\n /// @param feeType The type of fee to get\n /// @return The current fee value (in basis points)\n function getFee(FeeType feeType) external view returns (uint256);\n\n /// @notice Gets the current upkeep cost for an entry\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256);\n\n /// @notice Gets the proposed upkeep cost per update and its effective time\n /// @notice Gets the current minimum staleness value\n /// @return The current minimum staleness value in seconds\n function getMinStaleness() external view returns (uint256);\n\n /// @notice Gets the proposed minimum staleness value and its effective time\n /// @return proposedMinStaleness The proposed new minimum staleness value\n /// @return effectiveTime The timestamp when the new value will become effective\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime);\n\n /// @notice Returns the current Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to get the Merkle root for.\n /// @return The Merkle root for the hook's allowed targets.\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32);\n\n /// @notice Gets the proposed Merkle root and its effective time for a specific hook.\n /// @param hook The address of the hook to get the proposed Merkle root for.\n /// @return proposedRoot The proposed Merkle root.\n /// @return effectiveTime The timestamp when the proposed root will become effective.\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime);\n\n /// @notice Checks if upkeep payments are currently enabled\n /// @return enabled True if upkeep payments are enabled\n function isUpkeepPaymentsEnabled() external view returns (bool);\n\n /// @notice Gets the proposed upkeep payments status and effective time\n /// @return enabled The proposed status\n /// @return effectiveTime The timestamp when the change becomes effective\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime);\n\n /// @notice Gets the SUP strategy ID\n /// @return The ID of the SUP strategy vault\n function SUP_STRATEGY() external view returns (bytes32);\n\n /// @notice Gets the UP ID\n /// @return The ID of the UP token\n function UP() external view returns (bytes32);\n\n /// @notice Gets the UPKEEP_TOKEN ID\n /// @return The ID of the UPKEEP_TOKEN (used for upkeep payments, can be UP on mainnet or WETH/USDC on L2s)\n function UPKEEP_TOKEN() external view returns (bytes32);\n\n /// @notice Gets the Treasury ID\n /// @return The ID for the Treasury in the registry\n function TREASURY() external view returns (bytes32);\n\n /// @notice Gets the SuperOracle ID\n /// @return The ID for the SuperOracle in the registry\n function SUPER_ORACLE() external view returns (bytes32);\n\n /// @notice Gets the ECDSA PPS Oracle ID\n /// @return The ID for the ECDSA PPS Oracle in the registry\n function ECDSAPPSORACLE() external view returns (bytes32);\n\n /// @notice Gets the SuperVaultAggregator ID\n /// @return The ID for the SuperVaultAggregator in the registry\n function SUPER_VAULT_AGGREGATOR() external view returns (bytes32);\n\n /// @notice Gets the SuperBank ID\n /// @return The ID for the SuperBank in the registry\n function SUPER_BANK() external view returns (bytes32);\n\n /// @notice Gets the gas info for a specific SuperVault PPS Oracle\n /// @param oracle_ The address of the oracle to get gas info for\n /// @return The gas info for the specified oracle\n function getGasInfo(address oracle_) external view returns (uint256);\n\n /// @notice Cancels a previously proposed oracle provider removal\n function cancelOracleProviderRemoval() external;\n\n /// @notice Executes a previously proposed oracle provider removal after timelock has expired\n function executeOracleProviderRemoval() external;\n}\n"},"src/Bank.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { MerkleProof } from \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\n\n// Superform\nimport { IHookExecutionData } from \"./interfaces/IHookExecutionData.sol\";\nimport {\n ISuperHook,\n ISuperHookInspector,\n ISuperHookResult,\n Execution\n} from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\nabstract contract Bank is ReentrancyGuard {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INVALID_HOOK();\n error INVALID_MERKLE_PROOF();\n error HOOK_VALIDATION_FAILED();\n error HOOK_EXECUTION_FAILED();\n error HOOK_NOT_REGISTERED();\n error ZERO_LENGTH_ARRAY();\n error ZERO_AMOUNT();\n error INVALID_ARRAY_LENGTH();\n error ZERO_ADDRESS();\n error MINIMUM_OUTPUT_AMOUNT_NOT_MET();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when hooks are executed.\n /// @param hooks The addresses of the hooks that were executed.\n /// @param data The data passed to each hook.\n event HooksExecuted(address[] hooks, bytes[] data);\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n function _getMerkleRootForHook(address hookAddress) internal view virtual returns (bytes32);\n\n /// @notice Checks if a hook is registered.\n /// @param hookAddress The hook address to check.\n /// @return registered True if the hook is registered.\n function _isHookRegistered(address hookAddress) internal view virtual returns (bool);\n\n function _executeHooks(IHookExecutionData.HookExecutionData calldata executionData) internal virtual nonReentrant {\n uint256 hooksLength = executionData.hooks.length;\n if (hooksLength == 0) revert ZERO_LENGTH_ARRAY();\n\n // Validate arrays have matching lengths\n if (\n hooksLength != executionData.data.length || hooksLength != executionData.merkleProofs.length\n || hooksLength != executionData.expectedAssetsOrSharesOut.length\n ) {\n revert INVALID_ARRAY_LENGTH();\n }\n\n address prevHook;\n address hookAddress;\n bytes memory hookData;\n bytes32[] memory merkleProof;\n ISuperHook hook;\n bytes32 merkleRoot;\n Execution[] memory executions;\n Execution memory executionStep;\n bool success;\n uint256 expectedOutput;\n uint256 actualOutput;\n\n for (uint256 i; i < hooksLength; i++) {\n hookAddress = executionData.hooks[i];\n\n // Validate hook address is not zero\n if (hookAddress == address(0)) revert ZERO_ADDRESS();\n\n hookData = executionData.data[i];\n merkleProof = executionData.merkleProofs[i];\n expectedOutput = executionData.expectedAssetsOrSharesOut[i];\n\n hook = ISuperHook(hookAddress);\n\n // 1. Verify hook is registered\n if (!_isHookRegistered(hookAddress)) revert HOOK_NOT_REGISTERED();\n\n // 2. Get the Merkle root specific to this hook\n merkleRoot = _getMerkleRootForHook(hookAddress);\n\n // 3. VALIDATE HOOK CONFIGURATION\n if (!_validateHookConfiguration(hookAddress, hookData, merkleProof, merkleRoot)) {\n revert HOOK_VALIDATION_FAILED();\n }\n\n // 4. Set execution context\n hook.setExecutionContext(address(this));\n\n // 5. Build Execution Steps\n executions = hook.build(prevHook, address(this), hookData);\n\n uint256 len = executions.length;\n\n // 6. Execute all steps (no per-target validation needed)\n // Note: Uses all available gas for hook execution. Hooks are trusted and registered,\n // so unlimited gas is acceptable. This allows hooks to perform complex operations.\n // Note: Return data is discarded for gas efficiency. Hook failures will result in\n // generic HOOK_EXECUTION_FAILED error. For debugging, check hook contract logs or\n // use off-chain tooling to inspect failed transactions.\n for (uint256 j; j < len; ++j) {\n executionStep = executions[j];\n\n uint256 valueToSend = executionStep.value;\n address targetToCall = executionStep.target;\n bytes memory callData = executionStep.callData;\n\n // Execute the call\n // We call via assembly to avoid memcopying the returndata\n assembly {\n success := call(\n gas(), // gas - forwards all remaining gas (hooks are trusted)\n targetToCall, // recipient\n valueToSend, // ether value\n add(callData, 0x20), // inloc\n mload(callData), // inlen\n 0, // outloc\n 0 // outlen\n )\n }\n\n if (!success) {\n revert HOOK_EXECUTION_FAILED();\n }\n }\n\n // 6.5. VALIDATE OUTPUT AMOUNT (Slippage Protection)\n // Query the hook for actual output amount\n actualOutput = ISuperHookResult(address(hook)).getOutAmount(address(this));\n\n // Validate actual output meets or exceeds expected output\n // This protects against:\n // - MEV/front-running attacks\n // - Operator mistakes with wrong parameters\n // - Excessive slippage in swaps/conversions\n if (actualOutput < expectedOutput) {\n revert MINIMUM_OUTPUT_AMOUNT_NOT_MET();\n }\n\n // 7. Reset execution state after each hook\n hook.resetExecutionState(address(this));\n\n prevHook = hookAddress;\n }\n\n emit HooksExecuted(executionData.hooks, executionData.data);\n }\n\n /*//////////////////////////////////////////////////////////////\n PRIVATE HELPERS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Validates a hook configuration using Merkle proof.\n /// @dev Validates the hook configuration (hook address + arguments from inspect()) instead of individual targets.\n /// @param hookAddress Address of the hook contract.\n /// @param hookData Calldata to pass to the hook.\n /// @param proof Merkle proof for this hook configuration.\n /// @param root Merkle root to verify against.\n /// @return valid True if the hook configuration is approved.\n function _validateHookConfiguration(\n address hookAddress,\n bytes memory hookData,\n bytes32[] memory proof,\n bytes32 root\n )\n private\n view\n returns (bool valid)\n {\n // If root is not set, reject\n if (root == bytes32(0)) return false;\n\n // Extract hook arguments using inspect()\n bytes memory hookArgs;\n try ISuperHookInspector(hookAddress).inspect(hookData) returns (bytes memory args) {\n hookArgs = args;\n } catch {\n // If hook doesn't implement ISuperHookInspector or inspect() fails, reject\n return false;\n }\n\n // Reject hooks with no address parameters (empty args)\n if (hookArgs.length == 0) return false;\n\n // Create leaf: keccak256(bytes.concat(keccak256(abi.encode(hookAddress, hookArgs))))\n bytes32 leaf = _createHookLeaf(hookAddress, hookArgs);\n\n // For single-leaf trees, empty proof is valid when root equals leaf\n if (proof.length == 0) {\n return root == leaf;\n }\n\n // Verify Merkle proof\n return MerkleProof.verify(proof, root, leaf);\n }\n\n /// @notice Creates a Merkle leaf for a hook configuration.\n /// @dev Matches StandardMerkleTree.of() leaf hashing: keccak256(bytes.concat(keccak256(abi.encode(...))))\n /// @param hookAddress Address of the hook contract.\n /// @param hookArgs Encoded arguments from inspect().\n /// @return leaf The Merkle leaf hash.\n function _createHookLeaf(address hookAddress, bytes memory hookArgs) private pure returns (bytes32 leaf) {\n return keccak256(bytes.concat(keccak256(abi.encode(hookAddress, hookArgs))));\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"},"src/interfaces/IHookExecutionData.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\ninterface IHookExecutionData {\n /// @notice Data required for executing hooks with Merkle proof verification.\n /// @param hooks Array of addresses of hooks to execute.\n /// @param data Array of arbitrary data to pass to each hook.\n /// @param merkleProofs Double array of Merkle proofs verifying each hook's allowed targets.\n /// @param expectedAssetsOrSharesOut Array of minimum expected output amounts for slippage protection.\n struct HookExecutionData {\n address[] hooks;\n bytes[] data;\n bytes32[][] merkleProofs;\n uint256[] expectedAssetsOrSharesOut;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol)\n// This file was procedurally generated from scripts/generate/templates/MerkleProof.js.\n\npragma solidity ^0.8.20;\n\nimport {Hashes} from \"./Hashes.sol\";\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The tree and the proofs can be generated using our\n * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].\n * You will find a quickstart guide in the readme.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the Merkle tree could be reinterpreted as a leaf value.\n * OpenZeppelin's JavaScript library generates Merkle trees that are safe\n * against this attack out of the box.\n *\n * IMPORTANT: Consider memory side-effects when using custom hashing functions\n * that access memory in an unsafe way.\n *\n * NOTE: This library supports proof verification for merkle trees built using\n * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving\n * leaf inclusion in trees built using non-commutative hashing functions requires\n * additional logic that is not supported by this library.\n */\nlibrary MerkleProof {\n /**\n *@dev The multiproof provided is not valid.\n */\n error MerkleProofInvalidMultiproof();\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with the default hashing function.\n */\n function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with the default hashing function.\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with a custom hashing function.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processProof(proof, leaf, hasher) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with a custom hashing function.\n */\n function processProof(\n bytes32[] memory proof,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = hasher(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with the default hashing function.\n */\n function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with the default hashing function.\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with a custom hashing function.\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processProofCalldata(proof, leaf, hasher) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with a custom hashing function.\n */\n function processProofCalldata(\n bytes32[] calldata proof,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = hasher(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in memory with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProof}.\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in memory with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = Hashes.commutativeKeccak256(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in memory with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProof}.\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processMultiProof(proof, proofFlags, leaves, hasher) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in memory with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = hasher(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in calldata with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProofCalldata}.\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in calldata with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = Hashes.commutativeKeccak256(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in calldata with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProofCalldata}.\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in calldata with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = hasher(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant NOT_ENTERED = 1;\n uint256 private constant ENTERED = 2;\n\n uint256 private _status;\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n constructor() {\n _status = NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if (_status == ENTERED) {\n revert ReentrancyGuardReentrantCall();\n }\n\n // Any calls to nonReentrant after this point will fail\n _status = ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _status == ENTERED;\n }\n}\n"},"lib/v2-core/src/interfaces/ISuperHook.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { Execution } from \"modulekit/accounts/erc7579/lib/ExecutionLib.sol\";\n\n/**\n * @title SuperHook System\n * @author Superform Labs\n * @notice The hook system provides a modular and composable way to execute operations on assets\n * @dev The hook system architecture consists of several interfaces that work together:\n * - ISuperHook: The base interface all hooks implement, with lifecycle methods\n * - ISuperHookResult: Provides execution results and output information\n * - Specialized interfaces (ISuperHookOutflow, ISuperHookLoans, etc.) for specific behaviors\n *\n * Hooks are executed in sequence, where each hook can access the results from previous hooks.\n * The three main types of hooks are:\n * - NONACCOUNTING: Utility hooks that don't update the accounting system\n * - INFLOW: Hooks that process deposits or additions to positions\n * - OUTFLOW: Hooks that process withdrawals or reductions to positions\n */\ninterface ISuperLockableHook {\n /// @notice The vault bank address used to lock SuperPositions\n /// @dev Only relevant for cross-chain operations where positions are locked\n /// @return The vault bank address, or address(0) if not applicable\n function vaultBank() external view returns (address);\n\n /// @notice The destination chain ID for cross-chain operations\n /// @dev Used to identify the target chain for cross-chain position transfers\n /// @return The destination chain ID, or 0 if not a cross-chain operation\n function dstChainId() external view returns (uint256);\n}\n\ninterface ISuperHookSetter {\n /// @notice Sets the output amount for the hook\n /// @dev Used for updating `outAmount` when fees were deducted\n /// @param outAmount The amount of tokens processed by the hook\n /// @param caller The caller address for context identification\n function setOutAmount(uint256 outAmount, address caller) external;\n}\n/// @title ISuperHookInspector\n/// @author Superform Labs\n/// @notice Interface for the SuperHookInspector contract that manages hook inspection\n\ninterface ISuperHookInspector {\n /// @notice Inspect the hook\n /// @param data The hook data to inspect\n /// @return argsEncoded The arguments of the hook encoded\n function inspect(bytes calldata data) external view returns (bytes memory argsEncoded);\n}\n\n/// @title ISuperHookResult\n/// @author Superform Labs\n/// @notice Interface that exposes the result of a hook execution\n/// @dev All hooks must implement this interface to provide standardized access to execution results.\n/// These results are used by subsequent hooks in the execution chain and by the executor.\ninterface ISuperHookResult {\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The type of hook\n /// @dev Used to determine how accounting should process this hook's results\n /// @return The hook type (NONACCOUNTING, INFLOW, or OUTFLOW)\n function hookType() external view returns (ISuperHook.HookType);\n\n /// @notice The SuperPosition (SP) token associated with this hook\n /// @dev For vault hooks, this would be the tokenized position representing shares\n /// @return The address of the SP token, or address(0) if not applicable\n function spToken() external view returns (address);\n\n /// @notice The underlying asset token being processed\n /// @dev For most hooks, this is the actual token being deposited or withdrawn\n /// @return The address of the asset token, or address(0) for native assets\n function asset() external view returns (address);\n\n /// @notice The amount of tokens processed by the hook in a given caller context, subject to fees after update\n /// @dev This is the primary output value used by subsequent hooks\n /// @param caller The caller address for context identification\n /// @return The amount of tokens (assets or shares) processed\n function getOutAmount(address caller) external view returns (uint256);\n}\n\n/// @title ISuperHookContextAware\n/// @author Superform Labs\n/// @notice Interface for hooks that can use previous hook results in their execution\n/// @dev Enables contextual awareness and data flow between hooks in a chain\ninterface ISuperHookContextAware {\n /// @notice Determines if this hook should use the amount from the previous hook\n /// @dev Used to create hook chains where output from one hook becomes input to the next\n /// @param data The hook-specific data containing configuration\n /// @return True if the hook should use the previous hook's output amount\n function decodeUsePrevHookAmount(bytes memory data) external pure returns (bool);\n}\n\n/// @title ISuperHookInflowOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that handle both inflows and outflows\n/// @dev Provides standardized amount extraction for both deposit and withdrawal operations\ninterface ISuperHookInflowOutflow {\n /// @notice Extracts the amount from the hook's calldata\n /// @dev Used to determine the quantity of assets or shares being processed\n /// @param data The hook-specific calldata containing the amount\n /// @return The amount of tokens to process\n function decodeAmount(bytes memory data) external pure returns (uint256);\n}\n\n/// @title ISuperHookOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that specifically handle outflows (withdrawals)\n/// @dev Provides additional functionality needed only for outflow operations\ninterface ISuperHookOutflow {\n /// @notice Replace the amount in the calldata\n /// @param data The data to replace the amount in\n /// @param amount The amount to replace\n /// @return data The data with the replaced amount\n function replaceCalldataAmount(bytes memory data, uint256 amount) external pure returns (bytes memory);\n}\n\n/// @title ISuperHookResultOutflow\n/// @author Superform Labs\n/// @notice Extended result interface for outflow hook operations\n/// @dev Extends the base result interface with outflow-specific information\ninterface ISuperHookResultOutflow is ISuperHookResult {\n /// @notice The amount of shares consumed during outflow processing\n /// @dev Used for cost basis calculation in the accounting system\n /// @return The amount of shares consumed from the user's position\n function usedShares() external view returns (uint256);\n}\n\n/// @title ISuperHookLoans\n/// @author Superform Labs\n/// @notice Interface for hooks that interact with lending protocols\n/// @dev Extends context awareness to enable loan operations within hook chains\ninterface ISuperHookLoans is ISuperHookContextAware {\n /// @notice Gets the address of the token being borrowed\n /// @dev Used to identify which asset is being borrowed from the lending protocol\n /// @param data The hook-specific data containing loan information\n /// @return The address of the borrowed token\n function getLoanTokenAddress(bytes memory data) external pure returns (address);\n\n /// @notice Gets the address of the token used as collateral\n /// @dev Used to identify which asset is being used to secure the loan\n /// @param data The hook-specific data containing collateral information\n /// @return The address of the collateral token\n function getCollateralTokenAddress(bytes memory data) external view returns (address);\n\n /// @notice Gets the current loan token balance for an account\n /// @dev Used to track outstanding loan amounts\n /// @param account The account to check the loan balance for\n /// @param data The hook-specific data containing loan parameters\n /// @return The amount of tokens currently borrowed\n function getLoanTokenBalance(address account, bytes memory data) external view returns (uint256);\n\n /// @notice Gets the current collateral token balance for an account\n /// @dev Used to track collateral positions\n /// @param account The account to check the collateral balance for\n /// @param data The hook-specific data containing collateral parameters\n /// @return The amount of tokens currently used as collateral\n function getCollateralTokenBalance(address account, bytes memory data) external view returns (uint256);\n}\n\n/// @title ISuperHookAsyncCancelations\n/// @author Superform Labs\n/// @notice Interface for hooks that can cancel asynchronous operations\n/// @dev Used to handle cancellation of pending operations that haven't completed\ninterface ISuperHookAsyncCancelations {\n /// @notice Types of cancellations that can be performed\n /// @dev Distinguishes between different operation types that can be canceled\n enum CancelationType {\n NONE, // Not a cancelation hook\n INFLOW, // Cancels a pending deposit operation\n OUTFLOW // Cancels a pending withdrawal operation\n\n }\n\n /// @notice Identifies the type of async operation this hook can cancel\n /// @dev Used to verify the hook is appropriate for the operation being canceled\n /// @return asyncType The type of cancellation this hook performs\n function isAsyncCancelHook() external pure returns (CancelationType asyncType);\n}\n\n/// @title ISuperHook\n/// @author Superform Labs\n/// @notice The core hook interface that all hooks must implement\n/// @dev Defines the lifecycle methods and execution flow for the hook system\n/// Hooks are executed in sequence with results passed between them\ninterface ISuperHook {\n /*//////////////////////////////////////////////////////////////\n\n ENUMS\n //////////////////////////////////////////////////////////////*/\n /// @notice Defines the possible types of hooks in the system\n /// @dev Used to determine how the hook affects accounting and what operations it performs\n enum HookType {\n NONACCOUNTING, // Hook doesn't affect accounting (e.g., a swap or bridge)\n INFLOW, // Hook processes deposits or positions being added\n OUTFLOW // Hook processes withdrawals or positions being removed\n\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Builds the execution array for the hook operation\n /// @dev This is the core method where hooks define their on-chain interactions\n /// The returned executions are a sequence of contract calls to perform\n /// No state changes should occur in this method\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform executions for (usually an ERC7579 account)\n /// @param data The hook-specific parameters and configuration data\n /// @return executions Array of Execution structs defining calls to make\n function build(\n address prevHook,\n address account,\n bytes calldata data\n )\n external\n view\n returns (Execution[] memory executions);\n\n /*//////////////////////////////////////////////////////////////\n PUBLIC METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Prepares the hook for execution\n /// @dev Called before the main execution, used to validate inputs and set execution context\n /// This method may perform state changes to set up the hook's execution state\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform operations for\n /// @param data The hook-specific parameters and configuration data\n function preExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Finalizes the hook after execution\n /// @dev Called after the main execution, used to update hook state and calculate results\n /// Sets output values (outAmount, usedShares, etc.) for subsequent hooks\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account operations were performed for\n /// @param data The hook-specific parameters and configuration data\n function postExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Returns the specific subtype identification for this hook\n /// @dev Used to categorize hooks beyond the basic HookType\n /// For example, a hook might be of type INFLOW but subtype VAULT_DEPOSIT\n /// @return A bytes32 identifier for the specific hook functionality\n function subtype() external view returns (bytes32);\n\n /// @notice Resets hook mutexes\n /// @param caller The caller address for context identification\n function resetExecutionState(address caller) external;\n\n /// @notice Sets the caller address that initiated the execution\n /// @dev Used for security validation between preExecute and postExecute calls\n /// @param caller The caller address for context identification\n function setExecutionContext(address caller) external;\n\n /// @notice Returns the execution nonce for the current execution context\n /// @dev Used to ensure unique execution contexts and prevent replay attacks\n /// @return The execution nonce\n function executionNonce() external view returns (uint256);\n\n /// @notice Returns the last caller registered by `setExecutionContext`\n /// @return The last caller address\n function lastCaller() external view returns (address);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/Hashes.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library of standard hash functions.\n *\n * _Available since v5.1._\n */\nlibrary Hashes {\n /**\n * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.\n *\n * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].\n */\n function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {\n return a < b ? efficientKeccak256(a, b) : efficientKeccak256(b, a);\n }\n\n /**\n * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.\n */\n function efficientKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32 value) {\n assembly (\"memory-safe\") {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n// Types\nimport { Execution } from \"../../common/interfaces/IERC7579Account.sol\";\n\n/**\n * Helper Library for decoding Execution calldata\n * malloc for memory allocation is bad for gas. use this assembly instead\n */\nlibrary ExecutionLib {\n error ERC7579DecodingError();\n\n /**\n * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.\n * @dev code is copied from solady's LibERC7579.sol\n * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146\n * Credits to Vectorized and the Solady Team\n */\n function decodeBatch(bytes calldata executionCalldata)\n internal\n pure\n returns (Execution[] calldata executionBatch)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let u := calldataload(executionCalldata.offset)\n let s := add(executionCalldata.offset, u)\n let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)\n executionBatch.offset := add(s, 0x20)\n executionBatch.length := calldataload(s)\n if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if executionBatch.length {\n // Perform bounds checks on the decoded `executionBatch`.\n // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.\n for { let i := executionBatch.length } 1 { } {\n i := sub(i, 1)\n let p := calldataload(add(executionBatch.offset, shl(5, i)))\n let c := add(executionBatch.offset, p)\n let q := calldataload(add(c, 0x40))\n let o := add(c, q)\n // forgefmt: disable-next-item\n if or(shr(64, or(calldataload(o), or(p, q))),\n or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if iszero(i) { break }\n }\n }\n }\n }\n\n function encodeBatch(Execution[] memory executions)\n internal\n pure\n returns (bytes memory callData)\n {\n callData = abi.encode(executions);\n }\n\n function decodeSingle(bytes calldata executionCalldata)\n internal\n pure\n returns (address target, uint256 value, bytes calldata callData)\n {\n target = address(bytes20(executionCalldata[0:20]));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n function encodeSingle(\n address target,\n uint256 value,\n bytes memory callData\n )\n internal\n pure\n returns (bytes memory userOpCalldata)\n {\n userOpCalldata = abi.encodePacked(target, value, callData);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n/* solhint-disable no-unused-import */\n\n// Types\nimport { CallType, ExecType, ModeCode } from \"../lib/ModeLib.sol\";\n\n// Structs\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\ninterface IERC7579Account {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by ERC-4337 EntryPoint.sol\n * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @dev Ensure adequate authorization control: i.e. onlyExecutorModule\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function executeFromExecutor(\n ModeCode mode,\n bytes calldata executionCalldata\n )\n external\n payable\n returns (bytes[] memory returnData);\n\n /**\n * @dev ERC-1271 isValidSignature\n * This function is intended to be used to validate a smart account signature\n * and may forward the call to a validator module\n *\n * @param hash The hash of the data that is signed\n * @param data The data that is signed\n */\n function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);\n\n /**\n * @dev installs a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be required on the module during `onInstall`\n * initialization.\n */\n function installModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata initData\n )\n external\n payable;\n\n /**\n * @dev uninstalls a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be required on the module during `onUninstall`\n * de-initialization.\n */\n function uninstallModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata deInitData\n )\n external\n payable;\n\n /**\n * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)\n * @param encodedMode the encoded mode\n */\n function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);\n\n /**\n * Function to check if the account supports installation of a certain module type Id\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n\n /**\n * Function to check if the account has a certain module installed\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * Note: keep in mind that some contracts can be multiple module types at the same time. It\n * thus may be necessary to query multiple module types\n * @param module the module address\n * @param additionalContext additional context data that the smart account may interpret to\n * identifiy conditions under which the module is installed.\n * usually this is not necessary, but for some special hooks that\n * are stored in mappings, this param might be needed\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n )\n external\n view\n returns (bool);\n\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n * the accountId should be structured like so:\n * \"vendorname.accountname.semver\"\n */\n function accountId() external view returns (string memory accountImplementationId);\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/lib/ModeLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title ModeLib\n * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat)\n * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode\n * encoding is used.\n * Function Signature of execute function:\n * function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and\n * context.\n * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that\n * implement\n * more complex execution modes may use the entire bytes32.\n *\n * |--------------------------------------------------------------------|\n * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload |\n * |--------------------------------------------------------------------|\n * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes |\n * |--------------------------------------------------------------------|\n *\n * CALLTYPE: 1 byte\n * CallType is used to determine how the executeCalldata paramter of the execute function has to be\n * decoded.\n * It can be either single, batch or delegatecall. In the future different calls could be added.\n * CALLTYPE can be used by a validation module to determine how to decode .\n *\n * EXECTYPE: 1 byte\n * ExecType is used to determine how the account should handle the execution.\n * It can indicate if the execution should revert on failure or continue execution.\n * In the future more execution modes may be added.\n * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in\n * a batch fails, the entire batch is reverted\n *\n * UNUSED: 4 bytes\n * Unused bytes are reserved for future use.\n *\n * ModeSelector: bytes4\n * The \"optional\" mode selector can be used by account vendors, to implement custom behavior in\n * their accounts.\n * the way a ModeSelector is to be calculated is bytes4(keccak256(\"vendorname.featurename\"))\n * this is to prevent collisions between different vendors, while allowing innovation and the\n * development of new features without coordination between ERC-7579 implementing accounts\n *\n * ModePayload: 22 bytes\n * Mode payload is used to pass additional data to the smart account execution, this may be\n * interpreted depending on the ModeSelector\n *\n * ExecutionCallData: n bytes\n * single, delegatecall or batch exec abi.encoded as bytes\n */\n\n// Custom type for improved developer experience\ntype ModeCode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ModeSelector is bytes4;\n\ntype ModePayload is bytes22;\n\n// Default CallType\nCallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n// Batched CallType\nCallType constant CALLTYPE_BATCH = CallType.wrap(0x01);\nCallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);\n// @dev Implementing delegatecall is OPTIONAL!\n// implement delegatecall with extreme care.\nCallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n// @dev default behavior is to revert on failure\n// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure\n// Since this is value 0x00, no additional encoding is required for simple accounts\nExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n// @dev account may elect to change execution behavior. For example \"try exec\" / \"allow fail\"\nExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\nModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));\n// Example declaration of a custom mode selector\nModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256(\"default.mode.offset\")));\n\n/**\n * @dev ModeLib is a helper library to encode/decode ModeCodes\n */\nlibrary ModeLib {\n function decode(ModeCode mode)\n internal\n pure\n returns (\n CallType _calltype,\n ExecType _execType,\n ModeSelector _modeSelector,\n ModePayload _modePayload\n )\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _calltype := mode\n _execType := shl(8, mode)\n _modeSelector := shl(48, mode)\n _modePayload := shl(80, mode)\n }\n }\n\n function encode(\n CallType callType,\n ExecType execType,\n ModeSelector mode,\n ModePayload payload\n )\n internal\n pure\n returns (ModeCode)\n {\n return ModeCode.wrap(\n bytes32(\n abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)\n )\n );\n }\n\n function encodeSimpleBatch() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function encodeSimpleSingle() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function getCallType(ModeCode mode) internal pure returns (CallType calltype) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n calltype := mode\n }\n }\n}\n\nusing { eqModeSelector as == } for ModeSelector global;\nusing { eqCallType as == } for CallType global;\nusing { neqCallType as != } for CallType global;\nusing { eqExecType as == } for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction neqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperGovernor.standard-json-input.json b/script/locked-bytecode-dev/SuperGovernor.standard-json-input.json new file mode 100644 index 000000000..97bf37604 --- /dev/null +++ b/script/locked-bytecode-dev/SuperGovernor.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { AccessControl } from \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n// Superform\nimport { ISuperGovernor, FeeType } from \"./interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"./interfaces/SuperVault/ISuperVaultAggregator.sol\";\nimport { ISuperOracle } from \"./interfaces/oracles/ISuperOracle.sol\";\nimport { ISuperOracleL2 } from \"./interfaces/oracles/ISuperOracleL2.sol\";\n\n/// @title SuperGovernor\n/// @author Superform Labs\n/// @notice Central registry for all deployed contracts in the Superform periphery\ncontract SuperGovernor is ISuperGovernor, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n /*//////////////////////////////////////////////////////////////\n STORAGE\n //////////////////////////////////////////////////////////////*/\n // Address registry\n mapping(bytes32 id => address address_) private _addressRegistry;\n\n // PPS Oracle management\n // Current active PPS Oracle\n address private _activePPSOracle;\n // Proposed new active PPS Oracle\n address private _proposedActivePPSOracle;\n // Effective time for proposed active PPS Oracle change\n uint256 private _activePPSOracleEffectiveTime;\n\n // Hook registry\n EnumerableSet.AddressSet private _registeredHooks;\n\n // SuperBank Hook Target validation\n mapping(address hook => ISuperGovernor.HookMerkleRootData merkleData) private superBankHooksMerkleRoots;\n\n // Global freeze for manager takeovers\n bool private _managerTakeoversFrozen;\n\n // Validator configuration struct\n struct ValidatorConfig {\n uint256 version;\n EnumerableSet.AddressSet validators;\n bytes[] validatorPublicKeys;\n uint256 quorum;\n }\n\n // Validator configuration\n ValidatorConfig private _validatorConfig;\n\n // Fee management - packed struct for gas optimization\n struct FeeData {\n uint128 value; // Current fee value (BPS, max 10000)\n uint128 proposedValue; // Proposed fee value\n uint256 effectiveTime; // Timestamp when proposed value becomes effective\n }\n mapping(FeeType => FeeData) private _feeData;\n\n mapping(address _oracle => uint256 _entryGas) private _gasPerEntry;\n\n // Upkeep control\n bool private _upkeepPaymentsEnabled;\n bool private _proposedUpkeepPaymentsEnabled;\n uint256 private _upkeepPaymentsChangeEffectiveTime;\n\n // Min staleness configuration to prevent maxStaleness from being set too low\n uint256 private _minStaleness;\n uint256 private _proposedMinStaleness;\n uint256 private _minStalenessEffectiveTime;\n\n // Oracle constants for price conversions in _convertGasToUpkeepToken()\n // Standard ERC-7281 address for native token (ETH)\n address private constant NATIVE_TOKEN = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n // ISO 4217 numeric code for USD (840)\n address private constant USD_TOKEN = address(840);\n // Synthetic address for gas units in oracle pricing\n address private constant GAS_QUOTE = address(uint160(uint256(keccak256(\"GAS_QUOTE\"))));\n // Synthetic address for wei units in oracle pricing\n address private constant WEI_QUOTE = address(uint160(uint256(keccak256(\"WEI_QUOTE\"))));\n // Provider identifier for averaged oracle prices\n bytes32 private constant AVERAGE_PROVIDER = keccak256(\"AVERAGE_PROVIDER\");\n\n // Timelock configuration\n // 7-day timelock for critical parameter changes (standard governance delay)\n uint256 private constant TIMELOCK = 7 days;\n uint256 private constant BPS_MAX = 10_000; // 100% in basis points\n\n // Role definitions\n bytes32 private constant _SUPER_GOVERNOR_ROLE = keccak256(\"SUPER_GOVERNOR_ROLE\");\n bytes32 private constant _GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n bytes32 private constant _BANK_MANAGER_ROLE = keccak256(\"BANK_MANAGER_ROLE\");\n bytes32 private constant _GUARDIAN_ROLE = keccak256(\"GUARDIAN_ROLE\");\n bytes32 private constant _GAS_MANAGER_ROLE = keccak256(\"GAS_MANAGER_ROLE\");\n bytes32 private constant _ORACLE_MANAGER_ROLE = keccak256(\"ORACLE_MANAGER_ROLE\");\n\n // Common contract keys\n bytes32 public constant UP = keccak256(\"UP\");\n bytes32 public constant UPKEEP_TOKEN = keccak256(\"UPKEEP_TOKEN\");\n bytes32 public constant SUP_STRATEGY = keccak256(\"SUP_STRATEGY\");\n bytes32 public constant TREASURY = keccak256(\"TREASURY\");\n bytes32 public constant SUPER_BANK = keccak256(\"SUPER_BANK\");\n bytes32 public constant SUPER_ORACLE = keccak256(\"SUPER_ORACLE\");\n bytes32 public constant BANK_MANAGER = keccak256(\"BANK_MANAGER\");\n bytes32 public constant ECDSAPPSORACLE = keccak256(\"ECDSAPPSORACLE\");\n bytes32 public constant SUPER_VAULT_AGGREGATOR = keccak256(\"SUPER_VAULT_AGGREGATOR\");\n\n // Fee constants\n uint256 public constant REVENUE_SHARE = 0; // 0% starting revenue share to sUP\n uint256 public constant PERFORMANCE_FEE_SHARE = 5000; // 50% protocol share of manager's performance fee\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n /// @notice Initializes the SuperGovernor contract\n /// @param superGovernor Address of the default admin (will have SUPER_GOVERNOR_ROLE)\n /// @param governor Address that will have the GOVERNOR_ROLE for daily operations\n /// @param bankManager Address that will have the BANK_MANAGER_ROLE for daily operations\n /// @param oracleManager Address that will have the ORACLE_MANAGER_ROLE for daily operations\n /// @param gasManager Address that will have the GAS_MANAGER_ROLE for daily operations\n /// @param guardian Address that will have the GUARDIAN_ROLE for veto operations\n /// @param treasury Address of the treasury\n /// @param upkeepPaymentsEnabled Initial value for upkeep payments (true for mainnet, false otherwise)\n constructor(\n address superGovernor,\n address governor,\n address bankManager,\n address oracleManager,\n address gasManager,\n address guardian,\n address treasury,\n bool upkeepPaymentsEnabled\n ) {\n if (\n superGovernor == address(0) || treasury == address(0) || governor == address(0) || bankManager == address(0)\n || gasManager == address(0) || oracleManager == address(0) || guardian == address(0)\n ) revert INVALID_ADDRESS();\n\n // Set up roles\n _grantRole(DEFAULT_ADMIN_ROLE, superGovernor);\n _grantRole(_SUPER_GOVERNOR_ROLE, superGovernor);\n _grantRole(_GOVERNOR_ROLE, governor);\n _grantRole(_BANK_MANAGER_ROLE, bankManager);\n _grantRole(_ORACLE_MANAGER_ROLE, oracleManager);\n _grantRole(_GAS_MANAGER_ROLE, gasManager);\n _grantRole(_GUARDIAN_ROLE, guardian);\n\n // Set role admins\n _setRoleAdmin(_GUARDIAN_ROLE, DEFAULT_ADMIN_ROLE);\n _setRoleAdmin(_GOVERNOR_ROLE, DEFAULT_ADMIN_ROLE);\n _setRoleAdmin(_SUPER_GOVERNOR_ROLE, DEFAULT_ADMIN_ROLE);\n _setRoleAdmin(_BANK_MANAGER_ROLE, DEFAULT_ADMIN_ROLE);\n _setRoleAdmin(_ORACLE_MANAGER_ROLE, DEFAULT_ADMIN_ROLE);\n _setRoleAdmin(_GAS_MANAGER_ROLE, DEFAULT_ADMIN_ROLE);\n\n // Initialize with default fees\n // casting to 'uint128' is safe because REVENUE_SHARE and PERFORMANCE_FEE_SHARE are constants < BPS_MAX (10000)\n // forge-lint: disable-next-line(unsafe-typecast)\n _feeData[FeeType.REVENUE_SHARE].value = uint128(REVENUE_SHARE); // 0% revenue share (changeable via governance)\n // forge-lint: disable-next-line(unsafe-typecast)\n _feeData[FeeType.PERFORMANCE_FEE_SHARE].value = uint128(PERFORMANCE_FEE_SHARE); // 50% protocol fee share\n emit FeeUpdated(FeeType.REVENUE_SHARE, REVENUE_SHARE);\n emit FeeUpdated(FeeType.PERFORMANCE_FEE_SHARE, PERFORMANCE_FEE_SHARE);\n\n // Set treasury in address registry\n _addressRegistry[TREASURY] = treasury;\n emit AddressSet(TREASURY, address(0), treasury);\n\n // Initialize minimum staleness to 5 minutes (300 seconds)\n // Prevents oracle manipulation via extremely low staleness values\n // Ensures sufficient time for price feed updates across providers\n _minStaleness = 300;\n\n // Initialize upkeep payments enabled status\n // True for mainnet (where upkeep is needed), false otherwise\n _upkeepPaymentsEnabled = upkeepPaymentsEnabled;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function setAddress(bytes32 key, address value) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n if (value == address(0)) revert INVALID_ADDRESS();\n\n address oldValue = _addressRegistry[key];\n\n _addressRegistry[key] = value;\n emit AddressSet(key, oldValue, value);\n }\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function changePrimaryManager(\n address strategy,\n address newManager,\n address feeRecipient\n )\n external\n onlyRole(_SUPER_GOVERNOR_ROLE)\n {\n // Check if takeovers are globally frozen\n if (_managerTakeoversFrozen) revert MANAGER_TAKEOVERS_FROZEN();\n\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n // Call the interface method to change the manager\n // This function can only be called by the SuperGovernor and bypasses the timelock\n ISuperVaultAggregator(aggregator).changePrimaryManager(strategy, newManager, feeRecipient);\n }\n\n /// @inheritdoc ISuperGovernor\n function resetHighWaterMark(address strategy) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n if (strategy == address(0)) revert INVALID_ADDRESS();\n\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperVaultAggregator(aggregator).resetHighWaterMark(strategy);\n }\n\n /// @inheritdoc ISuperGovernor\n function freezeManagerTakeover() external onlyRole(_SUPER_GOVERNOR_ROLE) {\n if (_managerTakeoversFrozen) revert MANAGER_TAKEOVERS_FROZEN();\n\n // Set frozen status to true (permanent, cannot be undone)\n _managerTakeoversFrozen = true;\n\n // Emit event for the frozen status\n emit ManagerTakeoversFrozen();\n }\n\n /// @inheritdoc ISuperGovernor\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n // Note: Zero timelock is intentionally allowed for SUPER_GOVERNOR_ROLE\n // to enable immediate hook updates in emergency situations\n // Call the SuperVaultAggregator to change the hooks root update timelock\n ISuperVaultAggregator(aggregator).setHooksRootUpdateTimelock(newTimelock);\n }\n\n /// @inheritdoc ISuperGovernor\n function proposeGlobalHooksRoot(bytes32 newRoot) external onlyRole(_GOVERNOR_ROLE) {\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperVaultAggregator(aggregator).proposeGlobalHooksRoot(newRoot);\n }\n\n /// @inheritdoc ISuperGovernor\n function setGlobalHooksRootVetoStatus(bool vetoed) external onlyRole(_GUARDIAN_ROLE) {\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperVaultAggregator(aggregator).setGlobalHooksRootVetoStatus(vetoed);\n }\n\n /// @inheritdoc ISuperGovernor\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external onlyRole(_GUARDIAN_ROLE) {\n if (strategy == address(0)) revert INVALID_ADDRESS();\n\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperVaultAggregator(aggregator).setStrategyHooksRootVetoStatus(strategy, vetoed);\n }\n\n /// @inheritdoc ISuperGovernor\n function setOracleMaxStaleness(uint256 newMaxStaleness) external onlyRole(_ORACLE_MANAGER_ROLE) {\n if (newMaxStaleness < _minStaleness) revert MAX_STALENESS_TOO_LOW();\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).setDefaultStaleness(newMaxStaleness);\n }\n\n /// @inheritdoc ISuperGovernor\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external onlyRole(_ORACLE_MANAGER_ROLE) {\n if (feed == address(0)) revert INVALID_ADDRESS();\n if (newMaxStaleness < _minStaleness) revert MAX_STALENESS_TOO_LOW();\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).setFeedMaxStaleness(feed, newMaxStaleness);\n }\n\n /// @inheritdoc ISuperGovernor\n function setOracleFeedMaxStalenessBatch(\n address[] calldata feeds_,\n uint256[] calldata newMaxStalenessList_\n )\n external\n onlyRole(_ORACLE_MANAGER_ROLE)\n {\n // Validate all staleness values before proceeding\n for (uint256 i; i < newMaxStalenessList_.length; i++) {\n if (newMaxStalenessList_[i] < _minStaleness) revert MAX_STALENESS_TOO_LOW();\n }\n\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).setFeedMaxStalenessBatch(feeds_, newMaxStalenessList_);\n }\n\n /// @inheritdoc ISuperGovernor\n function queueOracleUpdate(\n address[] calldata bases_,\n address[] calldata quotes_,\n bytes32[] calldata providers_,\n address[] calldata feeds_\n )\n external\n onlyRole(_ORACLE_MANAGER_ROLE)\n {\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).queueOracleUpdate(bases_, quotes_, providers_, feeds_);\n }\n\n /// @inheritdoc ISuperGovernor\n function executeOracleUpdate() external onlyRole(_ORACLE_MANAGER_ROLE) {\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).executeOracleUpdate();\n }\n\n /// @inheritdoc ISuperGovernor\n function queueOracleProviderRemoval(bytes32[] calldata providers) external onlyRole(_ORACLE_MANAGER_ROLE) {\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).queueProviderRemoval(providers);\n }\n\n /// @inheritdoc ISuperGovernor\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles_,\n address[] calldata uptimeOracles_,\n uint256[] calldata gracePeriods_\n )\n external\n onlyRole(_ORACLE_MANAGER_ROLE)\n {\n address oracleL2 = _addressRegistry[SUPER_ORACLE];\n if (oracleL2 == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracleL2(oracleL2).batchSetUptimeFeed(dataOracles_, uptimeOracles_, gracePeriods_);\n }\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function registerHook(address hook) external onlyRole(_GOVERNOR_ROLE) {\n if (hook == address(0)) revert INVALID_ADDRESS();\n\n if (_registeredHooks.add(hook)) {\n emit HookApproved(hook);\n }\n }\n\n /// @inheritdoc ISuperGovernor\n function unregisterHook(address hook) external onlyRole(_GOVERNOR_ROLE) {\n if (_registeredHooks.remove(hook)) {\n // Clear merkle root data for the unregistered hook to prevent stale data\n delete superBankHooksMerkleRoots[hook];\n\n emit HookRemoved(hook);\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n // version is provided as param and not incremented in the function to sync config versions across chains\n // offchainConfig is not stored and simply emitted to create source for offchain validators to sync on\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external\n onlyRole(_GOVERNOR_ROLE)\n {\n uint256 validatorsLength = validators.length;\n uint256 validatorPublicKeysLength = validatorPublicKeys.length;\n // Validate inputs\n if (validatorsLength == 0) revert EMPTY_VALIDATOR_ARRAY();\n if (validatorsLength != validatorPublicKeysLength) revert ARRAY_LENGTH_MISMATCH();\n if (quorum == 0 || quorum > validatorsLength) revert INVALID_QUORUM();\n\n // Clear existing validators\n _validatorConfig.validators.clear();\n\n // Add new validators and validate no duplicates\n for (uint256 i; i < validatorsLength; i++) {\n if (validators[i] == address(0)) revert INVALID_ADDRESS();\n if (!_validatorConfig.validators.add(validators[i])) revert VALIDATOR_ALREADY_REGISTERED();\n }\n\n // Update config tracking\n _validatorConfig.version = version;\n _validatorConfig.quorum = quorum;\n\n // Store public keys\n delete _validatorConfig.validatorPublicKeys;\n for (uint256 i; i < validatorPublicKeysLength; i++) {\n _validatorConfig.validatorPublicKeys.push(validatorPublicKeys[i]);\n }\n\n emit ValidatorConfigSet(_validatorConfig.version, validators, validatorPublicKeys, quorum, offchainConfig);\n }\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function setActivePPSOracle(address oracle) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n if (oracle == address(0)) revert INVALID_ADDRESS();\n\n // If this is the first oracle or replacing a zero oracle, set it immediately\n if (_activePPSOracle == address(0)) {\n _activePPSOracle = oracle;\n emit ActivePPSOracleSet(oracle);\n } else {\n // Otherwise require the timelock process\n revert MUST_USE_TIMELOCK_FOR_CHANGE();\n }\n }\n\n /// @inheritdoc ISuperGovernor\n function proposeActivePPSOracle(address oracle) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n if (oracle == address(0)) revert INVALID_ADDRESS();\n\n _proposedActivePPSOracle = oracle;\n _activePPSOracleEffectiveTime = block.timestamp + TIMELOCK;\n\n emit ActivePPSOracleProposed(oracle, _activePPSOracleEffectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function executeActivePPSOracleChange() external {\n if (_proposedActivePPSOracle == address(0)) revert NO_PROPOSED_PPS_ORACLE();\n\n if (block.timestamp < _activePPSOracleEffectiveTime) {\n revert TIMELOCK_NOT_EXPIRED();\n }\n\n address oldOracle = _activePPSOracle;\n _activePPSOracle = _proposedActivePPSOracle;\n\n // Reset proposal data\n _proposedActivePPSOracle = address(0);\n _activePPSOracleEffectiveTime = 0;\n\n emit ActivePPSOracleChanged(oldOracle, _activePPSOracle);\n }\n\n /// @inheritdoc ISuperGovernor\n function cancelOracleProviderRemoval() external onlyRole(_ORACLE_MANAGER_ROLE) {\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).cancelProviderRemoval();\n }\n\n /// @inheritdoc ISuperGovernor\n function executeOracleProviderRemoval() external onlyRole(_ORACLE_MANAGER_ROLE) {\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperOracle(oracle).executeProviderRemoval();\n }\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function proposeFee(FeeType feeType, uint256 value) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n if (value > BPS_MAX) revert INVALID_FEE_VALUE();\n\n FeeData storage feeData = _feeData[feeType];\n // casting to 'uint128' is safe because value is validated to be <= BPS_MAX (10000)\n // forge-lint: disable-next-line(unsafe-typecast)\n feeData.proposedValue = uint128(value);\n feeData.effectiveTime = block.timestamp + TIMELOCK;\n\n emit FeeProposed(feeType, value, feeData.effectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function executeFeeUpdate(FeeType feeType) external {\n FeeData storage feeData = _feeData[feeType];\n uint256 effectiveTime = feeData.effectiveTime;\n if (effectiveTime == 0) revert NO_PROPOSED_FEE(feeType);\n if (block.timestamp < effectiveTime) {\n revert TIMELOCK_NOT_EXPIRED();\n }\n\n // Update the fee value from proposed\n feeData.value = feeData.proposedValue;\n\n // Reset proposal data\n feeData.proposedValue = 0;\n feeData.effectiveTime = 0;\n\n emit FeeUpdated(feeType, feeData.value);\n }\n\n /// @inheritdoc ISuperGovernor\n function executeUpkeepClaim(uint256 amount) external onlyRole(_GOVERNOR_ROLE) {\n address aggregator = _addressRegistry[SUPER_VAULT_AGGREGATOR];\n if (aggregator == address(0)) revert CONTRACT_NOT_FOUND();\n\n ISuperVaultAggregator(aggregator).claimUpkeep(amount);\n }\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external onlyRole(_GAS_MANAGER_ROLE) {\n if (oracle == address(0)) revert INVALID_ADDRESS();\n if (gasIncreasePerEntryBatch == 0) revert INVALID_GAS_INFO();\n\n _gasPerEntry[oracle] = gasIncreasePerEntryBatch;\n emit GasInfoSet(oracle, gasIncreasePerEntryBatch);\n }\n\n /// @inheritdoc ISuperGovernor\n /// @notice Proposes a change to the upkeep payments enabled status\n /// @param enabled The proposed new status for upkeep payments\n function proposeUpkeepPaymentsChange(bool enabled) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n _proposedUpkeepPaymentsEnabled = enabled;\n _upkeepPaymentsChangeEffectiveTime = block.timestamp + TIMELOCK;\n\n emit UpkeepPaymentsChangeProposed(enabled, _upkeepPaymentsChangeEffectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n /// @notice Executes a previously proposed change to upkeep payments status after timelock expires\n function executeUpkeepPaymentsChange() external {\n if (_upkeepPaymentsChangeEffectiveTime == 0) revert NO_PENDING_CHANGE();\n if (block.timestamp < _upkeepPaymentsChangeEffectiveTime) revert TIMELOCK_NOT_EXPIRED();\n\n _upkeepPaymentsEnabled = _proposedUpkeepPaymentsEnabled;\n _upkeepPaymentsChangeEffectiveTime = 0;\n _proposedUpkeepPaymentsEnabled = false;\n\n emit UpkeepPaymentsChanged(_upkeepPaymentsEnabled);\n }\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function proposeMinStaleness(uint256 newMinStaleness) external onlyRole(_SUPER_GOVERNOR_ROLE) {\n _proposedMinStaleness = newMinStaleness;\n _minStalenessEffectiveTime = block.timestamp + TIMELOCK;\n\n emit MinStalenessProposed(newMinStaleness, _minStalenessEffectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function executeMinStalenessChange() external {\n uint256 minStalenessEffectiveTime = _minStalenessEffectiveTime;\n if (minStalenessEffectiveTime == 0) revert NO_PROPOSED_MIN_STALENESS();\n if (block.timestamp < minStalenessEffectiveTime) revert TIMELOCK_NOT_EXPIRED();\n\n _minStaleness = _proposedMinStaleness;\n\n // Reset proposal data\n _proposedMinStaleness = 0;\n _minStalenessEffectiveTime = 0;\n\n emit MinStalenessChanged(_minStaleness);\n }\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external onlyRole(_GOVERNOR_ROLE) {\n if (!_registeredHooks.contains(hook)) revert HOOK_NOT_APPROVED();\n if (proposedRoot == bytes32(0)) revert ZERO_PROPOSED_MERKLE_ROOT();\n\n uint256 effectiveTime = block.timestamp + TIMELOCK;\n ISuperGovernor.HookMerkleRootData storage data = superBankHooksMerkleRoots[hook];\n data.proposedRoot = proposedRoot;\n data.effectiveTime = effectiveTime;\n\n emit SuperBankHookMerkleRootProposed(hook, proposedRoot, effectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function executeSuperBankHookMerkleRootUpdate(address hook) external {\n if (!_registeredHooks.contains(hook)) revert HOOK_NOT_APPROVED();\n\n ISuperGovernor.HookMerkleRootData storage data = superBankHooksMerkleRoots[hook];\n\n // Check if there's a proposed update\n bytes32 proposedRoot = data.proposedRoot;\n if (proposedRoot == bytes32(0)) revert NO_PROPOSED_MERKLE_ROOT();\n\n // Check if the effective time has passed\n if (block.timestamp < data.effectiveTime) revert TIMELOCK_NOT_EXPIRED();\n\n // Update the Merkle root\n data.currentRoot = proposedRoot;\n\n // Reset the proposal\n data.proposedRoot = bytes32(0);\n data.effectiveTime = 0;\n\n emit SuperBankHookMerkleRootUpdated(hook, proposedRoot);\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperGovernor\n function SUPER_GOVERNOR_ROLE() external pure returns (bytes32) {\n return _SUPER_GOVERNOR_ROLE;\n }\n\n /// @inheritdoc ISuperGovernor\n function GOVERNOR_ROLE() external pure returns (bytes32) {\n return _GOVERNOR_ROLE;\n }\n\n /// @inheritdoc ISuperGovernor\n function BANK_MANAGER_ROLE() external pure returns (bytes32) {\n return _BANK_MANAGER_ROLE;\n }\n\n /// @inheritdoc ISuperGovernor\n function GAS_MANAGER_ROLE() external pure returns (bytes32) {\n return _GAS_MANAGER_ROLE;\n }\n\n /// @inheritdoc ISuperGovernor\n function ORACLE_MANAGER_ROLE() external pure returns (bytes32) {\n return _ORACLE_MANAGER_ROLE;\n }\n\n /// @inheritdoc ISuperGovernor\n function GUARDIAN_ROLE() external pure returns (bytes32) {\n return _GUARDIAN_ROLE;\n }\n\n /// @inheritdoc ISuperGovernor\n function getAddress(bytes32 key) external view returns (address) {\n address value = _addressRegistry[key];\n if (value == address(0)) revert CONTRACT_NOT_FOUND();\n return value;\n }\n\n /// @inheritdoc ISuperGovernor\n function isManagerTakeoverFrozen() external view returns (bool) {\n return _managerTakeoversFrozen;\n }\n\n /// @inheritdoc ISuperGovernor\n function isHookRegistered(address hook) external view returns (bool) {\n return _registeredHooks.contains(hook);\n }\n\n /// @inheritdoc ISuperGovernor\n function getRegisteredHooks() external view returns (address[] memory) {\n return _registeredHooks.values();\n }\n\n /// @inheritdoc ISuperGovernor\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum)\n {\n return (\n _validatorConfig.version,\n _validatorConfig.validators.values(),\n _validatorConfig.validatorPublicKeys,\n _validatorConfig.quorum\n );\n }\n\n /// @inheritdoc ISuperGovernor\n function isValidator(address validator) external view returns (bool) {\n return _validatorConfig.validators.contains(validator);\n }\n\n /// @inheritdoc ISuperGovernor\n function isGuardian(address guardian) external view returns (bool) {\n return hasRole(_GUARDIAN_ROLE, guardian);\n }\n\n /// @inheritdoc ISuperGovernor\n function getValidators() external view returns (address[] memory) {\n return _validatorConfig.validators.values();\n }\n\n /// @inheritdoc ISuperGovernor\n function getValidatorsCount() external view returns (uint256) {\n return _validatorConfig.validators.length();\n }\n\n /// @inheritdoc ISuperGovernor\n function getValidatorAt(uint256 index) external view returns (address) {\n return _validatorConfig.validators.at(index);\n }\n\n /// @inheritdoc ISuperGovernor\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime) {\n return (_proposedActivePPSOracle, _activePPSOracleEffectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function getPPSOracleQuorum() external view returns (uint256) {\n return _validatorConfig.quorum;\n }\n\n /// @inheritdoc ISuperGovernor\n function getActivePPSOracle() external view returns (address) {\n if (_activePPSOracle == address(0)) revert NO_ACTIVE_PPS_ORACLE();\n return _activePPSOracle;\n }\n\n /// @inheritdoc ISuperGovernor\n function isActivePPSOracle(address oracle) external view returns (bool) {\n return oracle == _activePPSOracle;\n }\n\n /// @inheritdoc ISuperGovernor\n function getFee(FeeType feeType) external view returns (uint256) {\n return _feeData[feeType].value;\n }\n\n /// @inheritdoc ISuperGovernor\n function getGasInfo(address oracle_) external view returns (uint256) {\n return _gasPerEntry[oracle_];\n }\n\n /// @inheritdoc ISuperGovernor\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256) {\n return _convertGasToUpkeepToken(_gasPerEntry[oracle_]);\n }\n\n /// @inheritdoc ISuperGovernor\n function getMinStaleness() external view returns (uint256) {\n return _minStaleness;\n }\n\n /// @inheritdoc ISuperGovernor\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime) {\n return (_proposedMinStaleness, _minStalenessEffectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32) {\n if (!_registeredHooks.contains(hook)) revert HOOK_NOT_APPROVED();\n return superBankHooksMerkleRoots[hook].currentRoot;\n }\n\n /// @inheritdoc ISuperGovernor\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime)\n {\n if (!_registeredHooks.contains(hook)) revert HOOK_NOT_APPROVED();\n ISuperGovernor.HookMerkleRootData storage data = superBankHooksMerkleRoots[hook];\n return (data.proposedRoot, data.effectiveTime);\n }\n\n /// @inheritdoc ISuperGovernor\n function isUpkeepPaymentsEnabled() external view returns (bool enabled) {\n return _upkeepPaymentsEnabled;\n }\n\n /// @inheritdoc ISuperGovernor\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime) {\n return (_proposedUpkeepPaymentsEnabled, _upkeepPaymentsChangeEffectiveTime);\n }\n\n /// @dev Advertise ISuperGovernor support for ERC-165 detection\n function supportsInterface(bytes4 interfaceId) public view override(AccessControl) returns (bool) {\n return interfaceId == type(ISuperGovernor).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Converts gas units to UPKEEP_TOKEN cost using multi-step oracle pricing\n /// @dev Performs 3 oracle conversions: Gas->Native, Native->USD, USD->UPKEEP_TOKEN\n /// @dev Uses AVERAGE_PROVIDER for all price feeds to ensure consistency\n /// @dev Uses Math.Rounding.Ceil to ensure sufficient upkeep coverage\n /// @dev Dynamically queries token decimals to support tokens with different decimal places (e.g., USDC=6, WETH=18)\n /// @param gasAmount The gas units to convert\n /// @return requiredUpkeepTokens The equivalent amount in UPKEEP_TOKEN (token's native decimals)\n function _convertGasToUpkeepToken(uint256 gasAmount) internal view returns (uint256) {\n address oracle = _addressRegistry[SUPER_ORACLE];\n if (oracle == address(0)) revert SUPER_ORACLE_NOT_FOUND();\n address upkeepToken = _addressRegistry[UPKEEP_TOKEN];\n if (upkeepToken == address(0)) revert UPKEEP_TOKEN_NOT_FOUND();\n\n // Get the upkeep token's decimals dynamically\n uint8 tokenDecimals = IERC20Metadata(upkeepToken).decimals();\n uint256 tokenUnit = 10 ** tokenDecimals;\n\n // Step 1: convert gas to native token (wei)\n (uint256 weiAmount,,,) =\n ISuperOracle(oracle).getQuoteFromProvider(gasAmount, GAS_QUOTE, WEI_QUOTE, AVERAGE_PROVIDER);\n\n // Step 2: convert native token to USD\n (uint256 nativeToUsd,,,) =\n ISuperOracle(oracle).getQuoteFromProvider(weiAmount, NATIVE_TOKEN, USD_TOKEN, AVERAGE_PROVIDER);\n\n // Step 3: convert USD to UPKEEP_TOKEN (how much USD per 1 UPKEEP_TOKEN)\n (uint256 usdPerUpkeepToken,,,) = ISuperOracle(oracle)\n .getQuoteFromProvider(\n tokenUnit, // 1 UPKEEP_TOKEN (using actual decimals)\n upkeepToken,\n USD_TOKEN,\n AVERAGE_PROVIDER\n );\n\n // Calculate required UPKEEP_TOKEN\n // (usdAmount * tokenUnit) / usdPerUpkeepToken = required UPKEEP_TOKEN\n // Simplifies to: usdAmount / (usdPerUpkeepToken / tokenUnit) = tokens needed\n return Math.mulDiv(nativeToUsd, tokenUnit, usdPerUpkeepToken, Math.Rounding.Ceil);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/AccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {IERC165, ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account => bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\nimport {Math} from \"../math/Math.sol\";\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * The following types are supported:\n *\n * - `bytes32` (`Bytes32Set`) since v3.3.0\n * - `address` (`AddressSet`) since v3.3.0\n * - `uint256` (`UintSet`) since v3.3.0\n * - `string` (`StringSet`) since v5.4.0\n * - `bytes` (`BytesSet`) since v5.4.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that\n * using it may render the function uncallable if the set grows to the point where clearing it consumes too much\n * gas to fit in a block.\n */\n function _clear(Set storage set) private {\n uint256 len = _length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {\n unchecked {\n end = Math.min(end, _length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes32[] memory result = new bytes32[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(Bytes32Set storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(AddressSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(UintSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n struct StringSet {\n // Storage of set values\n string[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(string value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(StringSet storage set, string memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(StringSet storage set, string memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n string memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(StringSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(StringSet storage set, string memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(StringSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(StringSet storage set, uint256 index) internal view returns (string memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set) internal view returns (string[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n string[] memory result = new string[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n struct BytesSet {\n // Storage of set values\n bytes[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(BytesSet storage set, bytes memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(BytesSet storage set, bytes memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(BytesSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(BytesSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set) internal view returns (bytes[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes[] memory result = new bytes[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"src/interfaces/ISuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n/// @notice Enum representing different types of fees that can be managed\nenum FeeType {\n REVENUE_SHARE,\n PERFORMANCE_FEE_SHARE\n}\n/// @title ISuperGovernor\n/// @author Superform Labs\n/// @notice Interface for the SuperGovernor contract\n/// @dev Central registry for all deployed contracts in the Superform periphery\n\ninterface ISuperGovernor is IAccessControl {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Structure containing Merkle root data for a hook\n struct HookMerkleRootData {\n bytes32 currentRoot; // Current active Merkle root for the hook\n bytes32 proposedRoot; // Proposed new Merkle root (zero if no proposal exists)\n uint256 effectiveTime; // Timestamp when the proposed root becomes effective\n }\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when trying to access a contract that is not registered\n error CONTRACT_NOT_FOUND();\n /// @notice Thrown when providing an invalid address (typically zero address)\n error INVALID_ADDRESS();\n /// @notice Thrown when a hook is not approved but expected to be\n error HOOK_NOT_APPROVED();\n /// @notice Thrown when an invalid fee value is proposed (must be <= BPS_MAX)\n error INVALID_FEE_VALUE();\n /// @notice Thrown when no proposed fee exists but one is expected\n error NO_PROPOSED_FEE(FeeType feeType);\n /// @notice Thrown when timelock period has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when a validator is already registered\n error VALIDATOR_ALREADY_REGISTERED();\n /// @notice Thrown when trying to change active PPS oracle directly\n error MUST_USE_TIMELOCK_FOR_CHANGE();\n /// @notice Thrown when a SuperBank hook Merkle root is not registered but expected to be\n /// @dev This error is defined here for use by other contracts in the system (SuperVaultStrategy,\n /// SuperVaultAggregator, ECDSAPPSOracle)\n error INVALID_TIMESTAMP();\n /// @notice Thrown when attempting to set an invalid quorum value (typically zero)\n error INVALID_QUORUM();\n /// @notice Thrown when validator and public key array lengths don't match\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when trying to set validator config with an empty validator array\n error EMPTY_VALIDATOR_ARRAY();\n /// @notice Thrown when no active PPS oracle is set but one is required\n error NO_ACTIVE_PPS_ORACLE();\n /// @notice Thrown when no proposed PPS oracle exists but one is expected\n error NO_PROPOSED_PPS_ORACLE();\n /// @notice Error thrown when manager takeovers are frozen\n error MANAGER_TAKEOVERS_FROZEN();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error NO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error ZERO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed minimum staleness exists but one is expected\n error NO_PROPOSED_MIN_STALENESS();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when there's no pending change but one is expected\n error NO_PENDING_CHANGE();\n /// @notice Thrown when the super oracle is not found\n error SUPER_ORACLE_NOT_FOUND();\n /// @notice Thrown when the up token is not found\n error UP_NOT_FOUND();\n /// @notice Thrown when the upkeep token is not found\n error UPKEEP_TOKEN_NOT_FOUND();\n /// @notice Thrown when the gas info is invalid\n error INVALID_GAS_INFO();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an address is set in the registry\n /// @param key The key used to reference the address\n /// @param oldValue The old address value\n /// @param value The address value\n event AddressSet(bytes32 indexed key, address indexed oldValue, address indexed value);\n\n /// @notice Emitted when a hook is approved\n /// @param hook The address of the approved hook\n event HookApproved(address indexed hook);\n\n /// @notice Emitted when validator configuration is set\n /// @param version The version of the configuration\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys (for signature verification)\n /// @param quorum The quorum required for validator consensus\n /// @param offchainConfig Offchain configuration data\n event ValidatorConfigSet(\n uint256 version, address[] validators, bytes[] validatorPublicKeys, uint256 quorum, bytes offchainConfig\n );\n\n /// @notice Emitted when a hook is removed\n /// @param hook The address of the removed hook\n event HookRemoved(address indexed hook);\n\n /// @notice Emitted when a new fee is proposed\n /// @param feeType The type of fee being proposed\n /// @param value The proposed fee value (in basis points)\n /// @param effectiveTime The timestamp when the fee will be effective\n event FeeProposed(FeeType indexed feeType, uint256 value, uint256 effectiveTime);\n\n /// @notice Emitted when a fee is updated\n /// @param feeType The type of fee being updated\n /// @param value The new fee value (in basis points)\n event FeeUpdated(FeeType indexed feeType, uint256 value);\n\n /// @notice Emitted when a new SuperBank hook Merkle root is proposed\n /// @param hook The hook address for which the Merkle root is being proposed\n /// @param newRoot The new Merkle root\n /// @param effectiveTime The timestamp when the new root will be effective\n event SuperBankHookMerkleRootProposed(address indexed hook, bytes32 newRoot, uint256 effectiveTime);\n\n /// @notice Emitted when the SuperBank hook Merkle root is updated.\n /// @param hook The address of the hook for which the Merkle root was updated.\n /// @param newRoot The new Merkle root.\n event SuperBankHookMerkleRootUpdated(address indexed hook, bytes32 newRoot);\n\n /// @notice Emitted when an active PPS oracle is initially set\n /// @param oracle The address of the set oracle\n event ActivePPSOracleSet(address indexed oracle);\n\n /// @notice Emitted when a new PPS oracle is proposed\n /// @param oracle The address of the proposed oracle\n /// @param effectiveTime The timestamp when the proposal will be effective\n event ActivePPSOracleProposed(address indexed oracle, uint256 effectiveTime);\n\n /// @notice Emitted when the active PPS oracle is changed\n /// @param oldOracle The address of the previous oracle\n /// @param newOracle The address of the new oracle\n event ActivePPSOracleChanged(address indexed oldOracle, address indexed newOracle);\n\n /// @notice Event emitted when manager takeovers are permanently frozen\n event ManagerTakeoversFrozen();\n\n /// @notice Emitted when a change to upkeep payments status is proposed\n /// @param enabled The proposed status (enabled/disabled)\n /// @param effectiveTime The timestamp when the status change will be effective\n event UpkeepPaymentsChangeProposed(bool enabled, uint256 effectiveTime);\n\n /// @notice Emitted when upkeep payments status is changed\n /// @param enabled The new status (enabled/disabled)\n event UpkeepPaymentsChanged(bool enabled);\n\n /// @notice Emitted when a new minimum staleness is proposed\n /// @param newMinStaleness The proposed minimum staleness value\n /// @param effectiveTime The timestamp when the new value will be effective\n event MinStalenessProposed(uint256 newMinStaleness, uint256 effectiveTime);\n\n /// @notice Emitted when the minimum staleness is changed\n /// @param newMinStaleness The new minimum staleness value\n event MinStalenessChanged(uint256 newMinStaleness);\n\n /// @notice Emitted when gas info is set\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n event GasInfoSet(address indexed oracle, uint256 gasIncreasePerEntryBatch);\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets an address in the registry\n /// @param key The key to associate with the address\n /// @param value The address value\n function setAddress(bytes32 key, address value) external;\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Change the primary manager for a strategy\n /// @dev Only SuperGovernor can call this function directly\n /// @param strategy The strategy address\n /// @param newManager The new primary manager address\n /// @param feeRecipient The new fee recipient address\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Resets the high-water mark PPS to the current PPS\n /// @dev Only SuperGovernor can call this function\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value for the given strategy\n /// @param strategy Address of the strategy to reset the high-water mark for\n function resetHighWaterMark(address strategy) external;\n\n /// @notice Permanently freezes all manager takeovers globally\n function freezeManagerTakeover() external;\n\n /// @notice Changes the hooks root update timelock duration\n /// @param newTimelock New timelock duration in seconds\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes a new global hooks Merkle root\n /// @dev Only GOVERNOR_ROLE can call this function\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Sets veto status for global hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Sets veto status for a strategy-specific hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param strategy Address of the strategy to affect\n /// @param vetoed Whether to veto (true) or unveto (false) the strategy hooks root\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Sets the maximum staleness period for all oracle feeds\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleMaxStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness period for a specific oracle feed\n /// @param feed The address of the feed to set staleness for\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness periods for multiple oracle feeds in batch\n /// @param feeds The addresses of the feeds to set staleness for\n /// @param newMaxStalenessList The new maximum staleness periods in seconds\n function setOracleFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Queues an oracle update for execution after timelock period\n /// @param bases Base asset addresses\n /// @param quotes Quote asset addresses\n /// @param providers Provider identifiers\n /// @param feeds Feed addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Executes a previously queued oracle update after timelock has expired\n function executeOracleUpdate() external;\n\n /// @notice Queues a provider removal for execution after timelock period\n /// @param providers The providers to remove\n function queueOracleProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Sets uptime feeds for multiple data oracles in batch (Layer 2 only)\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Registers a hook for use in SuperVaults\n /// @param hook The address of the hook to register\n function registerHook(address hook) external;\n\n /// @notice Unregisters a hook from the approved list\n /// @param hook The address of the hook to unregister\n function unregisterHook(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the validator configuration for the protocol\n /// @dev This function atomically updates all validator configuration including quorum.\n /// The entire validator set is replaced (not incrementally updated).\n /// Version must be managed externally for cross-chain synchronization.\n /// Quorum updates require providing the full validator list.\n /// @param version The version number for the configuration (for cross-chain sync)\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys for signature verification\n /// @param quorum The number of validators required for consensus\n /// @param offchainConfig Offchain configuration data (emitted but not stored)\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the active PPS oracle (only if there is no active oracle yet)\n /// @param oracle Address of the PPS oracle to set as active\n function setActivePPSOracle(address oracle) external;\n\n /// @notice Proposes a new active PPS oracle (when there is already an active one)\n /// @param oracle Address of the PPS oracle to propose as active\n function proposeActivePPSOracle(address oracle) external;\n\n /// @notice Executes a previously proposed PPS oracle change after timelock has expired\n function executeActivePPSOracleChange() external;\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new fee value\n /// @param feeType The type of fee to propose\n /// @param value The proposed fee value (in basis points)\n function proposeFee(FeeType feeType, uint256 value) external;\n\n /// @notice Executes a previously proposed fee update after timelock has expired\n /// @param feeType The type of ffee to execute the update for\n function executeFeeUpdate(FeeType feeType) external;\n\n /// @notice Executes an upkeep claim on `SuperVaultAggregator`\n /// @param amount The amount to claim\n function executeUpkeepClaim(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets gas info for an oracle\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external;\n\n /// @notice Proposes a change to upkeep payments enabled status\n /// @param enabled The proposed enabled status\n function proposeUpkeepPaymentsChange(bool enabled) external;\n\n /// @notice Executes a previously proposed upkeep payments status change\n function executeUpkeepPaymentsChange() external;\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new minimum staleness value to prevent maxStaleness from being set too low\n /// @param newMinStaleness The proposed new minimum staleness value in seconds\n function proposeMinStaleness(uint256 newMinStaleness) external;\n\n /// @notice Executes a previously proposed minimum staleness change after timelock has expired\n function executeMinStalenessChange() external;\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to update the Merkle root for.\n /// @param proposedRoot The proposed new Merkle root.\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external;\n\n /// @notice Executes a previously proposed Merkle root update for a specific hook if the effective time has passed.\n /// @param hook The address of the hook to execute the update for.\n function executeSuperBankHookMerkleRootUpdate(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice The identifier of the role that grants access to critical governance functions\n function SUPER_GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to daily operations like hooks and validators\n function GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to bank management functions\n function BANK_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to gas management functions\n function GAS_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to oracle management functions\n function ORACLE_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to guardian functions\n function GUARDIAN_ROLE() external view returns (bytes32);\n\n /// @notice Gets an address from the registry\n /// @param key The key of the address to get\n /// @return The address value\n function getAddress(bytes32 key) external view returns (address);\n\n /// @notice Checks if manager takeovers are frozen\n /// @return True if manager takeovers are frozen, false otherwise\n function isManagerTakeoverFrozen() external view returns (bool);\n\n /// @notice Checks if a hook is registered\n /// @param hook The address of the hook to check\n /// @return True if the hook is registered, false otherwise\n function isHookRegistered(address hook) external view returns (bool);\n\n /// @notice Gets all registered hooks\n /// @return An array of registered hook addresses\n function getRegisteredHooks() external view returns (address[] memory);\n\n /// @notice Checks if an address is an approved validator\n /// @param validator The address to check\n /// @return True if the address is an approved validator, false otherwise\n function isValidator(address validator) external view returns (bool);\n\n /// @notice Checks if an address has the guardian role\n /// @param guardian Address to check\n /// @return true if the address has the GUARDIAN_ROLE\n function isGuardian(address guardian) external view returns (bool);\n\n /// @notice Returns the complete validator configuration\n /// @return version The current configuration version number\n /// @return validators Array of all registered validator addresses\n /// @return validatorPublicKeys Array of validator public keys\n /// @return quorum The number of validators required for consensus\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum);\n\n /// @notice Returns all registered validators\n /// @return List of validator addresses\n function getValidators() external view returns (address[] memory);\n\n /// @notice Returns the number of registered validators (O(1))\n function getValidatorsCount() external view returns (uint256);\n\n /// @notice Returns a validator address by index (0 … count-1)\n /// @param index The index into the validators set\n /// @return validator The validator address at the given index\n function getValidatorAt(uint256 index) external view returns (address validator);\n\n /// @notice Gets the proposed active PPS oracle and its effective time\n /// @return proposedOracle The proposed oracle address\n /// @return effectiveTime The timestamp when the proposed oracle will become effective\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime);\n\n /// @notice Gets the current quorum requirement for the active PPS Oracle\n /// @return The current quorum requirement\n function getPPSOracleQuorum() external view returns (uint256);\n\n /// @notice Gets the active PPS oracle\n /// @return The active PPS oracle address\n function getActivePPSOracle() external view returns (address);\n\n /// @notice Checks if an address is the current active PPS oracle\n /// @param oracle The address to check\n /// @return True if the address is the active PPS oracle, false otherwise\n function isActivePPSOracle(address oracle) external view returns (bool);\n\n /// @notice Gets the current fee value for a specific fee type\n /// @param feeType The type of fee to get\n /// @return The current fee value (in basis points)\n function getFee(FeeType feeType) external view returns (uint256);\n\n /// @notice Gets the current upkeep cost for an entry\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256);\n\n /// @notice Gets the proposed upkeep cost per update and its effective time\n /// @notice Gets the current minimum staleness value\n /// @return The current minimum staleness value in seconds\n function getMinStaleness() external view returns (uint256);\n\n /// @notice Gets the proposed minimum staleness value and its effective time\n /// @return proposedMinStaleness The proposed new minimum staleness value\n /// @return effectiveTime The timestamp when the new value will become effective\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime);\n\n /// @notice Returns the current Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to get the Merkle root for.\n /// @return The Merkle root for the hook's allowed targets.\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32);\n\n /// @notice Gets the proposed Merkle root and its effective time for a specific hook.\n /// @param hook The address of the hook to get the proposed Merkle root for.\n /// @return proposedRoot The proposed Merkle root.\n /// @return effectiveTime The timestamp when the proposed root will become effective.\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime);\n\n /// @notice Checks if upkeep payments are currently enabled\n /// @return enabled True if upkeep payments are enabled\n function isUpkeepPaymentsEnabled() external view returns (bool);\n\n /// @notice Gets the proposed upkeep payments status and effective time\n /// @return enabled The proposed status\n /// @return effectiveTime The timestamp when the change becomes effective\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime);\n\n /// @notice Gets the SUP strategy ID\n /// @return The ID of the SUP strategy vault\n function SUP_STRATEGY() external view returns (bytes32);\n\n /// @notice Gets the UP ID\n /// @return The ID of the UP token\n function UP() external view returns (bytes32);\n\n /// @notice Gets the UPKEEP_TOKEN ID\n /// @return The ID of the UPKEEP_TOKEN (used for upkeep payments, can be UP on mainnet or WETH/USDC on L2s)\n function UPKEEP_TOKEN() external view returns (bytes32);\n\n /// @notice Gets the Treasury ID\n /// @return The ID for the Treasury in the registry\n function TREASURY() external view returns (bytes32);\n\n /// @notice Gets the SuperOracle ID\n /// @return The ID for the SuperOracle in the registry\n function SUPER_ORACLE() external view returns (bytes32);\n\n /// @notice Gets the ECDSA PPS Oracle ID\n /// @return The ID for the ECDSA PPS Oracle in the registry\n function ECDSAPPSORACLE() external view returns (bytes32);\n\n /// @notice Gets the SuperVaultAggregator ID\n /// @return The ID for the SuperVaultAggregator in the registry\n function SUPER_VAULT_AGGREGATOR() external view returns (bytes32);\n\n /// @notice Gets the SuperBank ID\n /// @return The ID for the SuperBank in the registry\n function SUPER_BANK() external view returns (bytes32);\n\n /// @notice Gets the gas info for a specific SuperVault PPS Oracle\n /// @param oracle_ The address of the oracle to get gas info for\n /// @return The gas info for the specified oracle\n function getGasInfo(address oracle_) external view returns (uint256);\n\n /// @notice Cancels a previously proposed oracle provider removal\n function cancelOracleProviderRemoval() external;\n\n /// @notice Executes a previously proposed oracle provider removal after timelock has expired\n function executeOracleProviderRemoval() external;\n}\n"},"src/interfaces/SuperVault/ISuperVaultAggregator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { ISuperVaultStrategy } from \"../SuperVault/ISuperVaultStrategy.sol\";\n\n/// @title ISuperVaultAggregator\n/// @author Superform Labs\n/// @notice Interface for the SuperVaultAggregator contract\n/// @dev Registry and PPS oracle for all SuperVaults\ninterface ISuperVaultAggregator {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for forwarding PPS updates to avoid stack too deep errors\n /// @param strategy Address of the strategy being updated\n /// @param isExempt Whether the update is exempt from paying upkeep\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp when the value was generated\n /// @param upkeepCost Amount of upkeep tokens to charge if not exempt\n struct PPSUpdateData {\n address strategy;\n bool isExempt;\n uint256 pps;\n uint256 timestamp;\n uint256 upkeepCost;\n }\n\n /// @notice Local variables for vault creation to avoid stack too deep\n /// @param currentNonce Current vault creation nonce\n /// @param salt Salt for deterministic proxy creation\n /// @param initialPPS Initial price-per-share value\n struct VaultCreationLocalVars {\n uint256 currentNonce;\n bytes32 salt;\n uint256 initialPPS;\n }\n\n /// @notice Strategy configuration and state data\n /// @param pps Current price-per-share value\n /// @param lastUpdateTimestamp Last time PPS was updated\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param isPaused Whether the strategy is paused\n /// @param mainManager Address of the primary manager controlling the strategy\n /// @param secondaryManagers Set of secondary managers that can manage the strategy\n struct StrategyData {\n uint256 pps; // Slot 0: 32 bytes\n uint256 lastUpdateTimestamp; // Slot 1: 32 bytes\n uint256 minUpdateInterval; // Slot 2: 32 bytes\n uint256 maxStaleness; // Slot 3: 32 bytes\n // Packed slot 4: saves 2 storage slots (~4000 gas per read)\n address mainManager; // 20 bytes\n bool ppsStale; // 1 byte\n bool isPaused; // 1 byte\n bool hooksRootVetoed; // 1 byte\n uint72 __gap1; // 9 bytes padding\n EnumerableSet.AddressSet secondaryManagers;\n // Manager change proposal data\n address proposedManager;\n address proposedFeeRecipient;\n uint256 managerChangeEffectiveTime;\n // Hook validation data\n bytes32 managerHooksRoot;\n // Hook root update proposal data\n bytes32 proposedHooksRoot;\n uint256 hooksRootEffectiveTime;\n // PPS Verification thresholds\n uint256 deviationThreshold; // Threshold for abs(new - current) / current\n // Banned global leaves mapping\n mapping(bytes32 => bool) bannedLeaves; // Mapping of leaf hash to banned status\n // Min update interval proposal data\n uint256 proposedMinUpdateInterval;\n uint256 minUpdateIntervalEffectiveTime;\n uint256 lastUnpauseTimestamp; // Timestamp of last unpause (for skim timelock)\n }\n\n /// @notice Parameters for creating a new SuperVault trio\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param mainManager Address of the vault mainManager\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param feeConfig Fee configuration for the vault\n struct VaultCreationParams {\n address asset;\n string name;\n string symbol;\n address mainManager;\n address[] secondaryManagers;\n uint256 minUpdateInterval;\n uint256 maxStaleness;\n ISuperVaultStrategy.FeeConfig feeConfig;\n }\n\n /// @notice Struct to hold cached hook validation state variables to avoid stack too deep\n /// @param globalHooksRootVetoed Cached global hooks root veto status\n /// @param globalHooksRoot Cached global hooks root\n /// @param strategyHooksRootVetoed Cached strategy hooks root veto status\n /// @param strategyRoot Cached strategy hooks root\n struct HookValidationCache {\n bool globalHooksRootVetoed;\n bytes32 globalHooksRoot;\n bool strategyHooksRootVetoed;\n bytes32 strategyRoot;\n }\n\n /// @notice Arguments for validating a hook to avoid stack too deep\n /// @param hookAddress Address of the hook contract\n /// @param hookArgs Encoded arguments for the hook operation\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n struct ValidateHookArgs {\n address hookAddress;\n bytes hookArgs;\n bytes32[] globalProof;\n bytes32[] strategyProof;\n }\n\n /// @notice Two-step upkeep withdrawal request\n /// @param amount Amount to withdraw (full balance at time of request)\n /// @param effectiveTime When withdrawal can be executed (timestamp + 24h)\n struct UpkeepWithdrawalRequest {\n uint256 amount;\n uint256 effectiveTime;\n }\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when a new vault trio is created\n /// @param vault Address of the created SuperVault\n /// @param strategy Address of the created SuperVaultStrategy\n /// @param escrow Address of the created SuperVaultEscrow\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param nonce The nonce used for vault creation\n event VaultDeployed(\n address indexed vault,\n address indexed strategy,\n address escrow,\n address asset,\n string name,\n string symbol,\n uint256 indexed nonce\n );\n\n /// @notice Emitted when a PPS value is updated\n /// @param strategy Address of the strategy\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp of the update\n event PPSUpdated(address indexed strategy, uint256 pps, uint256 timestamp);\n\n /// @notice Emitted when a strategy is paused due to missed updates\n /// @param strategy Address of the paused strategy\n event StrategyPaused(address indexed strategy);\n\n /// @notice Emitted when a strategy is unpaused\n /// @param strategy Address of the unpaused strategy\n event StrategyUnpaused(address indexed strategy);\n\n /// @notice Emitted when a strategy validation check fails but execution continues\n /// @param strategy Address of the strategy that failed the check\n /// @param reason String description of which check failed\n event StrategyCheckFailed(address indexed strategy, string reason);\n\n /// @notice Emitted when upkeep tokens are deposited\n /// @param strategy Address of the strategy\n /// @param depositor Address of the depositor\n /// @param amount Amount of upkeep tokens deposited\n event UpkeepDeposited(address indexed strategy, address indexed depositor, uint256 amount);\n\n /// @notice Emitted when upkeep tokens are withdrawn\n /// @param strategy Address of the strategy\n /// @param withdrawer Address of the withdrawer (main manager of the strategy)\n /// @param amount Amount of upkeep tokens withdrawn\n event UpkeepWithdrawn(address indexed strategy, address indexed withdrawer, uint256 amount);\n\n /// @notice Emitted when an upkeep withdrawal is proposed (start of 24h timelock)\n /// @param strategy Address of the strategy\n /// @param mainManager Address of the main manager who proposed the withdrawal\n /// @param amount Amount of upkeep tokens to withdraw\n /// @param effectiveTime Timestamp when withdrawal can be executed\n event UpkeepWithdrawalProposed(\n address indexed strategy, address indexed mainManager, uint256 amount, uint256 effectiveTime\n );\n\n /// @notice Emitted when a pending upkeep withdrawal is cancelled (e.g., during governance takeover)\n /// @param strategy Address of the strategy\n event UpkeepWithdrawalCancelled(address indexed strategy);\n\n /// @notice Emitted when upkeep tokens are spent for validation\n /// @param strategy Address of the strategy\n /// @param amount Amount of upkeep tokens spent\n /// @param balance Current balance of the strategy\n /// @param claimableUpkeep Amount of upkeep tokens claimable\n event UpkeepSpent(address indexed strategy, uint256 amount, uint256 balance, uint256 claimableUpkeep);\n\n /// @notice Emitted when a secondary manager is added to a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager added\n event SecondaryManagerAdded(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a secondary manager is removed from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager removed\n event SecondaryManagerRemoved(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a primary manager is changed\n /// @param strategy Address of the strategy\n /// @param oldManager Address of the old primary manager\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n event PrimaryManagerChanged(\n address indexed strategy, address indexed oldManager, address indexed newManager, address feeRecipient\n );\n\n /// @notice Emitted when a change to primary manager is proposed by a secondary manager\n /// @param strategy Address of the strategy\n /// @param proposer Address of the secondary manager who made the proposal\n /// @param newManager Address of the proposed new primary manager\n /// @param effectiveTime Timestamp when the proposal can be executed\n event PrimaryManagerChangeProposed(\n address indexed strategy,\n address indexed proposer,\n address indexed newManager,\n address feeRecipient,\n uint256 effectiveTime\n );\n\n /// @notice Emitted when a primary manager change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledManager Address of the manager that was proposed\n event PrimaryManagerChangeCancelled(address indexed strategy, address indexed cancelledManager);\n\n /// @notice Emitted when the High Water Mark for a strategy is reset to PPS\n /// @param strategy Address of the strategy\n /// @param newHWM The new High Water Mark (PPS)\n event HighWaterMarkReset(address indexed strategy, uint256 indexed newHWM);\n\n /// @notice Emitted when a PPS update is stale (Validators could get slashed for innactivity)\n /// @param strategy Address of the strategy\n /// @param updateAuthority Address of the update authority\n /// @param timestamp Timestamp of the stale update\n event StaleUpdate(address indexed strategy, address indexed updateAuthority, uint256 timestamp);\n\n /// @notice Emitted when the global hooks Merkle root is being updated\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event GlobalHooksRootUpdateProposed(bytes32 indexed root, uint256 effectiveTime);\n\n /// @notice Emitted when the global hooks Merkle root is updated\n /// @param oldRoot Previous root value\n /// @param newRoot New root value\n event GlobalHooksRootUpdated(bytes32 indexed oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is updated\n /// @param strategy Address of the strategy\n /// @param oldRoot Previous root value (may be zero)\n /// @param newRoot New root value\n event StrategyHooksRootUpdated(address indexed strategy, bytes32 oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the account proposing the new root\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event StrategyHooksRootUpdateProposed(\n address indexed strategy, address indexed proposer, bytes32 root, uint256 effectiveTime\n );\n\n /// @notice Emitted when a proposed global hooks root update is vetoed by SuperGovernor\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event GlobalHooksRootVetoStatusChanged(bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's hooks Merkle root veto status changes\n /// @param strategy Address of the strategy\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event StrategyHooksRootVetoStatusChanged(address indexed strategy, bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's deviation threshold is updated\n /// @param strategy Address of the strategy\n /// @param deviationThreshold New deviation threshold (abs diff/current)\n event DeviationThresholdUpdated(address indexed strategy, uint256 deviationThreshold);\n\n /// @notice Emitted when the hooks root update timelock is changed\n /// @param newTimelock New timelock duration in seconds\n event HooksRootUpdateTimelockChanged(uint256 newTimelock);\n\n /// @notice Emitted when global leaves status is changed for a strategy\n /// @param strategy Address of the strategy\n /// @param leaves Array of leaf hashes that had their status changed\n /// @param statuses Array of new banned statuses (true = banned, false = allowed)\n event GlobalLeavesStatusChanged(address indexed strategy, bytes32[] leaves, bool[] statuses);\n\n /// @notice Emitted when upkeep is claimed\n /// @param superBank Address of the superBank\n /// @param amount Amount of upkeep claimed\n event UpkeepClaimed(address indexed superBank, uint256 amount);\n\n /// @notice Emitted when PPS update is too frequent (before minUpdateInterval)\n event UpdateTooFrequent();\n\n /// @notice Emitted when PPS update timestamp is not monotonically increasing\n event TimestampNotMonotonic();\n\n /// @notice Emitted when PPS update is rejected due to stale signature after unpause\n event StaleSignatureAfterUnpause(\n address indexed strategy, uint256 signatureTimestamp, uint256 lastUnpauseTimestamp\n );\n\n /// @notice Emitted when a strategy does not have enough upkeep balance\n event InsufficientUpkeep(address indexed strategy, address indexed strategyAddr, uint256 balance, uint256 cost);\n\n /// @notice Emitted when the provided timestamp is too large\n event ProvidedTimestampExceedsBlockTimestamp(\n address indexed strategy, uint256 argsTimestamp, uint256 blockTimestamp\n );\n\n /// @notice Emitted when a strategy is unknown\n event UnknownStrategy(address indexed strategy);\n\n /// @notice Emitted when the old primary manager is removed from the strategy\n /// @dev This can happen because of reaching the max number of secondary managers\n event OldPrimaryManagerRemoved(address indexed strategy, address indexed oldManager);\n\n /// @notice Emitted when a strategy's PPS is stale\n event StrategyPPSStale(address indexed strategy);\n\n /// @notice Emitted when a strategy's PPS is reset\n event StrategyPPSStaleReset(address indexed strategy);\n\n /// @notice Emitted when PPS is updated after performance fee skimming\n /// @param strategy Address of the strategy\n /// @param oldPPS Previous price-per-share value\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee skimmed that caused the PPS update\n /// @param timestamp Timestamp of the update\n event PPSUpdatedAfterSkim(\n address indexed strategy, uint256 oldPPS, uint256 newPPS, uint256 feeAmount, uint256 timestamp\n );\n\n /// @notice Emitted when a change to minUpdateInterval is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the manager who made the proposal\n /// @param newMinUpdateInterval The proposed new minimum update interval\n /// @param effectiveTime Timestamp when the proposal can be executed\n event MinUpdateIntervalChangeProposed(\n address indexed strategy, address indexed proposer, uint256 newMinUpdateInterval, uint256 effectiveTime\n );\n\n /// @notice Emitted when a minUpdateInterval change is executed\n /// @param strategy Address of the strategy\n /// @param oldMinUpdateInterval Previous minimum update interval\n /// @param newMinUpdateInterval New minimum update interval\n event MinUpdateIntervalChanged(\n address indexed strategy, uint256 oldMinUpdateInterval, uint256 newMinUpdateInterval\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is rejected due to validation failure\n /// @param strategy Address of the strategy\n /// @param proposedInterval The proposed interval that was rejected\n /// @param currentMaxStaleness The current maxStaleness value that caused rejection\n event MinUpdateIntervalChangeRejected(\n address indexed strategy, uint256 proposedInterval, uint256 currentMaxStaleness\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledInterval The proposed interval that was cancelled\n event MinUpdateIntervalChangeCancelled(address indexed strategy, uint256 cancelledInterval);\n\n /// @notice Emitted when a PPS update is rejected because strategy is paused\n /// @param strategy Address of the paused strategy\n event PPSUpdateRejectedStrategyPaused(address indexed strategy);\n\n /*///////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when address provided is zero\n error ZERO_ADDRESS();\n /// @notice Thrown when amount provided is zero\n error ZERO_AMOUNT();\n /// @notice Thrown when vault creation parameters are invalid (empty name or symbol)\n error INVALID_VAULT_PARAMS();\n /// @notice Thrown when array length is zero\n error ZERO_ARRAY_LENGTH();\n /// @notice Thrown when array length is zero\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when asset is invalid\n error INVALID_ASSET();\n /// @notice Thrown when insufficient upkeep balance for operation\n error INSUFFICIENT_UPKEEP();\n /// @notice Thrown when caller is not authorized\n error CALLER_NOT_AUTHORIZED();\n /// @notice Thrown when caller is not an approved PPS oracle\n error UNAUTHORIZED_PPS_ORACLE();\n /// @notice Thrown when caller is not authorized for update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n /// @notice Thrown when strategy address is not a known SuperVault strategy\n error UNKNOWN_STRATEGY();\n /// @notice Thrown when trying to unpause a strategy that is not paused\n error STRATEGY_NOT_PAUSED();\n /// @notice Thrown when trying to pause a strategy that is already paused\n error STRATEGY_ALREADY_PAUSED();\n /// @notice Thrown when array index is out of bounds\n error INDEX_OUT_OF_BOUNDS();\n /// @notice Thrown when attempting to add a manager that already exists\n error MANAGER_ALREADY_EXISTS();\n /// @notice Thrown when attempting to add a manager that is the primary manager\n error SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n /// @notice Thrown when there is no pending global hooks root change\n error NO_PENDING_GLOBAL_ROOT_CHANGE();\n /// @notice Thrown when attempting to execute a hooks root change before timelock has elapsed\n error ROOT_UPDATE_NOT_READY();\n /// @notice Thrown when a provided hook fails Merkle proof validation\n error HOOK_VALIDATION_FAILED();\n /// @notice Thrown when manager is not found\n error MANAGER_NOT_FOUND();\n /// @notice Thrown when there is no pending manager change proposal\n error NO_PENDING_MANAGER_CHANGE();\n /// @notice Thrown when caller is not authorized to update settings\n error UNAUTHORIZED_CALLER();\n /// @notice Thrown when the timelock for a proposed change has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when an array length is invalid\n error INVALID_ARRAY_LENGTH();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when arrays have mismatched lengths\n error MISMATCHED_ARRAY_LENGTHS();\n /// @notice Thrown when timestamp is invalid\n error INVALID_TIMESTAMP(uint256 index);\n /// @notice Thrown when too many secondary managers are added\n error TOO_MANY_SECONDARY_MANAGERS();\n /// @notice Thrown when upkeep withdrawal timelock has not passed yet\n error UPKEEP_WITHDRAWAL_NOT_READY();\n /// @notice Thrown when no pending upkeep withdrawal request exists\n error UPKEEP_WITHDRAWAL_NOT_FOUND();\n /// @notice PPS must decrease after skimming fees\n error PPS_MUST_DECREASE_AFTER_SKIM();\n /// @notice PPS deduction is larger than the maximum allowed fee rate\n error PPS_DEDUCTION_TOO_LARGE();\n /// @notice Thrown when no minUpdateInterval change proposal is pending\n error NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n /// @notice Thrown when minUpdateInterval >= maxStaleness\n error MIN_UPDATE_INTERVAL_TOO_HIGH();\n /// @notice Thrown when trying to update PPS while strategy is paused\n error STRATEGY_PAUSED();\n /// @notice Thrown when trying to update PPS while PPS is stale\n error PPS_STALE();\n\n /*//////////////////////////////////////////////////////////////\n VAULT CREATION\n //////////////////////////////////////////////////////////////*/\n /// @notice Creates a new SuperVault trio (SuperVault, SuperVaultStrategy, SuperVaultEscrow)\n /// @param params Parameters for the new vault creation\n /// @return superVault Address of the created SuperVault\n /// @return strategy Address of the created SuperVaultStrategy\n /// @return escrow Address of the created SuperVaultEscrow\n function createVault(VaultCreationParams calldata params)\n external\n returns (address superVault, address strategy, address escrow);\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for batch forwarding PPS updates\n /// @param strategies Array of strategy addresses\n /// @param ppss Array of price-per-share values\n /// @param timestamps Array of timestamps when values were generated\n /// @param updateAuthority Address of the update authority\n struct ForwardPPSArgs {\n address[] strategies;\n uint256[] ppss;\n uint256[] timestamps;\n address updateAuthority;\n }\n\n /// @notice Batch forwards validated PPS updates to multiple strategies\n /// @param args Struct containing all batch PPS update parameters\n function forwardPPS(ForwardPPSArgs calldata args) external;\n\n /// @notice Updates PPS directly after performance fee skimming\n /// @dev Only callable by the strategy contract itself (msg.sender must be a registered strategy)\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee that was skimmed (for event logging)\n function updatePPSAfterSkim(uint256 newPPS, uint256 feeAmount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Deposits upkeep tokens for strategy upkeep\n /// @dev The upkeep token is configurable per chain (UP on mainnet, WETH on L2s, etc.)\n /// @param strategy Address of the strategy to deposit for\n /// @param amount Amount of upkeep tokens to deposit\n function depositUpkeep(address strategy, uint256 amount) external;\n\n /// @notice Proposes withdrawal of upkeep tokens from strategy upkeep balance (starts 24h timelock)\n /// @dev Only the main manager can propose. Withdraws full balance at time of proposal.\n /// @param strategy Address of the strategy to withdraw from\n function proposeWithdrawUpkeep(address strategy) external;\n\n /// @notice Executes a pending upkeep withdrawal after 24h timelock\n /// @dev Anyone can execute, but funds go to the main manager of the strategy\n /// @param strategy Address of the strategy to withdraw from\n function executeWithdrawUpkeep(address strategy) external;\n\n /// @notice Claims upkeep tokens from the contract\n /// @param amount Amount of upkeep tokens to claim\n function claimUpkeep(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n PAUSE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Manually pauses a strategy\n /// @param strategy Address of the strategy to pause\n function pauseStrategy(address strategy) external;\n\n /// @notice Manually unpauses a strategy\n /// @param strategy Address of the strategy to unpause\n function unpauseStrategy(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER MANAGEMENT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Adds a secondary manager to a strategy\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to add\n function addSecondaryManager(address strategy, address manager) external;\n\n /// @notice Removes a secondary manager from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to remove\n function removeSecondaryManager(address strategy, address manager) external;\n\n /// @notice Changes the primary manager of a strategy immediately (only callable by SuperGovernor)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Proposes a change to the primary manager (callable by secondary managers)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the proposed new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function proposeChangePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Cancels a pending primary manager change proposal\n /// @dev Only the current primary manager can cancel the proposal\n /// @param strategy Address of the strategy\n function cancelChangePrimaryManager(address strategy) external;\n\n /// @notice Executes a previously proposed change to the primary manager after timelock\n /// @param strategy Address of the strategy\n function executeChangePrimaryManager(address strategy) external;\n\n /// @notice Resets the strategy's performance-fee high-water mark to PPS\n /// @dev Only callable by SuperGovernor\n /// @param strategy Address of the strategy\n function resetHighWaterMark(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK VALIDATION FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets a new hooks root update timelock duration\n /// @param newTimelock The new timelock duration in seconds\n function setHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes an update to the global hooks Merkle root\n /// @dev Only callable by SUPER_GOVERNOR\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed global hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeGlobalHooksRootUpdate() external;\n\n /// @notice Proposes an update to a strategy-specific hooks Merkle root\n /// @dev Only callable by the main manager for the strategy\n /// @param strategy Address of the strategy\n /// @param newRoot New Merkle root for strategy-specific hooks\n function proposeStrategyHooksRoot(address strategy, bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed strategy hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n /// @param strategy Address of the strategy whose root update to execute\n function executeStrategyHooksRootUpdate(address strategy) external;\n\n /// @notice Set veto status for the global hooks root\n /// @dev Only callable by SuperGovernor\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Set veto status for a strategy-specific hooks root\n /// @notice Sets the veto status of a strategy's hooks Merkle root\n /// @param strategy Address of the strategy\n /// @param vetoed Whether to veto (true) or unveto (false)\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Updates the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @param deviationThreshold_ New deviation threshold (abs diff/current ratio, scaled by 1e18)\n function updateDeviationThreshold(address strategy, uint256 deviationThreshold_) external;\n\n /// @notice Changes the banned status of global leaves for a specific strategy\n /// @dev Only callable by the primary manager of the strategy\n /// @param leaves Array of leaf hashes to change status for\n /// @param statuses Array of banned statuses (true = banned, false = allowed)\n /// @param strategy Address of the strategy to change banned leaves for\n function changeGlobalLeavesStatus(bytes32[] memory leaves, bool[] memory statuses, address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MIN UPDATE INTERVAL MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Proposes a change to the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @param newMinUpdateInterval The proposed new minimum update interval (in seconds)\n /// @dev Only the main manager can propose. Must be less than maxStaleness\n function proposeMinUpdateIntervalChange(address strategy, uint256 newMinUpdateInterval) external;\n\n /// @notice Executes a previously proposed minUpdateInterval change after timelock\n /// @param strategy Address of the strategy whose minUpdateInterval to update\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Cancels a pending minUpdateInterval change proposal\n /// @param strategy Address of the strategy\n /// @dev Only the main manager can cancel\n function cancelMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Gets the proposed minUpdateInterval and effective time\n /// @param strategy Address of the strategy\n /// @return proposedInterval The proposed minimum update interval\n /// @return effectiveTime The timestamp when the proposed interval becomes effective\n function getProposedMinUpdateInterval(address strategy)\n external\n view\n returns (uint256 proposedInterval, uint256 effectiveTime);\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the current vault creation nonce\n /// @dev This nonce is incremented every time a new vault is created\n /// @return Current vault creation nonce\n function getCurrentNonce() external view returns (uint256);\n\n /// @notice Check if the global hooks root is currently vetoed\n /// @return vetoed True if the global hooks root is vetoed\n function isGlobalHooksRootVetoed() external view returns (bool vetoed);\n\n /// @notice Check if a strategy hooks root is currently vetoed\n /// @param strategy Address of the strategy to check\n /// @return vetoed True if the strategy hooks root is vetoed\n function isStrategyHooksRootVetoed(address strategy) external view returns (bool vetoed);\n\n /// @notice Gets the current hooks root update timelock duration\n /// @return The current timelock duration in seconds\n function getHooksRootUpdateTimelock() external view returns (uint256);\n\n /// @notice Gets the current PPS (price-per-share) for a strategy\n /// @param strategy Address of the strategy\n /// @return pps Current price-per-share value\n function getPPS(address strategy) external view returns (uint256 pps);\n\n /// @notice Gets the last update timestamp for a strategy's PPS\n /// @param strategy Address of the strategy\n /// @return timestamp Last update timestamp\n function getLastUpdateTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @return interval Minimum time between updates\n function getMinUpdateInterval(address strategy) external view returns (uint256 interval);\n\n /// @notice Gets the maximum staleness period for a strategy\n /// @param strategy Address of the strategy\n /// @return staleness Maximum time allowed between updates\n function getMaxStaleness(address strategy) external view returns (uint256 staleness);\n\n /// @notice Gets the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @return deviationThreshold The current deviation threshold (abs diff/current ratio, scaled by 1e18)\n function getDeviationThreshold(address strategy) external view returns (uint256 deviationThreshold);\n\n /// @notice Checks if a strategy is currently paused\n /// @param strategy Address of the strategy\n /// @return isPaused True if paused, false otherwise\n function isStrategyPaused(address strategy) external view returns (bool isPaused);\n\n /// @notice Checks if a strategy's PPS is stale\n /// @dev PPS is automatically set to stale when the strategy is paused due to\n /// lack of upkeep payment in `SuperVaultAggregator`\n /// @param strategy Address of the strategy\n /// @return isStale True if stale, false otherwise\n function isPPSStale(address strategy) external view returns (bool isStale);\n\n /// @notice Gets the last unpause timestamp for a strategy\n /// @param strategy Address of the strategy\n /// @return timestamp Last unpause timestamp (0 if never unpaused)\n function getLastUnpauseTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the current upkeep balance for a strategy\n /// @param strategy Address of the strategy\n /// @return balance Current upkeep balance in upkeep tokens\n function getUpkeepBalance(address strategy) external view returns (uint256 balance);\n\n /// @notice Gets the main manager for a strategy\n /// @param strategy Address of the strategy\n /// @return manager Address of the main manager\n function getMainManager(address strategy) external view returns (address manager);\n\n /// @notice Gets pending primary manager change details\n /// @param strategy Address of the strategy\n /// @return proposedManager Address of the proposed new manager (address(0) if no pending change)\n /// @return effectiveTime Timestamp when the change can be executed (0 if no pending change)\n function getPendingManagerChange(address strategy)\n external\n view\n returns (address proposedManager, uint256 effectiveTime);\n\n /// @notice Checks if an address is the main manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isMainManager True if the address is the main manager, false otherwise\n function isMainManager(address manager, address strategy) external view returns (bool isMainManager);\n\n /// @notice Gets all secondary managers for a strategy\n /// @param strategy Address of the strategy\n /// @return secondaryManagers Array of secondary manager addresses\n function getSecondaryManagers(address strategy) external view returns (address[] memory secondaryManagers);\n\n /// @notice Checks if an address is a secondary manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isSecondaryManager True if the address is a secondary manager, false otherwise\n function isSecondaryManager(address manager, address strategy) external view returns (bool isSecondaryManager);\n\n /// @dev Internal helper function to check if an address is any kind of manager (primary or secondary)\n /// @param manager Address to check\n /// @param strategy The strategy to check against\n /// @return True if the address is either the primary manager or a secondary manager\n function isAnyManager(address manager, address strategy) external view returns (bool);\n\n /// @notice Gets all created SuperVaults\n /// @return Array of SuperVault addresses\n function getAllSuperVaults() external view returns (address[] memory);\n\n /// @notice Gets a SuperVault by index\n /// @param index The index of the SuperVault\n /// @return The SuperVault address at the given index\n function superVaults(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultStrategies\n /// @return Array of SuperVaultStrategy addresses\n function getAllSuperVaultStrategies() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultStrategy by index\n /// @param index The index of the SuperVaultStrategy\n /// @return The SuperVaultStrategy address at the given index\n function superVaultStrategies(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultEscrows\n /// @return Array of SuperVaultEscrow addresses\n function getAllSuperVaultEscrows() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultEscrow by index\n /// @param index The index of the SuperVaultEscrow\n /// @return The SuperVaultEscrow address at the given index\n function superVaultEscrows(uint256 index) external view returns (address);\n\n /// @notice Validates a hook against both global and strategy-specific Merkle roots\n /// @param strategy Address of the strategy\n /// @param args Arguments for hook validation\n /// @return isValid True if the hook is valid against either root\n function validateHook(address strategy, ValidateHookArgs calldata args) external view returns (bool isValid);\n\n /// @notice Batch validates multiple hooks against Merkle roots\n /// @param strategy Address of the strategy\n /// @param argsArray Array of hook validation arguments\n /// @return validHooks Array of booleans indicating which hooks are valid\n function validateHooks(\n address strategy,\n ValidateHookArgs[] calldata argsArray\n )\n external\n view\n returns (bool[] memory validHooks);\n\n /// @notice Gets the current global hooks Merkle root\n /// @return root The current global hooks Merkle root\n function getGlobalHooksRoot() external view returns (bytes32 root);\n\n /// @notice Gets the proposed global hooks root and effective time\n /// @return root The proposed global hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedGlobalHooksRoot() external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Checks if the global hooks root is active (timelock period has passed)\n /// @return isActive True if the global hooks root is active\n function isGlobalHooksRootActive() external view returns (bool);\n\n /// @notice Gets the hooks Merkle root for a specific strategy\n /// @param strategy Address of the strategy\n /// @return root The strategy-specific hooks Merkle root\n function getStrategyHooksRoot(address strategy) external view returns (bytes32 root);\n\n /// @notice Gets the proposed strategy hooks root and effective time\n /// @param strategy Address of the strategy\n /// @return root The proposed strategy hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedStrategyHooksRoot(address strategy) external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Gets the total number of SuperVaults\n /// @return count The total number of SuperVaults\n function getSuperVaultsCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultStrategies\n /// @return count The total number of SuperVaultStrategies\n function getSuperVaultStrategiesCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultEscrows\n /// @return count The total number of SuperVaultEscrows\n function getSuperVaultEscrowsCount() external view returns (uint256);\n}\n"},"src/interfaces/oracles/ISuperOracle.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperOracle\n/// @author Superform Labs\n/// @notice Interface for SuperOracle\ninterface ISuperOracle {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Error when address is zero\n error ZERO_ADDRESS();\n\n /// @notice Error when array length is zero\n error ZERO_ARRAY_LENGTH();\n\n /// @notice Error when oracle provider index is invalid\n error INVALID_ORACLE_PROVIDER();\n\n /// @notice Error when no oracles are configured for base asset\n error NO_ORACLES_CONFIGURED();\n\n /// @notice Error when no valid reported prices are found\n error NO_VALID_REPORTED_PRICES();\n\n /// @notice Error when arrays have mismatched lengths\n error ARRAY_LENGTH_MISMATCH();\n\n /// @notice Error when timelock period has not elapsed\n error TIMELOCK_NOT_ELAPSED();\n\n /// @notice Error when there is already a pending update\n error PENDING_UPDATE_EXISTS();\n\n /// @notice Error when oracle data is untrusted\n error ORACLE_UNTRUSTED_DATA();\n\n /// @notice Error when provider max staleness period is not set\n error NO_PENDING_UPDATE();\n\n /// @notice Error when provider max staleness period is exceeded\n error MAX_STALENESS_EXCEEDED();\n\n /// @notice Error when average provider is not allowed\n error AVERAGE_PROVIDER_NOT_ALLOWED();\n\n /// @notice Error when provider is zero\n error ZERO_PROVIDER();\n\n /// @notice Error when too many providers are being iterated through\n error TOO_MANY_PROVIDERS();\n\n /// @notice Error when caller is not authorized to update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n\n /// @notice Error when oracle decimals call fails\n error ORACLE_DECIMALS_CALL_FAIL(address oracle);\n\n /// @notice Error when oracle round data call fails\n error ORACLE_ROUND_DATA_CALL_FAIL(address oracle);\n\n /// @notice Error when external call gas is insufficient\n error INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when oracles are configured\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n event OraclesConfigured(address[] bases, address[] quotes, bytes32[] providers, address[] feeds);\n\n /// @notice Emitted when oracle update is queued\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n /// @param timestamp Timestamp when update was queued\n event OracleUpdateQueued(\n address[] bases, address[] quotes, bytes32[] providers, address[] feeds, uint256 timestamp\n );\n\n /// @notice Emitted when oracle update is executed\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n event OracleUpdateExecuted(address[] bases, address[] quotes, bytes32[] providers, address[] feeds);\n\n /// @notice Emitted when provider max staleness period is updated\n /// @param feed Feed address\n /// @param newMaxStaleness New maximum staleness period in seconds\n event FeedMaxStalenessUpdated(address feed, uint256 newMaxStaleness);\n\n /// @notice Emitted when max staleness period is updated\n /// @param newMaxStaleness New maximum staleness period in seconds\n event MaxStalenessUpdated(uint256 newMaxStaleness);\n\n /// @notice Emitted when provider removal is queued\n /// @param providers Array of provider ids to remove\n /// @param timestamp Timestamp when removal was queued\n event ProviderRemovalQueued(bytes32[] providers, uint256 timestamp);\n\n /// @notice Emitted when provider removal is executed\n /// @param providers Array of provider ids that were removed\n event ProviderRemovalExecuted(bytes32[] providers);\n\n /// @notice Emitted when provider removal is cancelled\n /// @param providers Array of provider ids that were queued for removal\n event ProviderRemovalCancelled(bytes32[] providers);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Struct for pending oracle update\n struct PendingUpdate {\n address[] bases;\n address[] quotes;\n bytes32[] providers;\n address[] feeds;\n uint256 timestamp;\n }\n\n /// @notice Struct for pending provider removal\n struct PendingRemoval {\n bytes32[] providers;\n uint256 timestamp;\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get oracle address for a base asset and provider\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param provider Provider id\n /// @return oracle Oracle address\n function getOracleAddress(address base, address quote, bytes32 provider) external view returns (address oracle);\n\n /// @notice Get quote from specified oracle provider\n /// @param baseAmount Amount of base asset\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param oracleProvider Id of oracle provider to use\n /// @return quoteAmount The quote amount\n /// @return deviation Standard deviation of oracle quotes in quote asset units (0 for single provider)\n /// @return totalProviders Total number of providers that have a configured oracle for this pair\n /// @return availableProviders Number of providers that successfully returned a valid quote\n function getQuoteFromProvider(\n uint256 baseAmount,\n address base,\n address quote,\n bytes32 oracleProvider\n )\n external\n view\n returns (uint256 quoteAmount, uint256 deviation, uint256 totalProviders, uint256 availableProviders);\n\n /// @notice Queue oracle update for timelock\n /// @param bases Array of base assets\n /// @param providers Array of provider ids\n /// @param quotes Array of quote assets\n /// @param feeds Array of oracle addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Execute queued oracle update after timelock period\n function executeOracleUpdate() external;\n\n /// @notice Queue provider removal for timelock\n /// @param providers Array of provider ids to remove\n function queueProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Execute queued provider removal after timelock period\n function executeProviderRemoval() external;\n\n /// @notice Cancel queued provider removal\n function cancelProviderRemoval() external;\n\n /// @notice Set the maximum staleness period for a specific provider\n /// @param feed Feed address\n /// @param newMaxStaleness New maximum staleness period in seconds\n function setFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Set the maximum staleness period for all providers\n /// @param newMaxStaleness New maximum staleness period in seconds\n function setDefaultStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Set the maximum staleness period for multiple providers\n /// @param feeds Array of feed addresses\n /// @param newMaxStalenessList Array of new maximum staleness periods in seconds\n function setFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Get all active provider ids\n /// @return Array of active provider ids\n function getActiveProviders() external view returns (bytes32[] memory);\n}\n"},"src/interfaces/oracles/ISuperOracleL2.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperOracleL2\n/// @author Superform Labs\n/// @notice Interface for Layer 2 Oracle for Superform\ninterface ISuperOracleL2 {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Error when no uptime feed is configured for the data oracle\n error NO_UPTIME_FEED();\n\n /// @notice Error when the L2 sequencer is down\n error SEQUENCER_DOWN();\n\n /// @notice Error when the grace period after sequencer restart is not over\n error GRACE_PERIOD_NOT_OVER();\n\n /// @notice Error when the grace period after sequencer restart is too low\n error GRACE_PERIOD_TOO_LOW();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an uptime feed is set for a data oracle\n /// @param dataOracle The data oracle address\n /// @param uptimeOracle The uptime feed address\n event UptimeFeedSet(address dataOracle, address uptimeOracle);\n\n /// @notice Emitted when a grace period is set for an uptime oracle\n /// @param uptimeOracle The uptime oracle address\n /// @param gracePeriod The grace period in seconds\n event GracePeriodSet(address uptimeOracle, uint256 gracePeriod);\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set uptime feeds for multiple data oracles in batch\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Arrays.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n using SlotDerivation for bytes32;\n using StorageSlot for bytes32;\n\n /**\n * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n uint256[] memory array,\n function(uint256, uint256) pure returns (bool) comp\n ) internal pure returns (uint256[] memory) {\n _quickSort(_begin(array), _end(array), comp);\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n */\n function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n sort(array, Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of address (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n address[] memory array,\n function(address, address) pure returns (bool) comp\n ) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of address in increasing order.\n */\n function sort(address[] memory array) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n bytes32[] memory array,\n function(bytes32, bytes32) pure returns (bool) comp\n ) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n */\n function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n * at end (exclusive). Sorting follows the `comp` comparator.\n *\n * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n *\n * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n * be used only if the limits are within a memory array.\n */\n function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n unchecked {\n if (end - begin < 0x40) return;\n\n // Use first element as pivot\n uint256 pivot = _mload(begin);\n // Position where the pivot should be at the end of the loop\n uint256 pos = begin;\n\n for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n if (comp(_mload(it), pivot)) {\n // If the value stored at the iterator's position comes before the pivot, we increment the\n // position of the pivot and move the value there.\n pos += 0x20;\n _swap(pos, it);\n }\n }\n\n _swap(begin, pos); // Swap pivot into place\n _quickSort(begin, pos, comp); // Sort the left side of the pivot\n _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first element of `array`.\n */\n function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := add(array, 0x20)\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n * that comes just after the last element of the array.\n */\n function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n unchecked {\n return _begin(array) + array.length * 0x20;\n }\n }\n\n /**\n * @dev Load memory word (as a uint256) at location `ptr`.\n */\n function _mload(uint256 ptr) private pure returns (uint256 value) {\n assembly {\n value := mload(ptr)\n }\n }\n\n /**\n * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n */\n function _swap(uint256 ptr1, uint256 ptr2) private pure {\n assembly {\n let value1 := mload(ptr1)\n let value2 := mload(ptr2)\n mstore(ptr1, value2)\n mstore(ptr2, value1)\n }\n }\n\n /// @dev Helper: low level cast address memory array to uint256 memory array\n function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast address comp function to uint256 comp function\n function _castToUint256Comp(\n function(address, address) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n function _castToUint256Comp(\n function(bytes32, bytes32) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /**\n * @dev Searches a sorted `array` and returns the first index that contains\n * a value greater or equal to `element`. If no such index exists (i.e. all\n * values in the array are strictly less than `element`), the array length is\n * returned. Time complexity O(log n).\n *\n * NOTE: The `array` is expected to be sorted in ascending order, and to\n * contain no repeated elements.\n *\n * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n * support for repeated elements in the array. The {lowerBound} function should\n * be used instead.\n */\n function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n return low - 1;\n } else {\n return low;\n }\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value greater or equal than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n */\n function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value strictly greater than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n */\n function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {lowerBound}, but with an array in memory.\n */\n function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {upperBound}, but with an array in memory.\n */\n function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getAddressSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytes32Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getUint256Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytesSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getStringSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(address[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(string[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"src/interfaces/SuperVault/ISuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { ISuperHook, Execution } from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n/// @title ISuperVaultStrategy\n/// @author Superform Labs\n/// @notice Interface for SuperVault strategy implementation that manages yield sources and executes strategies\ninterface ISuperVaultStrategy {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n error ZERO_LENGTH();\n error INVALID_HOOK();\n error ZERO_ADDRESS();\n error ACCESS_DENIED();\n error INVALID_AMOUNT();\n error OPERATION_FAILED();\n error INVALID_TIMESTAMP();\n error REQUEST_NOT_FOUND();\n error INVALID_ARRAY_LENGTH();\n error ACTION_TYPE_DISALLOWED();\n error YIELD_SOURCE_NOT_FOUND();\n error YIELD_SOURCE_ALREADY_EXISTS();\n error INVALID_PERFORMANCE_FEE_BPS();\n error MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n error MANAGER_NOT_AUTHORIZED();\n error INVALID_PPS();\n error INVALID_VAULT();\n error INVALID_ASSET();\n error OPERATIONS_BLOCKED_BY_VETO();\n error HOOK_VALIDATION_FAILED();\n error STRATEGY_PAUSED();\n error NO_PROPOSAL();\n error INVALID_REDEEM_SLIPPAGE_BPS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n error STALE_PPS();\n error PPS_EXPIRED();\n error INVALID_PPS_EXPIRY_THRESHOLD();\n error BOUNDS_EXCEEDED(uint256 minAllowed, uint256 maxAllowed, uint256 actual);\n error INSUFFICIENT_LIQUIDITY();\n error CONTROLLERS_NOT_SORTED_UNIQUE();\n error ZERO_SHARE_FULFILLMENT_DISALLOWED();\n error NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n error SKIM_TIMELOCK_ACTIVE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event SuperGovernorSet(address indexed superGovernor);\n event Initialized(address indexed vault);\n event YieldSourceAdded(address indexed source, address indexed oracle);\n event YieldSourceOracleUpdated(address indexed source, address indexed oldOracle, address indexed newOracle);\n event YieldSourceRemoved(address indexed source);\n\n event VaultFeeConfigUpdated(uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient);\n event VaultFeeConfigProposed(\n uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient, uint256 effectiveTime\n );\n event HooksExecuted(address[] hooks);\n event RedeemRequestPlaced(address indexed controller, address indexed owner, uint256 shares);\n event RedeemRequestClaimed(address indexed controller, address indexed receiver, uint256 assets, uint256 shares);\n event RedeemRequestsFulfilled(address[] controllers, uint256 processedShares, uint256 currentPPS);\n event RedeemRequestCanceled(address indexed controller, uint256 shares);\n event RedeemCancelRequestPlaced(address indexed controller);\n event RedeemCancelRequestFulfilled(address indexed controller, uint256 shares);\n event HookExecuted(\n address indexed hook,\n address indexed prevHook,\n address indexed targetedYieldSource,\n bool usePrevHookAmount,\n bytes hookCalldata\n );\n\n event PPSUpdated(uint256 newPPS, uint256 calculationBlock);\n event FeeRecipientChanged(address indexed newRecipient);\n event ManagementFeePaid(address indexed controller, address indexed recipient, uint256 feeAssets, uint256 feeBps);\n event DepositHandled(address indexed controller, uint256 assets, uint256 shares);\n event RedeemClaimable(\n address indexed controller, uint256 assetsFulfilled, uint256 sharesFulfilled, uint256 averageWithdrawPrice\n );\n event RedeemSlippageSet(address indexed controller, uint16 slippageBps);\n\n event PPSExpirationProposed(uint256 currentProposedThreshold, uint256 ppsExpiration, uint256 effectiveTime);\n event PPSExpiryThresholdUpdated(uint256 ppsExpiration);\n event PPSExpiryThresholdProposalCanceled();\n\n /// @notice Emitted when the high-water mark PPS is updated after fee collection\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n /// @param previousPps The PPS before fee collection\n /// @param profit The total profit above HWM (in assets)\n /// @param feeCollected The total fee collected (in assets)\n event HWMPPSUpdated(uint256 newHwmPps, uint256 previousPps, uint256 profit, uint256 feeCollected);\n\n /// @notice Emitted when the high-water mark PPS is reset\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n event HighWaterMarkReset(uint256 newHwmPps);\n\n /// @notice Emitted when performance fees are skimmed\n /// @param totalFee The total fee collected (in assets)\n /// @param superformFee The fee collected for Superform (in assets)\n event PerformanceFeeSkimmed(uint256 totalFee, uint256 superformFee);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n struct FeeConfig {\n uint256 performanceFeeBps; // On profit at fulfill time\n uint256 managementFeeBps; // Entry fee on deposit/mint (asset-side)\n address recipient; // Fee sink (entry + performance)\n }\n\n /// @notice Structure for hook execution arguments\n struct ExecuteArgs {\n /// @notice Array of hooks to execute\n address[] hooks;\n /// @notice Calldata for each hook (must match hooks array length)\n bytes[] hookCalldata;\n /// @notice Expected output amounts or output shares\n uint256[] expectedAssetsOrSharesOut;\n /// @notice Global Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] globalProofs;\n /// @notice Strategy-specific Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] strategyProofs;\n }\n\n struct YieldSource {\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice Comprehensive information about a yield source including its address and configuration\n struct YieldSourceInfo {\n address sourceAddress; // Address of the yield source\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice State specific to asynchronous redeem requests\n struct SuperVaultState {\n // Cancellation\n bool pendingCancelRedeemRequest;\n uint256 claimableCancelRedeemRequest;\n // Redeems\n uint256 pendingRedeemRequest; // Shares requested\n uint256 maxWithdraw; // Assets claimable after fulfillment\n uint256 averageRequestPPS; // Average PPS at the time of redeem request\n uint256 averageWithdrawPrice; // Average price for claimable assets\n uint16 redeemSlippageBps; // User-defined slippage tolerance in BPS for redeem fulfillment\n }\n\n struct ExecutionVars {\n bool success;\n address targetedYieldSource;\n uint256 outAmount;\n ISuperHook hookContract;\n Execution[] executions;\n }\n\n struct FulfillRedeemVars {\n uint256 totalRequestedShares;\n uint256 totalNetAssetsOut;\n uint256 currentPPS;\n uint256 strategyBalance;\n }\n\n /*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n enum Operation {\n RedeemRequest,\n CancelRedeemRequest,\n ClaimCancelRedeem,\n ClaimRedeem\n }\n\n /// @notice Action types for yield source management\n enum YieldSourceAction {\n Add, // 0: Add a new yield source\n UpdateOracle, // 1: Update an existing yield source's oracle\n Remove // 2: Remove a yield source\n }\n\n /// @notice Action types for PPS expiration threshold management\n enum PPSExpirationAction {\n Propose, // 0: Propose a new PPS expiration threshold\n Execute, // 1: Execute the proposed threshold update\n Cancel // 2: Cancel the pending threshold proposal\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the strategy with required parameters\n /// @param vaultAddress Address of the associated SuperVault\n /// @param feeConfigData Fee configuration\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external;\n\n /// @notice Execute a 4626 deposit by processing assets.\n /// @param controller The controller address\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @return sharesNet The amount of net shares to mint\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet);\n\n /// @notice Execute a 4626 mint by processing shares.\n /// @param controller The controller address\n /// @param sharesNet The amount of shares to mint\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @param assetsNet The amount of net assets that strategy will receive\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external;\n\n /// @notice Quotes the amount of assets that will be received for a given amount of shares.\n /// @param shares The amount of shares to mint\n /// @return assetsGross The amount of gross assets that will be received\n /// @return assetsNet The amount of net assets that will be received\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet);\n\n /// @notice Execute async redeem requests (redeem, cancel, claim).\n /// @param op The operation type (RedeemRequest, CancelRedeem, ClaimRedeem)\n /// @param controller The controller address\n /// @param receiver The receiver address\n /// @param amount The amount of assets or shares\n function handleOperations7540(Operation op, address controller, address receiver, uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Execute hooks for general strategy management (rebalancing, etc.).\n /// @param args Execution arguments containing hooks, calldata, proofs, expectations.\n function executeHooks(ExecuteArgs calldata args) external payable;\n\n /// @notice Fulfills pending cancel redeem requests by making shares claimable\n /// @dev Processes all controllers with pending cancellation flags\n /// @dev Can only be called by authorized managers\n /// @param controllers Array of controller addresses with pending cancel requests\n function fulfillCancelRedeemRequests(address[] memory controllers) external;\n\n /// @notice Fulfills pending redeem requests with exact total assets per controller (pre-fee).\n /// @dev PRE: Off-chain sort/unique controllers. Call executeHooks(sum(totalAssetsOut)) first.\n /// @dev Social: totalAssetsOut[i] = theoreticalGross[i] (full). Selective: totalAssetsOut[i] < theoreticalGross[i].\n /// @dev NOTE: totalAssetsOut includes fees - actual net amount received is calculated internally after fee\n /// deduction. @param controllers Ordered/unique controllers with pending requests.\n /// @param totalAssetsOut Total PRE-FEE assets available for each controller[i] (from executeHooks).\n function fulfillRedeemRequests(address[] calldata controllers, uint256[] calldata totalAssetsOut) external;\n\n /// @notice Skim performance fees based on per-share High Water Mark (PPS-based)\n /// @dev Can be called by any manager when vault PPS has grown above HWM PPS\n /// @dev Uses PPS growth to calculate profit: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev HWM is only updated during this function, not during deposits/redemptions\n function skimPerformanceFee() external;\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Manage a single yield source: add, update oracle, or remove\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle (used for adding/updating, ignored for removal)\n /// @param actionType Type of action (see YieldSourceAction enum)\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external;\n\n /// @notice Batch manage multiple yield sources in a single transaction\n /// @param sources Array of yield source addresses\n /// @param oracles Array of oracle addresses (used for adding/updating, ignored for removal)\n /// @param actionTypes Array of action types (see YieldSourceAction enum)\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external;\n\n /// @notice Change the fee recipient when the primary manager is changed\n /// @param newRecipient New fee recipient\n function changeFeeRecipient(address newRecipient) external;\n\n /// @notice Propose or execute a hook root update\n /// @notice Propose changes to vault-specific fee configuration\n /// @param performanceFeeBps New performance fee in basis points\n /// @param managementFeeBps New management fee in basis points\n /// @param recipient New fee recipient\n /// @dev IMPORTANT: Before executing the proposed update (via executeVaultFeeConfigUpdate),\n /// manager should call skimPerformanceFee() to collect performance fees on existing profits\n /// under the current fee structure to avoid losing profit or incorrect fee calculations.\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external;\n\n /// @notice Execute the proposed vault fee configuration update after timelock\n /// @dev IMPORTANT: Manager should call skimPerformanceFee() before executing this update\n /// to collect performance fees on existing profits under the current fee structure.\n /// Otherwise, profit earned under the old fee percentage will be lost or incorrectly calculated.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// to avoid incorrect fee calculations with the new fee structure.\n function executeVaultFeeConfigUpdate() external;\n\n /// @notice Reset the high-water mark PPS to the current PPS\n /// @dev This function is only callable by Aggregator\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// @param newHwmPps The new high-water mark PPS value\n function resetHighWaterMark(uint256 newHwmPps) external;\n\n /// @notice Manage PPS expiry threshold\n /// @param action Type of action (see PPSExpirationAction enum)\n /// @param ppsExpiration The new PPS expiry threshold\n function managePPSExpiration(PPSExpirationAction action, uint256 ppsExpiration) external;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set the slippage tolerance for all future redeem request fulfillments, until reset using this function\n /// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)\n function setRedeemSlippage(uint16 slippageBps) external;\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Get the vault info\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals);\n\n /// @notice Get the fee configurations\n function getConfigInfo() external view returns (FeeConfig memory feeConfig);\n\n /// @notice Returns the currently stored PPS value.\n function getStoredPPS() external view returns (uint256);\n\n /// @notice Get a yield source's configuration\n function getYieldSource(address source) external view returns (YieldSource memory);\n\n /// @notice Get all yield sources with their information\n /// @return Array of YieldSourceInfo structs\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory);\n\n /// @notice Get all yield source addresses\n /// @return Array of yield source addresses\n function getYieldSources() external view returns (address[] memory);\n\n /// @notice Get the count of yield sources\n /// @return Number of yield sources\n function getYieldSourcesCount() external view returns (uint256);\n\n /// @notice Check if a yield source exists\n /// @param source Address of the yield source\n /// @return True if the yield source exists\n function containsYieldSource(address source) external view returns (bool);\n\n /// @notice Get the average withdraw price for a controller\n /// @param controller The controller address\n /// @return averageWithdrawPrice The average withdraw price\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice);\n\n /// @notice Get the super vault state for a controller\n /// @param controller The controller address\n /// @return state The super vault state\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state);\n\n /// @notice Get the pending redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return pendingShares The amount of shares pending redemption\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares);\n\n /// @notice Get the pending cancellation for a redeem request for a controller\n /// @param controller The controller address\n /// @return isPending True if the redeem request is pending cancellation\n function pendingCancelRedeemRequest(address controller) external view returns (bool isPending);\n\n /// @notice Get the claimable cancel redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return claimableShares The amount of shares claimable\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares);\n\n /// @notice Get the claimable withdraw amount (assets) for a controller\n /// @param controller The controller address\n /// @return claimableAssets The amount of assets claimable\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets);\n\n /// @notice Preview exact redeem fulfillment for off-chain calculation\n /// @param controller The controller address to preview\n /// @return shares Pending redeem shares\n /// @return theoreticalAssets Theoretical assets at current PPS\n /// @return minAssets Minimum acceptable assets (slippage floor)\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets);\n\n /// @notice Batch preview exact redeem fulfillment for multiple controllers\n /// @dev Efficiently batches multiple previewExactRedeem calls to reduce RPC overhead\n /// @param controllers Array of controller addresses to preview\n /// @return totalTheoAssets Total theoretical assets across all controllers\n /// @return individualAssets Array of theoretical assets per controller\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets);\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev Returns 0 if totalSupply is 0 or currentPPS <= hwmPPS\n function vaultUnrealizedProfit() external view returns (uint256);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Comparators.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n function lt(uint256 a, uint256 b) internal pure returns (bool) {\n return a < b;\n }\n\n function gt(uint256 a, uint256 b) internal pure returns (bool) {\n return a > b;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using StorageSlot for bytes32;\n * using SlotDerivation for bytes32;\n *\n * // Declare a namespace\n * string private constant _NAMESPACE = \"\"; // eg. OpenZeppelin.Slot\n *\n * function setValueInNamespace(uint256 key, address newValue) internal {\n * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n * }\n *\n * function getValueInNamespace(uint256 key) internal view returns (address) {\n * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n /**\n * @dev Derive an ERC-7201 slot from a string (namespace).\n */\n function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n assembly (\"memory-safe\") {\n mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n slot := and(keccak256(0x00, 0x20), not(0xff))\n }\n }\n\n /**\n * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n */\n function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n unchecked {\n return bytes32(uint256(slot) + pos);\n }\n }\n\n /**\n * @dev Derive the location of the first element in an array from the slot where the length is stored.\n */\n function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, slot)\n result := keccak256(0x00, 0x20)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, and(key, shr(96, not(0))))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, iszero(iszero(key)))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n"},"lib/v2-core/src/interfaces/ISuperHook.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { Execution } from \"modulekit/accounts/erc7579/lib/ExecutionLib.sol\";\n\n/**\n * @title SuperHook System\n * @author Superform Labs\n * @notice The hook system provides a modular and composable way to execute operations on assets\n * @dev The hook system architecture consists of several interfaces that work together:\n * - ISuperHook: The base interface all hooks implement, with lifecycle methods\n * - ISuperHookResult: Provides execution results and output information\n * - Specialized interfaces (ISuperHookOutflow, ISuperHookLoans, etc.) for specific behaviors\n *\n * Hooks are executed in sequence, where each hook can access the results from previous hooks.\n * The three main types of hooks are:\n * - NONACCOUNTING: Utility hooks that don't update the accounting system\n * - INFLOW: Hooks that process deposits or additions to positions\n * - OUTFLOW: Hooks that process withdrawals or reductions to positions\n */\ninterface ISuperLockableHook {\n /// @notice The vault bank address used to lock SuperPositions\n /// @dev Only relevant for cross-chain operations where positions are locked\n /// @return The vault bank address, or address(0) if not applicable\n function vaultBank() external view returns (address);\n\n /// @notice The destination chain ID for cross-chain operations\n /// @dev Used to identify the target chain for cross-chain position transfers\n /// @return The destination chain ID, or 0 if not a cross-chain operation\n function dstChainId() external view returns (uint256);\n}\n\ninterface ISuperHookSetter {\n /// @notice Sets the output amount for the hook\n /// @dev Used for updating `outAmount` when fees were deducted\n /// @param outAmount The amount of tokens processed by the hook\n /// @param caller The caller address for context identification\n function setOutAmount(uint256 outAmount, address caller) external;\n}\n/// @title ISuperHookInspector\n/// @author Superform Labs\n/// @notice Interface for the SuperHookInspector contract that manages hook inspection\n\ninterface ISuperHookInspector {\n /// @notice Inspect the hook\n /// @param data The hook data to inspect\n /// @return argsEncoded The arguments of the hook encoded\n function inspect(bytes calldata data) external view returns (bytes memory argsEncoded);\n}\n\n/// @title ISuperHookResult\n/// @author Superform Labs\n/// @notice Interface that exposes the result of a hook execution\n/// @dev All hooks must implement this interface to provide standardized access to execution results.\n/// These results are used by subsequent hooks in the execution chain and by the executor.\ninterface ISuperHookResult {\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The type of hook\n /// @dev Used to determine how accounting should process this hook's results\n /// @return The hook type (NONACCOUNTING, INFLOW, or OUTFLOW)\n function hookType() external view returns (ISuperHook.HookType);\n\n /// @notice The SuperPosition (SP) token associated with this hook\n /// @dev For vault hooks, this would be the tokenized position representing shares\n /// @return The address of the SP token, or address(0) if not applicable\n function spToken() external view returns (address);\n\n /// @notice The underlying asset token being processed\n /// @dev For most hooks, this is the actual token being deposited or withdrawn\n /// @return The address of the asset token, or address(0) for native assets\n function asset() external view returns (address);\n\n /// @notice The amount of tokens processed by the hook in a given caller context, subject to fees after update\n /// @dev This is the primary output value used by subsequent hooks\n /// @param caller The caller address for context identification\n /// @return The amount of tokens (assets or shares) processed\n function getOutAmount(address caller) external view returns (uint256);\n}\n\n/// @title ISuperHookContextAware\n/// @author Superform Labs\n/// @notice Interface for hooks that can use previous hook results in their execution\n/// @dev Enables contextual awareness and data flow between hooks in a chain\ninterface ISuperHookContextAware {\n /// @notice Determines if this hook should use the amount from the previous hook\n /// @dev Used to create hook chains where output from one hook becomes input to the next\n /// @param data The hook-specific data containing configuration\n /// @return True if the hook should use the previous hook's output amount\n function decodeUsePrevHookAmount(bytes memory data) external pure returns (bool);\n}\n\n/// @title ISuperHookInflowOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that handle both inflows and outflows\n/// @dev Provides standardized amount extraction for both deposit and withdrawal operations\ninterface ISuperHookInflowOutflow {\n /// @notice Extracts the amount from the hook's calldata\n /// @dev Used to determine the quantity of assets or shares being processed\n /// @param data The hook-specific calldata containing the amount\n /// @return The amount of tokens to process\n function decodeAmount(bytes memory data) external pure returns (uint256);\n}\n\n/// @title ISuperHookOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that specifically handle outflows (withdrawals)\n/// @dev Provides additional functionality needed only for outflow operations\ninterface ISuperHookOutflow {\n /// @notice Replace the amount in the calldata\n /// @param data The data to replace the amount in\n /// @param amount The amount to replace\n /// @return data The data with the replaced amount\n function replaceCalldataAmount(bytes memory data, uint256 amount) external pure returns (bytes memory);\n}\n\n/// @title ISuperHookResultOutflow\n/// @author Superform Labs\n/// @notice Extended result interface for outflow hook operations\n/// @dev Extends the base result interface with outflow-specific information\ninterface ISuperHookResultOutflow is ISuperHookResult {\n /// @notice The amount of shares consumed during outflow processing\n /// @dev Used for cost basis calculation in the accounting system\n /// @return The amount of shares consumed from the user's position\n function usedShares() external view returns (uint256);\n}\n\n/// @title ISuperHookLoans\n/// @author Superform Labs\n/// @notice Interface for hooks that interact with lending protocols\n/// @dev Extends context awareness to enable loan operations within hook chains\ninterface ISuperHookLoans is ISuperHookContextAware {\n /// @notice Gets the address of the token being borrowed\n /// @dev Used to identify which asset is being borrowed from the lending protocol\n /// @param data The hook-specific data containing loan information\n /// @return The address of the borrowed token\n function getLoanTokenAddress(bytes memory data) external pure returns (address);\n\n /// @notice Gets the address of the token used as collateral\n /// @dev Used to identify which asset is being used to secure the loan\n /// @param data The hook-specific data containing collateral information\n /// @return The address of the collateral token\n function getCollateralTokenAddress(bytes memory data) external view returns (address);\n\n /// @notice Gets the current loan token balance for an account\n /// @dev Used to track outstanding loan amounts\n /// @param account The account to check the loan balance for\n /// @param data The hook-specific data containing loan parameters\n /// @return The amount of tokens currently borrowed\n function getLoanTokenBalance(address account, bytes memory data) external view returns (uint256);\n\n /// @notice Gets the current collateral token balance for an account\n /// @dev Used to track collateral positions\n /// @param account The account to check the collateral balance for\n /// @param data The hook-specific data containing collateral parameters\n /// @return The amount of tokens currently used as collateral\n function getCollateralTokenBalance(address account, bytes memory data) external view returns (uint256);\n}\n\n/// @title ISuperHookAsyncCancelations\n/// @author Superform Labs\n/// @notice Interface for hooks that can cancel asynchronous operations\n/// @dev Used to handle cancellation of pending operations that haven't completed\ninterface ISuperHookAsyncCancelations {\n /// @notice Types of cancellations that can be performed\n /// @dev Distinguishes between different operation types that can be canceled\n enum CancelationType {\n NONE, // Not a cancelation hook\n INFLOW, // Cancels a pending deposit operation\n OUTFLOW // Cancels a pending withdrawal operation\n\n }\n\n /// @notice Identifies the type of async operation this hook can cancel\n /// @dev Used to verify the hook is appropriate for the operation being canceled\n /// @return asyncType The type of cancellation this hook performs\n function isAsyncCancelHook() external pure returns (CancelationType asyncType);\n}\n\n/// @title ISuperHook\n/// @author Superform Labs\n/// @notice The core hook interface that all hooks must implement\n/// @dev Defines the lifecycle methods and execution flow for the hook system\n/// Hooks are executed in sequence with results passed between them\ninterface ISuperHook {\n /*//////////////////////////////////////////////////////////////\n\n ENUMS\n //////////////////////////////////////////////////////////////*/\n /// @notice Defines the possible types of hooks in the system\n /// @dev Used to determine how the hook affects accounting and what operations it performs\n enum HookType {\n NONACCOUNTING, // Hook doesn't affect accounting (e.g., a swap or bridge)\n INFLOW, // Hook processes deposits or positions being added\n OUTFLOW // Hook processes withdrawals or positions being removed\n\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Builds the execution array for the hook operation\n /// @dev This is the core method where hooks define their on-chain interactions\n /// The returned executions are a sequence of contract calls to perform\n /// No state changes should occur in this method\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform executions for (usually an ERC7579 account)\n /// @param data The hook-specific parameters and configuration data\n /// @return executions Array of Execution structs defining calls to make\n function build(\n address prevHook,\n address account,\n bytes calldata data\n )\n external\n view\n returns (Execution[] memory executions);\n\n /*//////////////////////////////////////////////////////////////\n PUBLIC METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Prepares the hook for execution\n /// @dev Called before the main execution, used to validate inputs and set execution context\n /// This method may perform state changes to set up the hook's execution state\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform operations for\n /// @param data The hook-specific parameters and configuration data\n function preExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Finalizes the hook after execution\n /// @dev Called after the main execution, used to update hook state and calculate results\n /// Sets output values (outAmount, usedShares, etc.) for subsequent hooks\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account operations were performed for\n /// @param data The hook-specific parameters and configuration data\n function postExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Returns the specific subtype identification for this hook\n /// @dev Used to categorize hooks beyond the basic HookType\n /// For example, a hook might be of type INFLOW but subtype VAULT_DEPOSIT\n /// @return A bytes32 identifier for the specific hook functionality\n function subtype() external view returns (bytes32);\n\n /// @notice Resets hook mutexes\n /// @param caller The caller address for context identification\n function resetExecutionState(address caller) external;\n\n /// @notice Sets the caller address that initiated the execution\n /// @dev Used for security validation between preExecute and postExecute calls\n /// @param caller The caller address for context identification\n function setExecutionContext(address caller) external;\n\n /// @notice Returns the execution nonce for the current execution context\n /// @dev Used to ensure unique execution contexts and prevent replay attacks\n /// @return The execution nonce\n function executionNonce() external view returns (uint256);\n\n /// @notice Returns the last caller registered by `setExecutionContext`\n /// @return The last caller address\n function lastCaller() external view returns (address);\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n// Types\nimport { Execution } from \"../../common/interfaces/IERC7579Account.sol\";\n\n/**\n * Helper Library for decoding Execution calldata\n * malloc for memory allocation is bad for gas. use this assembly instead\n */\nlibrary ExecutionLib {\n error ERC7579DecodingError();\n\n /**\n * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.\n * @dev code is copied from solady's LibERC7579.sol\n * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146\n * Credits to Vectorized and the Solady Team\n */\n function decodeBatch(bytes calldata executionCalldata)\n internal\n pure\n returns (Execution[] calldata executionBatch)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let u := calldataload(executionCalldata.offset)\n let s := add(executionCalldata.offset, u)\n let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)\n executionBatch.offset := add(s, 0x20)\n executionBatch.length := calldataload(s)\n if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if executionBatch.length {\n // Perform bounds checks on the decoded `executionBatch`.\n // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.\n for { let i := executionBatch.length } 1 { } {\n i := sub(i, 1)\n let p := calldataload(add(executionBatch.offset, shl(5, i)))\n let c := add(executionBatch.offset, p)\n let q := calldataload(add(c, 0x40))\n let o := add(c, q)\n // forgefmt: disable-next-item\n if or(shr(64, or(calldataload(o), or(p, q))),\n or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if iszero(i) { break }\n }\n }\n }\n }\n\n function encodeBatch(Execution[] memory executions)\n internal\n pure\n returns (bytes memory callData)\n {\n callData = abi.encode(executions);\n }\n\n function decodeSingle(bytes calldata executionCalldata)\n internal\n pure\n returns (address target, uint256 value, bytes calldata callData)\n {\n target = address(bytes20(executionCalldata[0:20]));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n function encodeSingle(\n address target,\n uint256 value,\n bytes memory callData\n )\n internal\n pure\n returns (bytes memory userOpCalldata)\n {\n userOpCalldata = abi.encodePacked(target, value, callData);\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n/* solhint-disable no-unused-import */\n\n// Types\nimport { CallType, ExecType, ModeCode } from \"../lib/ModeLib.sol\";\n\n// Structs\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\ninterface IERC7579Account {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by ERC-4337 EntryPoint.sol\n * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @dev Ensure adequate authorization control: i.e. onlyExecutorModule\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function executeFromExecutor(\n ModeCode mode,\n bytes calldata executionCalldata\n )\n external\n payable\n returns (bytes[] memory returnData);\n\n /**\n * @dev ERC-1271 isValidSignature\n * This function is intended to be used to validate a smart account signature\n * and may forward the call to a validator module\n *\n * @param hash The hash of the data that is signed\n * @param data The data that is signed\n */\n function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);\n\n /**\n * @dev installs a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be required on the module during `onInstall`\n * initialization.\n */\n function installModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata initData\n )\n external\n payable;\n\n /**\n * @dev uninstalls a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be required on the module during `onUninstall`\n * de-initialization.\n */\n function uninstallModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata deInitData\n )\n external\n payable;\n\n /**\n * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)\n * @param encodedMode the encoded mode\n */\n function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);\n\n /**\n * Function to check if the account supports installation of a certain module type Id\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n\n /**\n * Function to check if the account has a certain module installed\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * Note: keep in mind that some contracts can be multiple module types at the same time. It\n * thus may be necessary to query multiple module types\n * @param module the module address\n * @param additionalContext additional context data that the smart account may interpret to\n * identifiy conditions under which the module is installed.\n * usually this is not necessary, but for some special hooks that\n * are stored in mappings, this param might be needed\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n )\n external\n view\n returns (bool);\n\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n * the accountId should be structured like so:\n * \"vendorname.accountname.semver\"\n */\n function accountId() external view returns (string memory accountImplementationId);\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/lib/ModeLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title ModeLib\n * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat)\n * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode\n * encoding is used.\n * Function Signature of execute function:\n * function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and\n * context.\n * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that\n * implement\n * more complex execution modes may use the entire bytes32.\n *\n * |--------------------------------------------------------------------|\n * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload |\n * |--------------------------------------------------------------------|\n * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes |\n * |--------------------------------------------------------------------|\n *\n * CALLTYPE: 1 byte\n * CallType is used to determine how the executeCalldata paramter of the execute function has to be\n * decoded.\n * It can be either single, batch or delegatecall. In the future different calls could be added.\n * CALLTYPE can be used by a validation module to determine how to decode .\n *\n * EXECTYPE: 1 byte\n * ExecType is used to determine how the account should handle the execution.\n * It can indicate if the execution should revert on failure or continue execution.\n * In the future more execution modes may be added.\n * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in\n * a batch fails, the entire batch is reverted\n *\n * UNUSED: 4 bytes\n * Unused bytes are reserved for future use.\n *\n * ModeSelector: bytes4\n * The \"optional\" mode selector can be used by account vendors, to implement custom behavior in\n * their accounts.\n * the way a ModeSelector is to be calculated is bytes4(keccak256(\"vendorname.featurename\"))\n * this is to prevent collisions between different vendors, while allowing innovation and the\n * development of new features without coordination between ERC-7579 implementing accounts\n *\n * ModePayload: 22 bytes\n * Mode payload is used to pass additional data to the smart account execution, this may be\n * interpreted depending on the ModeSelector\n *\n * ExecutionCallData: n bytes\n * single, delegatecall or batch exec abi.encoded as bytes\n */\n\n// Custom type for improved developer experience\ntype ModeCode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ModeSelector is bytes4;\n\ntype ModePayload is bytes22;\n\n// Default CallType\nCallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n// Batched CallType\nCallType constant CALLTYPE_BATCH = CallType.wrap(0x01);\nCallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);\n// @dev Implementing delegatecall is OPTIONAL!\n// implement delegatecall with extreme care.\nCallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n// @dev default behavior is to revert on failure\n// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure\n// Since this is value 0x00, no additional encoding is required for simple accounts\nExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n// @dev account may elect to change execution behavior. For example \"try exec\" / \"allow fail\"\nExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\nModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));\n// Example declaration of a custom mode selector\nModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256(\"default.mode.offset\")));\n\n/**\n * @dev ModeLib is a helper library to encode/decode ModeCodes\n */\nlibrary ModeLib {\n function decode(ModeCode mode)\n internal\n pure\n returns (\n CallType _calltype,\n ExecType _execType,\n ModeSelector _modeSelector,\n ModePayload _modePayload\n )\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _calltype := mode\n _execType := shl(8, mode)\n _modeSelector := shl(48, mode)\n _modePayload := shl(80, mode)\n }\n }\n\n function encode(\n CallType callType,\n ExecType execType,\n ModeSelector mode,\n ModePayload payload\n )\n internal\n pure\n returns (ModeCode)\n {\n return ModeCode.wrap(\n bytes32(\n abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)\n )\n );\n }\n\n function encodeSimpleBatch() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function encodeSimpleSingle() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function getCallType(ModeCode mode) internal pure returns (CallType calltype) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n calltype := mode\n }\n }\n}\n\nusing { eqModeSelector as == } for ModeSelector global;\nusing { eqCallType as == } for CallType global;\nusing { neqCallType as != } for CallType global;\nusing { eqExecType as == } for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction neqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperOracle.standard-json-input.json b/script/locked-bytecode-dev/SuperOracle.standard-json-input.json new file mode 100644 index 000000000..92bbec5a5 --- /dev/null +++ b/script/locked-bytecode-dev/SuperOracle.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/oracles/SuperOracle.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// Superform\nimport { SuperOracleBase } from \"./SuperOracleBase.sol\";\n\n/// @title SuperOracle\n/// @author Superform Labs\n/// @notice Oracle for Superform\ncontract SuperOracle is SuperOracleBase {\n constructor(\n address superGovernor_,\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n )\n SuperOracleBase(superGovernor_, bases, quotes, providers, feeds)\n { }\n}\n"},"src/oracles/SuperOracleBase.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { IOracle } from \"../vendor/awesome-oracles/IOracle.sol\";\nimport { AggregatorV3Interface } from \"../vendor/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"forge-std/interfaces/IERC20.sol\";\nimport { BoringERC20 } from \"../vendor/BoringSolidity/BoringERC20.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n// Superform\nimport { ISuperOracle } from \"../interfaces/oracles/ISuperOracle.sol\";\n\n/// @title SuperOracle\n/// @author Superform Labs\n/// @notice Oracle for Superform\nabstract contract SuperOracleBase is ISuperOracle, IOracle {\n using BoringERC20 for IERC20;\n\n /// @notice Mapping of feed to max staleness period\n mapping(address feed => uint256 maxStaleness) public feedMaxStaleness;\n\n uint256 public defaultStaleness;\n\n /// @notice Pending oracle update\n PendingUpdate public pendingUpdate;\n\n /// @notice Pending provider removal\n PendingRemoval public pendingRemoval;\n\n /// @notice Mapping of base asset to quote asset to oracle provider id to oracle feed address\n mapping(address base => mapping(address quote => mapping(bytes32 provider => address feed))) internal oracles;\n\n /// @notice Array of active provider ids\n bytes32[] public activeProviders;\n mapping(bytes32 provider => bool isSet) public isProviderSet;\n\n /// @notice Timelock period for oracle feed additions (1 week)\n /// @dev Long timelock protects against malicious oracle configurations that could manipulate pricing\n uint256 internal constant TIMELOCK_PERIOD = 1 weeks;\n /// @notice Short timelock period for provider removal (1 hour)\n /// @dev Trade-off: Short timelock enables rapid response to corrupted feeds (DoS prevention)\n /// but provides limited time to detect malicious governance actions. Removal is safer\n /// than addition since it only reduces available oracles rather than introducing new attack vectors.\n uint256 internal constant REMOVAL_TIMELOCK_PERIOD = 1 hours;\n /// @notice Maximum number of oracle providers to sample when calculating average price\n /// @dev Limits gas costs for getQuoteFromProvider(AVERAGE_PROVIDER).\n /// 10 providers balances price accuracy against gas costs (~300k gas for 10 oracle calls).\n /// See _getAverageQuote() for sampling logic.\n uint256 internal constant MAX_SAMPLE_PROVIDERS = 10;\n /// @notice Maximum number of providers that can be removed in a single queued removal\n /// @dev Prevents excessive gas costs in executeProviderRemoval() loop.\n /// Set to 20 (2x MAX_SAMPLE_PROVIDERS) to allow full provider rotation if needed.\n uint256 internal constant MAX_PROVIDER_REMOVALS = 20;\n bytes32 internal constant AVERAGE_PROVIDER = keccak256(\"AVERAGE_PROVIDER\");\n\n // SuperGovernor address\n address public immutable SUPER_GOVERNOR;\n\n /// @notice Initializes the oracle with governance authority and initial feed configurations\n /// @param superGovernor_ Immutable governance contract address (cannot be zero)\n /// @param bases Array of base asset addresses (token being priced)\n /// @param quotes Array of quote asset addresses (pricing denomination)\n /// @param providers Array of provider identifiers (e.g., keccak256(\"CHAINLINK\"))\n /// @param feeds Array of Chainlink aggregator addresses for corresponding base/quote/provider triples\n /// @dev All arrays must have equal length. Sets default staleness to 1 day.\n constructor(\n address superGovernor_,\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n ) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n SUPER_GOVERNOR = superGovernor_;\n defaultStaleness = 1 days;\n\n uint256 len = bases.length;\n if (len != quotes.length || len != providers.length || len != feeds.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n // validate oracle inputs\n _validateOracleInputs(bases, quotes, providers, feeds);\n\n // configure oracles\n _configureOracles(bases, quotes, providers, feeds);\n emit OraclesConfigured(bases, quotes, providers, feeds);\n uint256 length = feeds.length;\n for (uint256 i; i < length; ++i) {\n feedMaxStaleness[feeds[i]] = defaultStaleness;\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperOracle\n function setDefaultStaleness(uint256 newMaxStaleness) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n defaultStaleness = newMaxStaleness;\n emit MaxStalenessUpdated(newMaxStaleness);\n }\n\n /// @inheritdoc ISuperOracle\n function setFeedMaxStaleness(address feed, uint256 newMaxStaleness) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n _setFeedMaxStaleness(feed, newMaxStaleness);\n }\n\n /// @inheritdoc ISuperOracle\n function setFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n uint256 length = feeds.length;\n if (length == 0) revert ZERO_ARRAY_LENGTH();\n if (length != newMaxStalenessList.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n for (uint256 i; i < length; ++i) {\n _setFeedMaxStaleness(feeds[i], newMaxStalenessList[i]);\n }\n }\n\n /// @inheritdoc ISuperOracle\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external\n {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n uint256 length = bases.length;\n if (length != quotes.length || length != providers.length || length != feeds.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n _validateOracleInputs(bases, quotes, providers, feeds);\n\n pendingUpdate = PendingUpdate({\n bases: bases, quotes: quotes, providers: providers, feeds: feeds, timestamp: block.timestamp\n });\n\n emit OracleUpdateQueued(bases, quotes, providers, feeds, block.timestamp);\n }\n\n /// @inheritdoc ISuperOracle\n function executeOracleUpdate() external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n if (pendingUpdate.timestamp == 0) revert NO_PENDING_UPDATE();\n if (block.timestamp < pendingUpdate.timestamp + TIMELOCK_PERIOD) revert TIMELOCK_NOT_ELAPSED();\n\n _configureOracles(pendingUpdate.bases, pendingUpdate.quotes, pendingUpdate.providers, pendingUpdate.feeds);\n\n emit OracleUpdateExecuted(\n pendingUpdate.bases, pendingUpdate.quotes, pendingUpdate.providers, pendingUpdate.feeds\n );\n\n delete pendingUpdate;\n }\n\n /// @inheritdoc ISuperOracle\n function getOracleAddress(address base, address quote, bytes32 provider) external view returns (address oracle) {\n if (!isProviderSet[provider]) revert INVALID_ORACLE_PROVIDER();\n oracle = oracles[base][quote][provider];\n if (oracle == address(0)) revert NO_ORACLES_CONFIGURED();\n }\n\n /// @inheritdoc ISuperOracle\n function queueProviderRemoval(bytes32[] calldata providers) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n if (pendingRemoval.timestamp != 0) revert PENDING_UPDATE_EXISTS();\n\n uint256 length = providers.length;\n if (length == 0) revert ZERO_ARRAY_LENGTH();\n\n if (length > MAX_PROVIDER_REMOVALS) revert TOO_MANY_PROVIDERS();\n\n pendingRemoval = PendingRemoval({ providers: providers, timestamp: block.timestamp });\n\n emit ProviderRemovalQueued(providers, block.timestamp);\n }\n\n /// @inheritdoc ISuperOracle\n function executeProviderRemoval() external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n if (pendingRemoval.timestamp == 0) revert NO_PENDING_UPDATE();\n if (block.timestamp < pendingRemoval.timestamp + REMOVAL_TIMELOCK_PERIOD) revert TIMELOCK_NOT_ELAPSED();\n\n bytes32[] memory providersToRemove = pendingRemoval.providers;\n\n // Loop through each provider to remove\n for (uint256 i; i < providersToRemove.length; i++) {\n bytes32 providerToRemove = providersToRemove[i];\n isProviderSet[providerToRemove] = false;\n\n // Find the provider in activeProviders array\n for (uint256 j; j < activeProviders.length; j++) {\n if (activeProviders[j] == providerToRemove) {\n // Replace the provider to remove with the last provider in the array\n if (j < activeProviders.length - 1) {\n activeProviders[j] = activeProviders[activeProviders.length - 1];\n }\n\n // Remove the last element\n activeProviders.pop();\n break;\n }\n }\n }\n\n emit ProviderRemovalExecuted(providersToRemove);\n\n delete pendingRemoval;\n }\n\n /// @inheritdoc ISuperOracle\n function cancelProviderRemoval() external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n if (pendingRemoval.timestamp == 0) revert NO_PENDING_UPDATE();\n\n bytes32[] memory cancelledProviders = pendingRemoval.providers;\n\n delete pendingRemoval;\n\n emit ProviderRemovalCancelled(cancelledProviders);\n }\n\n /// @inheritdoc ISuperOracle\n function getActiveProviders() external view returns (bytes32[] memory) {\n return activeProviders;\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperOracle\n function getQuoteFromProvider(\n uint256 baseAmount,\n address base,\n address quote,\n bytes32 oracleProvider\n )\n public\n view\n virtual\n returns (uint256 quoteAmount, uint256 deviation, uint256 totalProviders, uint256 availableProviders)\n {\n // If average, calculate average of all oracles\n if (oracleProvider == AVERAGE_PROVIDER) {\n // activeProviders.length is already capped at MAX_SAMPLE_PROVIDERS by _configureOracles\n uint256 length = activeProviders.length;\n uint256[] memory validQuotes = new uint256[](length);\n uint256 count;\n (quoteAmount, validQuotes, totalProviders, count) = _getAverageQuote(base, quote, baseAmount, length);\n availableProviders = count;\n deviation = _calculateStdDev(validQuotes, count);\n } else {\n if (!isProviderSet[oracleProvider]) revert ORACLE_UNTRUSTED_DATA();\n address _oracle = oracles[base][quote][oracleProvider];\n if (_oracle == address(0)) revert NO_ORACLES_CONFIGURED();\n quoteAmount = _getQuoteFromOracle(_oracle, baseAmount, base, quote, true);\n deviation = 0;\n totalProviders = 1;\n availableProviders = 1;\n }\n }\n\n /// @inheritdoc IOracle\n function getQuote(\n uint256 baseAmount,\n address base,\n address quote\n )\n external\n view\n virtual\n returns (uint256 quoteAmount)\n {\n // using IOracle interface we always assume average provider\n (quoteAmount,,,) = getQuoteFromProvider(baseAmount, base, quote, AVERAGE_PROVIDER);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n function _validateOracleInputs(\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n )\n internal\n pure\n {\n uint256 length = bases.length;\n for (uint256 i; i < length; ++i) {\n address base = bases[i];\n address quote = quotes[i];\n bytes32 provider = providers[i];\n address feed = feeds[i];\n\n if (provider == bytes32(0)) revert ZERO_PROVIDER();\n if (provider == AVERAGE_PROVIDER) revert AVERAGE_PROVIDER_NOT_ALLOWED();\n if (base == address(0) || quote == address(0) || feed == address(0)) revert ZERO_ADDRESS();\n }\n }\n\n /// @notice Internal setter for feed-specific staleness limits\n /// @param feed Oracle feed address\n /// @param newMaxStaleness Maximum staleness in seconds (0 means use defaultStaleness)\n /// @dev If newMaxStaleness > defaultStaleness, reverts with MAX_STALENESS_EXCEEDED.\n /// Setting to 0 resets to defaultStaleness.\n function _setFeedMaxStaleness(address feed, uint256 newMaxStaleness) internal {\n if (newMaxStaleness > defaultStaleness) {\n revert MAX_STALENESS_EXCEEDED();\n }\n if (newMaxStaleness == 0) {\n newMaxStaleness = defaultStaleness;\n }\n feedMaxStaleness[feed] = newMaxStaleness;\n emit FeedMaxStalenessUpdated(feed, newMaxStaleness);\n }\n\n function _getQuoteFromOracle(\n address oracle,\n uint256 baseAmount,\n address base,\n address quote,\n bool revertOnError\n )\n internal\n view\n virtual\n returns (uint256 quoteAmount)\n {\n int256 answer;\n uint256 updatedAt;\n\n // --- Get round data ---\n uint256 gasBefore = gasleft();\n\n try AggregatorV3Interface(oracle).latestRoundData() returns (\n uint80, int256 _answer, uint256, uint256 _updatedAt, uint80\n ) {\n answer = _answer;\n updatedAt = _updatedAt;\n } catch {\n // Require that enough gas was provided to prevent an OOG revert\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (revertOnError && gasleft() <= gasBefore / 64) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n if (revertOnError) revert ORACLE_ROUND_DATA_CALL_FAIL(oracle);\n return 0;\n }\n\n // --- Validate data ---\n uint256 limit =\n feedMaxStaleness[oracle] == 0 ? defaultStaleness : Math.min(feedMaxStaleness[oracle], defaultStaleness);\n if (answer <= 0 || block.timestamp - updatedAt > limit) {\n if (revertOnError) revert ORACLE_UNTRUSTED_DATA();\n return 0;\n }\n\n gasBefore = gasleft();\n // --- Get decimals and compute scaled amount ---\n try AggregatorV3Interface(oracle).decimals() returns (uint8 feedDecimals) {\n uint8 baseDecimals = IERC20(base).safeDecimals();\n uint8 quoteDecimals = IERC20(quote).safeDecimals();\n\n // Calculate quote amount with proper decimal scaling\n // casting to 'uint256' is safe because the answer is a valid int256\n // forge-lint: disable-next-line(unsafe-typecast)\n quoteAmount = _scaleQuoteAmount(baseAmount, uint256(answer), feedDecimals, baseDecimals, quoteDecimals);\n } catch {\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (revertOnError && gasleft() <= gasBefore / 64) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n if (revertOnError) revert ORACLE_DECIMALS_CALL_FAIL(oracle);\n return 0;\n }\n }\n\n /// @notice Scales quote amount using proper decimal conversion\n /// @param baseAmount Amount of base asset\n /// @param answer Oracle price answer\n /// @param feedDecimals Decimals of the oracle feed\n /// @param baseDecimals Decimals of the base asset\n /// @param quoteDecimals Decimals of the quote asset\n /// @return quoteAmount Scaled quote amount\n /// @dev Formula: quoteAmount = (baseAmount * answer * 10^quoteDecimals) / (10^(feedDecimals + baseDecimals))\n /// This ensures proper decimal scaling across all three token types\n function _scaleQuoteAmount(\n uint256 baseAmount,\n uint256 answer,\n uint8 feedDecimals,\n uint8 baseDecimals,\n uint8 quoteDecimals\n )\n internal\n pure\n returns (uint256 quoteAmount)\n {\n return Math.mulDiv(baseAmount, uint256(answer) * 10 ** quoteDecimals, 10 ** (feedDecimals + baseDecimals));\n }\n\n /// @notice Calculates average quote across multiple oracle providers\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param baseAmount Amount to convert\n /// @param numberOfProviders Maximum providers to sample (capped to activeProviders.length)\n /// @return quoteAmount Average of all valid oracle quotes\n /// @return validQuotes Array of valid quotes (only first `count` elements valid, rest are zero)\n /// @return totalCount Number of providers that have a configured oracle for this pair\n /// @return count Number of providers that successfully returned a valid quote\n /// @dev Gracefully skips providers without configured oracles or with untrusted data.\n /// Early exits after MAX_SAMPLE_PROVIDERS valid quotes to bound gas costs.\n /// Reverts only if NO valid quotes are found (all oracles failed or unconfigured).\n function _getAverageQuote(\n address base,\n address quote,\n uint256 baseAmount,\n uint256 numberOfProviders\n )\n internal\n view\n virtual\n returns (uint256 quoteAmount, uint256[] memory validQuotes, uint256 totalCount, uint256 count)\n {\n uint256 total;\n validQuotes = new uint256[](numberOfProviders);\n\n // Early exits after collecting MAX_SAMPLE_PROVIDERS valid quotes to bound gas usage.\n // Iterates through up to numberOfProviders registered oracles (capped at MAX_SAMPLE_PROVIDERS).\n for (uint256 i; i < numberOfProviders; ++i) {\n bytes32 provider = activeProviders[i];\n address providerOracle = oracles[base][quote][provider];\n // provider is in active list but has no available oracle address\n /*\n base = ETH\n quote = [USD, EUR]\n providers = [CHAINLINK, eORACLE]\n\n Let's say we have\n\n ETH -> USD -> CHAINLINK -> address(0x1)\n ETH -> USD - eORACLE -> address(0x2)\n ETH -> EUR -> CHAINLINK -> address(0x3)\n\n This would just continue for\n\n ETH -> EUR -> eOracle, because oracle address is 0\n */\n if (providerOracle == address(0)) continue;\n\n // We have one more registered oracle for this base asset\n unchecked {\n ++totalCount;\n }\n\n uint256 quote_ = _getQuoteFromOracle(providerOracle, baseAmount, base, quote, false);\n\n /// @dev we don't revert on error, we just skip the oracle value\n if (quote_ > 0) {\n total += quote_;\n validQuotes[count] = quote_;\n // This oracle is available\n unchecked {\n ++count;\n }\n if (count == MAX_SAMPLE_PROVIDERS) {\n break;\n }\n }\n }\n if (count == 0) revert NO_VALID_REPORTED_PRICES();\n\n quoteAmount = total / count;\n }\n\n function _getOracleDecimals(AggregatorV3Interface oracle_) internal view virtual returns (uint8) {\n return oracle_.decimals();\n }\n\n /// @notice Calculates standard deviation of oracle price quotes\n /// @param values Array of quote values\n /// @param length Number of valid elements in values array (first `length` elements)\n /// @return stddev Standard deviation (square root of variance)\n /// @dev Uses Babylonian square root method (_sqrt). Returns 0 if fewer than 2 values.\n /// Used by getQuoteFromProvider() to measure price deviation across oracle providers.\n function _calculateStdDev(uint256[] memory values, uint256 length) internal pure virtual returns (uint256 stddev) {\n uint256 sum = 0;\n uint256 count = 0;\n for (uint256 i; i < length; ++i) {\n sum += values[i];\n count++;\n }\n if (count < 2) return 0;\n\n uint256 mean = sum / count;\n uint256 sumSquaredDiff = 0;\n for (uint256 i; i < length; ++i) {\n uint256 diff;\n if (values[i] >= mean) {\n diff = values[i] - mean;\n } else {\n diff = mean - values[i];\n }\n\n uint256 squaredDiff = Math.mulDiv(diff, diff, 1);\n sumSquaredDiff += squaredDiff;\n }\n\n uint256 variance = sumSquaredDiff / count;\n return _sqrt(variance);\n }\n\n /// @notice Calculates integer square root using Babylonian method\n /// @param x Value to calculate square root of\n /// @return y Integer square root (rounded down)\n /// @dev Iterative convergence algorithm. Safe for all uint256 values.\n function _sqrt(uint256 x) internal pure returns (uint256 y) {\n if (x == 0) return 0;\n\n uint256 z = (x + 1) / 2;\n y = x;\n\n while (z < y) {\n y = z;\n z = (x / z + z) / 2;\n }\n }\n\n /// @notice Internal function to configure oracle feeds and update active provider list\n /// @param bases Array of base asset addresses\n /// @param quotes Array of quote asset addresses\n /// @param providers Array of provider identifiers\n /// @param feeds Array of Chainlink aggregator addresses\n /// @dev Validates inputs via _validateOracleInputs() before calling.\n /// Automatically adds new providers to activeProviders array (up to MAX_SAMPLE_PROVIDERS).\n /// Reverts if adding a provider would exceed MAX_SAMPLE_PROVIDERS limit.\n function _configureOracles(\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n )\n internal\n {\n uint256 length = bases.length;\n\n for (uint256 i; i < length; ++i) {\n address base = bases[i];\n address quote = quotes[i];\n bytes32 provider = providers[i];\n address feed = feeds[i];\n\n oracles[base][quote][provider] = feed;\n\n // Update activeProviders array - add provider if not already present\n bool providerExists = isProviderSet[provider];\n if (!providerExists) {\n if (activeProviders.length >= MAX_SAMPLE_PROVIDERS) {\n revert TOO_MANY_PROVIDERS();\n }\n activeProviders.push(provider);\n isProviderSet[provider] = true;\n }\n }\n }\n}\n"},"src/vendor/awesome-oracles/IOracle.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\n/// @title Common interface for price oracles.\n/// @dev Implements the spec at https://eips.ethereum.org/EIPS/eip-7726\ninterface IOracle {\n /// @notice The oracle does not support the given base/quote pair.\n /// @param base The asset that the user needs to know the value or price for.\n /// @param quote The asset in which the user needs to value or price the base.\n error OracleUnsupportedPair(address base, address quote);\n\n /// @notice The oracle is not capable to provide data within a degree of confidence.\n /// @param base The asset that the user needs to know the value or price for.\n /// @param quote The asset in which the user needs to value or price the base.\n error OracleUntrustedData(address base, address quote);\n\n /// @notice Returns the value of `baseAmount` of `base` in `quote` terms.\n /// @dev MUST round down towards 0.\n /// MUST revert with `OracleUnsupportedPair` if not capable to provide data for the specified `base` and `quote`\n /// pair.\n /// MUST revert with `OracleUntrustedData` if not capable to provide data within a degree of confidence publicly\n /// specified.\n /// @param baseAmount The amount of `base` to convert.\n /// @param base The asset that the user needs to know the value for.\n /// @param quote The asset in which the user needs to value the base.\n /// @return quoteAmount The value of `baseAmount` of `base` in `quote` terms\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n"},"src/vendor/chainlink/AggregatorV3Interface.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function latestRoundData()\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"},"lib/forge-std/src/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @dev This includes the optional name, symbol, and decimals metadata.\ninterface IERC20 {\n /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`\n /// is the new allowance.\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// @notice Returns the amount of tokens in existence.\n function totalSupply() external view returns (uint256);\n\n /// @notice Returns the amount of tokens owned by `account`.\n function balanceOf(address account) external view returns (uint256);\n\n /// @notice Moves `amount` tokens from the caller's account to `to`.\n function transfer(address to, uint256 amount) external returns (bool);\n\n /// @notice Returns the remaining number of tokens that `spender` is allowed\n /// to spend on behalf of `owner`\n function allowance(address owner, address spender) external view returns (uint256);\n\n /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.\n /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n function approve(address spender, uint256 amount) external returns (bool);\n\n /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.\n /// `amount` is then deducted from the caller's allowance.\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n\n /// @notice Returns the name of the token.\n function name() external view returns (string memory);\n\n /// @notice Returns the symbol of the token.\n function symbol() external view returns (string memory);\n\n /// @notice Returns the decimals places of the token.\n function decimals() external view returns (uint8);\n}\n"},"src/vendor/BoringSolidity/BoringERC20.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\n// With thanks to @BoringCrypto\npragma solidity >=0.8.19;\n\nimport { IERC20 } from \"forge-std/interfaces/IERC20.sol\";\n\n// solhint-disable avoid-low-level-calls\n\nlibrary BoringERC20 {\n bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()\n\n /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.\n /// @param token The address of the ERC-20 token contract.\n /// @return (uint8) Token decimals.\n function safeDecimals(IERC20 token) internal view returns (uint8) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));\n return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"src/interfaces/oracles/ISuperOracle.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperOracle\n/// @author Superform Labs\n/// @notice Interface for SuperOracle\ninterface ISuperOracle {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Error when address is zero\n error ZERO_ADDRESS();\n\n /// @notice Error when array length is zero\n error ZERO_ARRAY_LENGTH();\n\n /// @notice Error when oracle provider index is invalid\n error INVALID_ORACLE_PROVIDER();\n\n /// @notice Error when no oracles are configured for base asset\n error NO_ORACLES_CONFIGURED();\n\n /// @notice Error when no valid reported prices are found\n error NO_VALID_REPORTED_PRICES();\n\n /// @notice Error when arrays have mismatched lengths\n error ARRAY_LENGTH_MISMATCH();\n\n /// @notice Error when timelock period has not elapsed\n error TIMELOCK_NOT_ELAPSED();\n\n /// @notice Error when there is already a pending update\n error PENDING_UPDATE_EXISTS();\n\n /// @notice Error when oracle data is untrusted\n error ORACLE_UNTRUSTED_DATA();\n\n /// @notice Error when provider max staleness period is not set\n error NO_PENDING_UPDATE();\n\n /// @notice Error when provider max staleness period is exceeded\n error MAX_STALENESS_EXCEEDED();\n\n /// @notice Error when average provider is not allowed\n error AVERAGE_PROVIDER_NOT_ALLOWED();\n\n /// @notice Error when provider is zero\n error ZERO_PROVIDER();\n\n /// @notice Error when too many providers are being iterated through\n error TOO_MANY_PROVIDERS();\n\n /// @notice Error when caller is not authorized to update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n\n /// @notice Error when oracle decimals call fails\n error ORACLE_DECIMALS_CALL_FAIL(address oracle);\n\n /// @notice Error when oracle round data call fails\n error ORACLE_ROUND_DATA_CALL_FAIL(address oracle);\n\n /// @notice Error when external call gas is insufficient\n error INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when oracles are configured\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n event OraclesConfigured(address[] bases, address[] quotes, bytes32[] providers, address[] feeds);\n\n /// @notice Emitted when oracle update is queued\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n /// @param timestamp Timestamp when update was queued\n event OracleUpdateQueued(\n address[] bases, address[] quotes, bytes32[] providers, address[] feeds, uint256 timestamp\n );\n\n /// @notice Emitted when oracle update is executed\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n event OracleUpdateExecuted(address[] bases, address[] quotes, bytes32[] providers, address[] feeds);\n\n /// @notice Emitted when provider max staleness period is updated\n /// @param feed Feed address\n /// @param newMaxStaleness New maximum staleness period in seconds\n event FeedMaxStalenessUpdated(address feed, uint256 newMaxStaleness);\n\n /// @notice Emitted when max staleness period is updated\n /// @param newMaxStaleness New maximum staleness period in seconds\n event MaxStalenessUpdated(uint256 newMaxStaleness);\n\n /// @notice Emitted when provider removal is queued\n /// @param providers Array of provider ids to remove\n /// @param timestamp Timestamp when removal was queued\n event ProviderRemovalQueued(bytes32[] providers, uint256 timestamp);\n\n /// @notice Emitted when provider removal is executed\n /// @param providers Array of provider ids that were removed\n event ProviderRemovalExecuted(bytes32[] providers);\n\n /// @notice Emitted when provider removal is cancelled\n /// @param providers Array of provider ids that were queued for removal\n event ProviderRemovalCancelled(bytes32[] providers);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Struct for pending oracle update\n struct PendingUpdate {\n address[] bases;\n address[] quotes;\n bytes32[] providers;\n address[] feeds;\n uint256 timestamp;\n }\n\n /// @notice Struct for pending provider removal\n struct PendingRemoval {\n bytes32[] providers;\n uint256 timestamp;\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get oracle address for a base asset and provider\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param provider Provider id\n /// @return oracle Oracle address\n function getOracleAddress(address base, address quote, bytes32 provider) external view returns (address oracle);\n\n /// @notice Get quote from specified oracle provider\n /// @param baseAmount Amount of base asset\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param oracleProvider Id of oracle provider to use\n /// @return quoteAmount The quote amount\n /// @return deviation Standard deviation of oracle quotes in quote asset units (0 for single provider)\n /// @return totalProviders Total number of providers that have a configured oracle for this pair\n /// @return availableProviders Number of providers that successfully returned a valid quote\n function getQuoteFromProvider(\n uint256 baseAmount,\n address base,\n address quote,\n bytes32 oracleProvider\n )\n external\n view\n returns (uint256 quoteAmount, uint256 deviation, uint256 totalProviders, uint256 availableProviders);\n\n /// @notice Queue oracle update for timelock\n /// @param bases Array of base assets\n /// @param providers Array of provider ids\n /// @param quotes Array of quote assets\n /// @param feeds Array of oracle addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Execute queued oracle update after timelock period\n function executeOracleUpdate() external;\n\n /// @notice Queue provider removal for timelock\n /// @param providers Array of provider ids to remove\n function queueProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Execute queued provider removal after timelock period\n function executeProviderRemoval() external;\n\n /// @notice Cancel queued provider removal\n function cancelProviderRemoval() external;\n\n /// @notice Set the maximum staleness period for a specific provider\n /// @param feed Feed address\n /// @param newMaxStaleness New maximum staleness period in seconds\n function setFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Set the maximum staleness period for all providers\n /// @param newMaxStaleness New maximum staleness period in seconds\n function setDefaultStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Set the maximum staleness period for multiple providers\n /// @param feeds Array of feed addresses\n /// @param newMaxStalenessList Array of new maximum staleness periods in seconds\n function setFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Get all active provider ids\n /// @return Array of active provider ids\n function getActiveProviders() external view returns (bytes32[] memory);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperOracleL2.standard-json-input.json b/script/locked-bytecode-dev/SuperOracleL2.standard-json-input.json new file mode 100644 index 000000000..e73208b7e --- /dev/null +++ b/script/locked-bytecode-dev/SuperOracleL2.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/oracles/SuperOracleL2.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// Superform\n\nimport { SuperOracleBase } from \"./SuperOracleBase.sol\";\nimport { ISuperOracleL2 } from \"../interfaces/oracles/ISuperOracleL2.sol\";\n\n// external\nimport { IERC20 } from \"forge-std/interfaces/IERC20.sol\";\nimport { BoringERC20 } from \"../vendor/BoringSolidity/BoringERC20.sol\";\nimport { AggregatorV3Interface } from \"../vendor/chainlink/AggregatorV3Interface.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n/// @title SuperOracleL2\n/// @author Superform Labs\n/// @notice Layer 2 Oracle for Superform\ncontract SuperOracleL2 is SuperOracleBase, ISuperOracleL2 {\n using BoringERC20 for IERC20;\n\n /*//////////////////////////////////////////////////////////////\n STORAGE\n //////////////////////////////////////////////////////////////*/\n mapping(address dataOracle => address uptimeOracle) public uptimeFeeds;\n mapping(address uptimeOracle => uint256 gracePeriod) public gracePeriods;\n\n /// @notice Default grace period after L2 sequencer restart (1 hour)\n /// @dev Prevents stale prices from being used immediately after sequencer downtime.\n /// Price feeds collected during downtime may be unreliable or manipulated.\n uint256 private constant DEFAULT_GRACE_PERIOD_TIME = 3600;\n\n /// @notice Minimum allowed grace period (10 minutes)\n /// @dev Lower bound to ensure reasonable protection against stale data after sequencer restart\n uint256 private constant MIN_GRACE_PERIOD_TIME = 600;\n\n constructor(\n address superGovernor_,\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n )\n SuperOracleBase(superGovernor_, bases, quotes, providers, feeds)\n { }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperOracleL2\n function batchSetUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods_\n )\n external\n override\n {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n uint256 length = dataOracles.length;\n if (length == 0) revert ZERO_ARRAY_LENGTH();\n if (length != uptimeOracles.length || length != gracePeriods_.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n for (uint256 i; i < length; ++i) {\n address dataOracle = dataOracles[i];\n address uptimeOracle = uptimeOracles[i];\n uint256 gracePeriod = gracePeriods_[i];\n if (gracePeriod != 0 && gracePeriod < MIN_GRACE_PERIOD_TIME) revert GRACE_PERIOD_TOO_LOW();\n\n if (dataOracle == address(0) || uptimeOracle == address(0)) revert ZERO_ADDRESS();\n\n uptimeFeeds[dataOracle] = uptimeOracle;\n gracePeriods[uptimeOracle] = gracePeriod;\n\n emit UptimeFeedSet(dataOracle, uptimeOracle);\n emit GracePeriodSet(uptimeOracle, gracePeriod);\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n function _getQuoteFromOracle(\n address oracle,\n uint256 baseAmount,\n address base,\n address quote,\n bool revertOnError\n )\n internal\n view\n override\n returns (uint256 quoteAmount)\n {\n int256 answer;\n uint256 updatedAt;\n\n {\n address uptimeOracle = uptimeFeeds[oracle];\n if (uptimeOracle == address(0)) {\n if (revertOnError) revert NO_UPTIME_FEED();\n return 0;\n }\n\n // --- Get uptime round data ---\n uint256 gasBeforeUptime = gasleft();\n int256 uptimeAnswer;\n uint256 startedAt;\n\n try AggregatorV3Interface(uptimeOracle).latestRoundData() returns (\n uint80, int256 _uptimeAnswer, uint256 _startedAt, uint256, uint80\n ) {\n uptimeAnswer = _uptimeAnswer;\n startedAt = _startedAt;\n } catch {\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (gasleft() <= gasBeforeUptime / 64 && revertOnError) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n if (revertOnError) revert ORACLE_ROUND_DATA_CALL_FAIL(uptimeOracle);\n return 0;\n }\n\n // Answer == 0: Sequencer is up\n // Answer == 1: Sequencer is down\n bool isSequencerUp = uptimeAnswer == 0;\n if (!isSequencerUp) {\n if (revertOnError) revert SEQUENCER_DOWN();\n return 0;\n }\n\n // Make sure the grace period has passed after the\n // sequencer is back up.\n uint256 timeSinceUp = block.timestamp - startedAt;\n uint256 gracePeriod = gracePeriods[uptimeOracle];\n if (gracePeriod == 0) {\n gracePeriod = DEFAULT_GRACE_PERIOD_TIME;\n }\n if (timeSinceUp <= gracePeriod) {\n if (revertOnError) revert GRACE_PERIOD_NOT_OVER();\n return 0;\n }\n }\n\n // --- Get data oracle round data ---\n {\n uint256 gasBeforeData = gasleft();\n\n try AggregatorV3Interface(oracle).latestRoundData() returns (\n uint80, int256 _answer, uint256, uint256 _updatedAt, uint80\n ) {\n answer = _answer;\n updatedAt = _updatedAt;\n } catch {\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (gasleft() <= gasBeforeData / 64 && revertOnError) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n if (revertOnError) revert ORACLE_ROUND_DATA_CALL_FAIL(oracle);\n return 0;\n }\n }\n\n // Validate data\n uint256 limit =\n feedMaxStaleness[oracle] == 0 ? defaultStaleness : Math.min(feedMaxStaleness[oracle], defaultStaleness);\n if (answer <= 0 || block.timestamp - updatedAt > limit) {\n if (revertOnError) revert ORACLE_UNTRUSTED_DATA();\n return 0;\n }\n\n // Get decimals with error handling\n uint256 gasBefore = gasleft();\n try AggregatorV3Interface(oracle).decimals() returns (uint8 feedDecimals) {\n uint8 baseDecimals = IERC20(base).safeDecimals();\n uint8 quoteDecimals = IERC20(quote).safeDecimals();\n\n // Calculate quote amount with proper decimal scaling using shared function\n // casting to 'uint256' is safe because the answer is a valid int256\n // forge-lint: disable-next-line(unsafe-typecast)\n quoteAmount = _scaleQuoteAmount(baseAmount, uint256(answer), feedDecimals, baseDecimals, quoteDecimals);\n } catch {\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (gasleft() <= gasBefore / 64 && revertOnError) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n if (revertOnError) revert ORACLE_DECIMALS_CALL_FAIL(oracle);\n return 0;\n }\n }\n}\n"},"src/oracles/SuperOracleBase.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { IOracle } from \"../vendor/awesome-oracles/IOracle.sol\";\nimport { AggregatorV3Interface } from \"../vendor/chainlink/AggregatorV3Interface.sol\";\nimport { IERC20 } from \"forge-std/interfaces/IERC20.sol\";\nimport { BoringERC20 } from \"../vendor/BoringSolidity/BoringERC20.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n// Superform\nimport { ISuperOracle } from \"../interfaces/oracles/ISuperOracle.sol\";\n\n/// @title SuperOracle\n/// @author Superform Labs\n/// @notice Oracle for Superform\nabstract contract SuperOracleBase is ISuperOracle, IOracle {\n using BoringERC20 for IERC20;\n\n /// @notice Mapping of feed to max staleness period\n mapping(address feed => uint256 maxStaleness) public feedMaxStaleness;\n\n uint256 public defaultStaleness;\n\n /// @notice Pending oracle update\n PendingUpdate public pendingUpdate;\n\n /// @notice Pending provider removal\n PendingRemoval public pendingRemoval;\n\n /// @notice Mapping of base asset to quote asset to oracle provider id to oracle feed address\n mapping(address base => mapping(address quote => mapping(bytes32 provider => address feed))) internal oracles;\n\n /// @notice Array of active provider ids\n bytes32[] public activeProviders;\n mapping(bytes32 provider => bool isSet) public isProviderSet;\n\n /// @notice Timelock period for oracle feed additions (1 week)\n /// @dev Long timelock protects against malicious oracle configurations that could manipulate pricing\n uint256 internal constant TIMELOCK_PERIOD = 1 weeks;\n /// @notice Short timelock period for provider removal (1 hour)\n /// @dev Trade-off: Short timelock enables rapid response to corrupted feeds (DoS prevention)\n /// but provides limited time to detect malicious governance actions. Removal is safer\n /// than addition since it only reduces available oracles rather than introducing new attack vectors.\n uint256 internal constant REMOVAL_TIMELOCK_PERIOD = 1 hours;\n /// @notice Maximum number of oracle providers to sample when calculating average price\n /// @dev Limits gas costs for getQuoteFromProvider(AVERAGE_PROVIDER).\n /// 10 providers balances price accuracy against gas costs (~300k gas for 10 oracle calls).\n /// See _getAverageQuote() for sampling logic.\n uint256 internal constant MAX_SAMPLE_PROVIDERS = 10;\n /// @notice Maximum number of providers that can be removed in a single queued removal\n /// @dev Prevents excessive gas costs in executeProviderRemoval() loop.\n /// Set to 20 (2x MAX_SAMPLE_PROVIDERS) to allow full provider rotation if needed.\n uint256 internal constant MAX_PROVIDER_REMOVALS = 20;\n bytes32 internal constant AVERAGE_PROVIDER = keccak256(\"AVERAGE_PROVIDER\");\n\n // SuperGovernor address\n address public immutable SUPER_GOVERNOR;\n\n /// @notice Initializes the oracle with governance authority and initial feed configurations\n /// @param superGovernor_ Immutable governance contract address (cannot be zero)\n /// @param bases Array of base asset addresses (token being priced)\n /// @param quotes Array of quote asset addresses (pricing denomination)\n /// @param providers Array of provider identifiers (e.g., keccak256(\"CHAINLINK\"))\n /// @param feeds Array of Chainlink aggregator addresses for corresponding base/quote/provider triples\n /// @dev All arrays must have equal length. Sets default staleness to 1 day.\n constructor(\n address superGovernor_,\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n ) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n SUPER_GOVERNOR = superGovernor_;\n defaultStaleness = 1 days;\n\n uint256 len = bases.length;\n if (len != quotes.length || len != providers.length || len != feeds.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n // validate oracle inputs\n _validateOracleInputs(bases, quotes, providers, feeds);\n\n // configure oracles\n _configureOracles(bases, quotes, providers, feeds);\n emit OraclesConfigured(bases, quotes, providers, feeds);\n uint256 length = feeds.length;\n for (uint256 i; i < length; ++i) {\n feedMaxStaleness[feeds[i]] = defaultStaleness;\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperOracle\n function setDefaultStaleness(uint256 newMaxStaleness) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n defaultStaleness = newMaxStaleness;\n emit MaxStalenessUpdated(newMaxStaleness);\n }\n\n /// @inheritdoc ISuperOracle\n function setFeedMaxStaleness(address feed, uint256 newMaxStaleness) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n _setFeedMaxStaleness(feed, newMaxStaleness);\n }\n\n /// @inheritdoc ISuperOracle\n function setFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n uint256 length = feeds.length;\n if (length == 0) revert ZERO_ARRAY_LENGTH();\n if (length != newMaxStalenessList.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n for (uint256 i; i < length; ++i) {\n _setFeedMaxStaleness(feeds[i], newMaxStalenessList[i]);\n }\n }\n\n /// @inheritdoc ISuperOracle\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external\n {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n uint256 length = bases.length;\n if (length != quotes.length || length != providers.length || length != feeds.length) {\n revert ARRAY_LENGTH_MISMATCH();\n }\n\n _validateOracleInputs(bases, quotes, providers, feeds);\n\n pendingUpdate = PendingUpdate({\n bases: bases, quotes: quotes, providers: providers, feeds: feeds, timestamp: block.timestamp\n });\n\n emit OracleUpdateQueued(bases, quotes, providers, feeds, block.timestamp);\n }\n\n /// @inheritdoc ISuperOracle\n function executeOracleUpdate() external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n if (pendingUpdate.timestamp == 0) revert NO_PENDING_UPDATE();\n if (block.timestamp < pendingUpdate.timestamp + TIMELOCK_PERIOD) revert TIMELOCK_NOT_ELAPSED();\n\n _configureOracles(pendingUpdate.bases, pendingUpdate.quotes, pendingUpdate.providers, pendingUpdate.feeds);\n\n emit OracleUpdateExecuted(\n pendingUpdate.bases, pendingUpdate.quotes, pendingUpdate.providers, pendingUpdate.feeds\n );\n\n delete pendingUpdate;\n }\n\n /// @inheritdoc ISuperOracle\n function getOracleAddress(address base, address quote, bytes32 provider) external view returns (address oracle) {\n if (!isProviderSet[provider]) revert INVALID_ORACLE_PROVIDER();\n oracle = oracles[base][quote][provider];\n if (oracle == address(0)) revert NO_ORACLES_CONFIGURED();\n }\n\n /// @inheritdoc ISuperOracle\n function queueProviderRemoval(bytes32[] calldata providers) external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n if (pendingRemoval.timestamp != 0) revert PENDING_UPDATE_EXISTS();\n\n uint256 length = providers.length;\n if (length == 0) revert ZERO_ARRAY_LENGTH();\n\n if (length > MAX_PROVIDER_REMOVALS) revert TOO_MANY_PROVIDERS();\n\n pendingRemoval = PendingRemoval({ providers: providers, timestamp: block.timestamp });\n\n emit ProviderRemovalQueued(providers, block.timestamp);\n }\n\n /// @inheritdoc ISuperOracle\n function executeProviderRemoval() external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n if (pendingRemoval.timestamp == 0) revert NO_PENDING_UPDATE();\n if (block.timestamp < pendingRemoval.timestamp + REMOVAL_TIMELOCK_PERIOD) revert TIMELOCK_NOT_ELAPSED();\n\n bytes32[] memory providersToRemove = pendingRemoval.providers;\n\n // Loop through each provider to remove\n for (uint256 i; i < providersToRemove.length; i++) {\n bytes32 providerToRemove = providersToRemove[i];\n isProviderSet[providerToRemove] = false;\n\n // Find the provider in activeProviders array\n for (uint256 j; j < activeProviders.length; j++) {\n if (activeProviders[j] == providerToRemove) {\n // Replace the provider to remove with the last provider in the array\n if (j < activeProviders.length - 1) {\n activeProviders[j] = activeProviders[activeProviders.length - 1];\n }\n\n // Remove the last element\n activeProviders.pop();\n break;\n }\n }\n }\n\n emit ProviderRemovalExecuted(providersToRemove);\n\n delete pendingRemoval;\n }\n\n /// @inheritdoc ISuperOracle\n function cancelProviderRemoval() external {\n if (msg.sender != SUPER_GOVERNOR) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n if (pendingRemoval.timestamp == 0) revert NO_PENDING_UPDATE();\n\n bytes32[] memory cancelledProviders = pendingRemoval.providers;\n\n delete pendingRemoval;\n\n emit ProviderRemovalCancelled(cancelledProviders);\n }\n\n /// @inheritdoc ISuperOracle\n function getActiveProviders() external view returns (bytes32[] memory) {\n return activeProviders;\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperOracle\n function getQuoteFromProvider(\n uint256 baseAmount,\n address base,\n address quote,\n bytes32 oracleProvider\n )\n public\n view\n virtual\n returns (uint256 quoteAmount, uint256 deviation, uint256 totalProviders, uint256 availableProviders)\n {\n // If average, calculate average of all oracles\n if (oracleProvider == AVERAGE_PROVIDER) {\n // activeProviders.length is already capped at MAX_SAMPLE_PROVIDERS by _configureOracles\n uint256 length = activeProviders.length;\n uint256[] memory validQuotes = new uint256[](length);\n uint256 count;\n (quoteAmount, validQuotes, totalProviders, count) = _getAverageQuote(base, quote, baseAmount, length);\n availableProviders = count;\n deviation = _calculateStdDev(validQuotes, count);\n } else {\n if (!isProviderSet[oracleProvider]) revert ORACLE_UNTRUSTED_DATA();\n address _oracle = oracles[base][quote][oracleProvider];\n if (_oracle == address(0)) revert NO_ORACLES_CONFIGURED();\n quoteAmount = _getQuoteFromOracle(_oracle, baseAmount, base, quote, true);\n deviation = 0;\n totalProviders = 1;\n availableProviders = 1;\n }\n }\n\n /// @inheritdoc IOracle\n function getQuote(\n uint256 baseAmount,\n address base,\n address quote\n )\n external\n view\n virtual\n returns (uint256 quoteAmount)\n {\n // using IOracle interface we always assume average provider\n (quoteAmount,,,) = getQuoteFromProvider(baseAmount, base, quote, AVERAGE_PROVIDER);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n function _validateOracleInputs(\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n )\n internal\n pure\n {\n uint256 length = bases.length;\n for (uint256 i; i < length; ++i) {\n address base = bases[i];\n address quote = quotes[i];\n bytes32 provider = providers[i];\n address feed = feeds[i];\n\n if (provider == bytes32(0)) revert ZERO_PROVIDER();\n if (provider == AVERAGE_PROVIDER) revert AVERAGE_PROVIDER_NOT_ALLOWED();\n if (base == address(0) || quote == address(0) || feed == address(0)) revert ZERO_ADDRESS();\n }\n }\n\n /// @notice Internal setter for feed-specific staleness limits\n /// @param feed Oracle feed address\n /// @param newMaxStaleness Maximum staleness in seconds (0 means use defaultStaleness)\n /// @dev If newMaxStaleness > defaultStaleness, reverts with MAX_STALENESS_EXCEEDED.\n /// Setting to 0 resets to defaultStaleness.\n function _setFeedMaxStaleness(address feed, uint256 newMaxStaleness) internal {\n if (newMaxStaleness > defaultStaleness) {\n revert MAX_STALENESS_EXCEEDED();\n }\n if (newMaxStaleness == 0) {\n newMaxStaleness = defaultStaleness;\n }\n feedMaxStaleness[feed] = newMaxStaleness;\n emit FeedMaxStalenessUpdated(feed, newMaxStaleness);\n }\n\n function _getQuoteFromOracle(\n address oracle,\n uint256 baseAmount,\n address base,\n address quote,\n bool revertOnError\n )\n internal\n view\n virtual\n returns (uint256 quoteAmount)\n {\n int256 answer;\n uint256 updatedAt;\n\n // --- Get round data ---\n uint256 gasBefore = gasleft();\n\n try AggregatorV3Interface(oracle).latestRoundData() returns (\n uint80, int256 _answer, uint256, uint256 _updatedAt, uint80\n ) {\n answer = _answer;\n updatedAt = _updatedAt;\n } catch {\n // Require that enough gas was provided to prevent an OOG revert\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (revertOnError && gasleft() <= gasBefore / 64) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n if (revertOnError) revert ORACLE_ROUND_DATA_CALL_FAIL(oracle);\n return 0;\n }\n\n // --- Validate data ---\n uint256 limit =\n feedMaxStaleness[oracle] == 0 ? defaultStaleness : Math.min(feedMaxStaleness[oracle], defaultStaleness);\n if (answer <= 0 || block.timestamp - updatedAt > limit) {\n if (revertOnError) revert ORACLE_UNTRUSTED_DATA();\n return 0;\n }\n\n gasBefore = gasleft();\n // --- Get decimals and compute scaled amount ---\n try AggregatorV3Interface(oracle).decimals() returns (uint8 feedDecimals) {\n uint8 baseDecimals = IERC20(base).safeDecimals();\n uint8 quoteDecimals = IERC20(quote).safeDecimals();\n\n // Calculate quote amount with proper decimal scaling\n // casting to 'uint256' is safe because the answer is a valid int256\n // forge-lint: disable-next-line(unsafe-typecast)\n quoteAmount = _scaleQuoteAmount(baseAmount, uint256(answer), feedDecimals, baseDecimals, quoteDecimals);\n } catch {\n // EIP-150: Ensure at least 1/64 of gas remained to prevent out-of-gas reverts being misinterpreted as\n // oracle failures\n if (revertOnError && gasleft() <= gasBefore / 64) revert INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n if (revertOnError) revert ORACLE_DECIMALS_CALL_FAIL(oracle);\n return 0;\n }\n }\n\n /// @notice Scales quote amount using proper decimal conversion\n /// @param baseAmount Amount of base asset\n /// @param answer Oracle price answer\n /// @param feedDecimals Decimals of the oracle feed\n /// @param baseDecimals Decimals of the base asset\n /// @param quoteDecimals Decimals of the quote asset\n /// @return quoteAmount Scaled quote amount\n /// @dev Formula: quoteAmount = (baseAmount * answer * 10^quoteDecimals) / (10^(feedDecimals + baseDecimals))\n /// This ensures proper decimal scaling across all three token types\n function _scaleQuoteAmount(\n uint256 baseAmount,\n uint256 answer,\n uint8 feedDecimals,\n uint8 baseDecimals,\n uint8 quoteDecimals\n )\n internal\n pure\n returns (uint256 quoteAmount)\n {\n return Math.mulDiv(baseAmount, uint256(answer) * 10 ** quoteDecimals, 10 ** (feedDecimals + baseDecimals));\n }\n\n /// @notice Calculates average quote across multiple oracle providers\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param baseAmount Amount to convert\n /// @param numberOfProviders Maximum providers to sample (capped to activeProviders.length)\n /// @return quoteAmount Average of all valid oracle quotes\n /// @return validQuotes Array of valid quotes (only first `count` elements valid, rest are zero)\n /// @return totalCount Number of providers that have a configured oracle for this pair\n /// @return count Number of providers that successfully returned a valid quote\n /// @dev Gracefully skips providers without configured oracles or with untrusted data.\n /// Early exits after MAX_SAMPLE_PROVIDERS valid quotes to bound gas costs.\n /// Reverts only if NO valid quotes are found (all oracles failed or unconfigured).\n function _getAverageQuote(\n address base,\n address quote,\n uint256 baseAmount,\n uint256 numberOfProviders\n )\n internal\n view\n virtual\n returns (uint256 quoteAmount, uint256[] memory validQuotes, uint256 totalCount, uint256 count)\n {\n uint256 total;\n validQuotes = new uint256[](numberOfProviders);\n\n // Early exits after collecting MAX_SAMPLE_PROVIDERS valid quotes to bound gas usage.\n // Iterates through up to numberOfProviders registered oracles (capped at MAX_SAMPLE_PROVIDERS).\n for (uint256 i; i < numberOfProviders; ++i) {\n bytes32 provider = activeProviders[i];\n address providerOracle = oracles[base][quote][provider];\n // provider is in active list but has no available oracle address\n /*\n base = ETH\n quote = [USD, EUR]\n providers = [CHAINLINK, eORACLE]\n\n Let's say we have\n\n ETH -> USD -> CHAINLINK -> address(0x1)\n ETH -> USD - eORACLE -> address(0x2)\n ETH -> EUR -> CHAINLINK -> address(0x3)\n\n This would just continue for\n\n ETH -> EUR -> eOracle, because oracle address is 0\n */\n if (providerOracle == address(0)) continue;\n\n // We have one more registered oracle for this base asset\n unchecked {\n ++totalCount;\n }\n\n uint256 quote_ = _getQuoteFromOracle(providerOracle, baseAmount, base, quote, false);\n\n /// @dev we don't revert on error, we just skip the oracle value\n if (quote_ > 0) {\n total += quote_;\n validQuotes[count] = quote_;\n // This oracle is available\n unchecked {\n ++count;\n }\n if (count == MAX_SAMPLE_PROVIDERS) {\n break;\n }\n }\n }\n if (count == 0) revert NO_VALID_REPORTED_PRICES();\n\n quoteAmount = total / count;\n }\n\n function _getOracleDecimals(AggregatorV3Interface oracle_) internal view virtual returns (uint8) {\n return oracle_.decimals();\n }\n\n /// @notice Calculates standard deviation of oracle price quotes\n /// @param values Array of quote values\n /// @param length Number of valid elements in values array (first `length` elements)\n /// @return stddev Standard deviation (square root of variance)\n /// @dev Uses Babylonian square root method (_sqrt). Returns 0 if fewer than 2 values.\n /// Used by getQuoteFromProvider() to measure price deviation across oracle providers.\n function _calculateStdDev(uint256[] memory values, uint256 length) internal pure virtual returns (uint256 stddev) {\n uint256 sum = 0;\n uint256 count = 0;\n for (uint256 i; i < length; ++i) {\n sum += values[i];\n count++;\n }\n if (count < 2) return 0;\n\n uint256 mean = sum / count;\n uint256 sumSquaredDiff = 0;\n for (uint256 i; i < length; ++i) {\n uint256 diff;\n if (values[i] >= mean) {\n diff = values[i] - mean;\n } else {\n diff = mean - values[i];\n }\n\n uint256 squaredDiff = Math.mulDiv(diff, diff, 1);\n sumSquaredDiff += squaredDiff;\n }\n\n uint256 variance = sumSquaredDiff / count;\n return _sqrt(variance);\n }\n\n /// @notice Calculates integer square root using Babylonian method\n /// @param x Value to calculate square root of\n /// @return y Integer square root (rounded down)\n /// @dev Iterative convergence algorithm. Safe for all uint256 values.\n function _sqrt(uint256 x) internal pure returns (uint256 y) {\n if (x == 0) return 0;\n\n uint256 z = (x + 1) / 2;\n y = x;\n\n while (z < y) {\n y = z;\n z = (x / z + z) / 2;\n }\n }\n\n /// @notice Internal function to configure oracle feeds and update active provider list\n /// @param bases Array of base asset addresses\n /// @param quotes Array of quote asset addresses\n /// @param providers Array of provider identifiers\n /// @param feeds Array of Chainlink aggregator addresses\n /// @dev Validates inputs via _validateOracleInputs() before calling.\n /// Automatically adds new providers to activeProviders array (up to MAX_SAMPLE_PROVIDERS).\n /// Reverts if adding a provider would exceed MAX_SAMPLE_PROVIDERS limit.\n function _configureOracles(\n address[] memory bases,\n address[] memory quotes,\n bytes32[] memory providers,\n address[] memory feeds\n )\n internal\n {\n uint256 length = bases.length;\n\n for (uint256 i; i < length; ++i) {\n address base = bases[i];\n address quote = quotes[i];\n bytes32 provider = providers[i];\n address feed = feeds[i];\n\n oracles[base][quote][provider] = feed;\n\n // Update activeProviders array - add provider if not already present\n bool providerExists = isProviderSet[provider];\n if (!providerExists) {\n if (activeProviders.length >= MAX_SAMPLE_PROVIDERS) {\n revert TOO_MANY_PROVIDERS();\n }\n activeProviders.push(provider);\n isProviderSet[provider] = true;\n }\n }\n }\n}\n"},"src/interfaces/oracles/ISuperOracleL2.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperOracleL2\n/// @author Superform Labs\n/// @notice Interface for Layer 2 Oracle for Superform\ninterface ISuperOracleL2 {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Error when no uptime feed is configured for the data oracle\n error NO_UPTIME_FEED();\n\n /// @notice Error when the L2 sequencer is down\n error SEQUENCER_DOWN();\n\n /// @notice Error when the grace period after sequencer restart is not over\n error GRACE_PERIOD_NOT_OVER();\n\n /// @notice Error when the grace period after sequencer restart is too low\n error GRACE_PERIOD_TOO_LOW();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an uptime feed is set for a data oracle\n /// @param dataOracle The data oracle address\n /// @param uptimeOracle The uptime feed address\n event UptimeFeedSet(address dataOracle, address uptimeOracle);\n\n /// @notice Emitted when a grace period is set for an uptime oracle\n /// @param uptimeOracle The uptime oracle address\n /// @param gracePeriod The grace period in seconds\n event GracePeriodSet(address uptimeOracle, uint256 gracePeriod);\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set uptime feeds for multiple data oracles in batch\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n}\n"},"lib/forge-std/src/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2;\n\n/// @dev Interface of the ERC20 standard as defined in the EIP.\n/// @dev This includes the optional name, symbol, and decimals metadata.\ninterface IERC20 {\n /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`\n /// is the new allowance.\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// @notice Returns the amount of tokens in existence.\n function totalSupply() external view returns (uint256);\n\n /// @notice Returns the amount of tokens owned by `account`.\n function balanceOf(address account) external view returns (uint256);\n\n /// @notice Moves `amount` tokens from the caller's account to `to`.\n function transfer(address to, uint256 amount) external returns (bool);\n\n /// @notice Returns the remaining number of tokens that `spender` is allowed\n /// to spend on behalf of `owner`\n function allowance(address owner, address spender) external view returns (uint256);\n\n /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.\n /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n function approve(address spender, uint256 amount) external returns (bool);\n\n /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.\n /// `amount` is then deducted from the caller's allowance.\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n\n /// @notice Returns the name of the token.\n function name() external view returns (string memory);\n\n /// @notice Returns the symbol of the token.\n function symbol() external view returns (string memory);\n\n /// @notice Returns the decimals places of the token.\n function decimals() external view returns (uint8);\n}\n"},"src/vendor/BoringSolidity/BoringERC20.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\n// With thanks to @BoringCrypto\npragma solidity >=0.8.19;\n\nimport { IERC20 } from \"forge-std/interfaces/IERC20.sol\";\n\n// solhint-disable avoid-low-level-calls\n\nlibrary BoringERC20 {\n bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()\n\n /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.\n /// @param token The address of the ERC-20 token contract.\n /// @return (uint8) Token decimals.\n function safeDecimals(IERC20 token) internal view returns (uint8) {\n (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));\n return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;\n }\n}\n"},"src/vendor/chainlink/AggregatorV3Interface.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function latestRoundData()\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"src/vendor/awesome-oracles/IOracle.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.20;\n\n/// @title Common interface for price oracles.\n/// @dev Implements the spec at https://eips.ethereum.org/EIPS/eip-7726\ninterface IOracle {\n /// @notice The oracle does not support the given base/quote pair.\n /// @param base The asset that the user needs to know the value or price for.\n /// @param quote The asset in which the user needs to value or price the base.\n error OracleUnsupportedPair(address base, address quote);\n\n /// @notice The oracle is not capable to provide data within a degree of confidence.\n /// @param base The asset that the user needs to know the value or price for.\n /// @param quote The asset in which the user needs to value or price the base.\n error OracleUntrustedData(address base, address quote);\n\n /// @notice Returns the value of `baseAmount` of `base` in `quote` terms.\n /// @dev MUST round down towards 0.\n /// MUST revert with `OracleUnsupportedPair` if not capable to provide data for the specified `base` and `quote`\n /// pair.\n /// MUST revert with `OracleUntrustedData` if not capable to provide data within a degree of confidence publicly\n /// specified.\n /// @param baseAmount The amount of `base` to convert.\n /// @param base The asset that the user needs to know the value for.\n /// @param quote The asset in which the user needs to value the base.\n /// @return quoteAmount The value of `baseAmount` of `base` in `quote` terms\n function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);\n}\n"},"src/interfaces/oracles/ISuperOracle.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperOracle\n/// @author Superform Labs\n/// @notice Interface for SuperOracle\ninterface ISuperOracle {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Error when address is zero\n error ZERO_ADDRESS();\n\n /// @notice Error when array length is zero\n error ZERO_ARRAY_LENGTH();\n\n /// @notice Error when oracle provider index is invalid\n error INVALID_ORACLE_PROVIDER();\n\n /// @notice Error when no oracles are configured for base asset\n error NO_ORACLES_CONFIGURED();\n\n /// @notice Error when no valid reported prices are found\n error NO_VALID_REPORTED_PRICES();\n\n /// @notice Error when arrays have mismatched lengths\n error ARRAY_LENGTH_MISMATCH();\n\n /// @notice Error when timelock period has not elapsed\n error TIMELOCK_NOT_ELAPSED();\n\n /// @notice Error when there is already a pending update\n error PENDING_UPDATE_EXISTS();\n\n /// @notice Error when oracle data is untrusted\n error ORACLE_UNTRUSTED_DATA();\n\n /// @notice Error when provider max staleness period is not set\n error NO_PENDING_UPDATE();\n\n /// @notice Error when provider max staleness period is exceeded\n error MAX_STALENESS_EXCEEDED();\n\n /// @notice Error when average provider is not allowed\n error AVERAGE_PROVIDER_NOT_ALLOWED();\n\n /// @notice Error when provider is zero\n error ZERO_PROVIDER();\n\n /// @notice Error when too many providers are being iterated through\n error TOO_MANY_PROVIDERS();\n\n /// @notice Error when caller is not authorized to update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n\n /// @notice Error when oracle decimals call fails\n error ORACLE_DECIMALS_CALL_FAIL(address oracle);\n\n /// @notice Error when oracle round data call fails\n error ORACLE_ROUND_DATA_CALL_FAIL(address oracle);\n\n /// @notice Error when external call gas is insufficient\n error INSUFFICIENT_GAS_FOR_EXTERNAL_CALL();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when oracles are configured\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n event OraclesConfigured(address[] bases, address[] quotes, bytes32[] providers, address[] feeds);\n\n /// @notice Emitted when oracle update is queued\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n /// @param timestamp Timestamp when update was queued\n event OracleUpdateQueued(\n address[] bases, address[] quotes, bytes32[] providers, address[] feeds, uint256 timestamp\n );\n\n /// @notice Emitted when oracle update is executed\n /// @param bases Array of base assets\n /// @param quotes Array of quote assets\n /// @param providers Array of provider indexes\n /// @param feeds Array of oracle addresses\n event OracleUpdateExecuted(address[] bases, address[] quotes, bytes32[] providers, address[] feeds);\n\n /// @notice Emitted when provider max staleness period is updated\n /// @param feed Feed address\n /// @param newMaxStaleness New maximum staleness period in seconds\n event FeedMaxStalenessUpdated(address feed, uint256 newMaxStaleness);\n\n /// @notice Emitted when max staleness period is updated\n /// @param newMaxStaleness New maximum staleness period in seconds\n event MaxStalenessUpdated(uint256 newMaxStaleness);\n\n /// @notice Emitted when provider removal is queued\n /// @param providers Array of provider ids to remove\n /// @param timestamp Timestamp when removal was queued\n event ProviderRemovalQueued(bytes32[] providers, uint256 timestamp);\n\n /// @notice Emitted when provider removal is executed\n /// @param providers Array of provider ids that were removed\n event ProviderRemovalExecuted(bytes32[] providers);\n\n /// @notice Emitted when provider removal is cancelled\n /// @param providers Array of provider ids that were queued for removal\n event ProviderRemovalCancelled(bytes32[] providers);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Struct for pending oracle update\n struct PendingUpdate {\n address[] bases;\n address[] quotes;\n bytes32[] providers;\n address[] feeds;\n uint256 timestamp;\n }\n\n /// @notice Struct for pending provider removal\n struct PendingRemoval {\n bytes32[] providers;\n uint256 timestamp;\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get oracle address for a base asset and provider\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param provider Provider id\n /// @return oracle Oracle address\n function getOracleAddress(address base, address quote, bytes32 provider) external view returns (address oracle);\n\n /// @notice Get quote from specified oracle provider\n /// @param baseAmount Amount of base asset\n /// @param base Base asset address\n /// @param quote Quote asset address\n /// @param oracleProvider Id of oracle provider to use\n /// @return quoteAmount The quote amount\n /// @return deviation Standard deviation of oracle quotes in quote asset units (0 for single provider)\n /// @return totalProviders Total number of providers that have a configured oracle for this pair\n /// @return availableProviders Number of providers that successfully returned a valid quote\n function getQuoteFromProvider(\n uint256 baseAmount,\n address base,\n address quote,\n bytes32 oracleProvider\n )\n external\n view\n returns (uint256 quoteAmount, uint256 deviation, uint256 totalProviders, uint256 availableProviders);\n\n /// @notice Queue oracle update for timelock\n /// @param bases Array of base assets\n /// @param providers Array of provider ids\n /// @param quotes Array of quote assets\n /// @param feeds Array of oracle addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Execute queued oracle update after timelock period\n function executeOracleUpdate() external;\n\n /// @notice Queue provider removal for timelock\n /// @param providers Array of provider ids to remove\n function queueProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Execute queued provider removal after timelock period\n function executeProviderRemoval() external;\n\n /// @notice Cancel queued provider removal\n function cancelProviderRemoval() external;\n\n /// @notice Set the maximum staleness period for a specific provider\n /// @param feed Feed address\n /// @param newMaxStaleness New maximum staleness period in seconds\n function setFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Set the maximum staleness period for all providers\n /// @param newMaxStaleness New maximum staleness period in seconds\n function setDefaultStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Set the maximum staleness period for multiple providers\n /// @param feeds Array of feed addresses\n /// @param newMaxStalenessList Array of new maximum staleness periods in seconds\n function setFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Get all active provider ids\n /// @return Array of active provider ids\n function getActiveProviders() external view returns (bytes32[] memory);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperVault.standard-json-input.json b/script/locked-bytecode-dev/SuperVault.standard-json-input.json new file mode 100644 index 000000000..195ae1209 --- /dev/null +++ b/script/locked-bytecode-dev/SuperVault.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperVault/SuperVault.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ECDSA } from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\n\n// OpenZeppelin Upgradeable\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC165 } from \"@openzeppelin/contracts/interfaces/IERC165.sol\";\nimport { EIP712Upgradeable } from \"@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/interfaces/IERC20Metadata.sol\";\n\n// Interfaces\nimport { ISuperVault } from \"../interfaces/SuperVault/ISuperVault.sol\";\nimport { ISuperVaultStrategy } from \"../interfaces/SuperVault/ISuperVaultStrategy.sol\";\nimport { ISuperGovernor } from \"../interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"../interfaces/SuperVault/ISuperVaultAggregator.sol\";\nimport { IERC7540Operator, IERC7540Redeem, IERC7540CancelRedeem } from \"../vendor/standards/ERC7540/IERC7540Vault.sol\";\nimport { IERC7741 } from \"../vendor/standards/ERC7741/IERC7741.sol\";\nimport { IERC7575 } from \"../vendor/standards/ERC7575/IERC7575.sol\";\nimport { ISuperVaultEscrow } from \"../interfaces/SuperVault/ISuperVaultEscrow.sol\";\n\n// Libraries\nimport { AssetMetadataLib } from \"../libraries/AssetMetadataLib.sol\";\n\n/// @title SuperVault\n/// @author Superform Labs\n/// @notice SuperVault vault contract implementing ERC4626 with synchronous deposits and asynchronous redeems via\n/// ERC7540\ncontract SuperVault is Initializable, ERC20Upgradeable, ISuperVault, ReentrancyGuardUpgradeable, EIP712Upgradeable {\n using AssetMetadataLib for address;\n using SafeERC20 for IERC20;\n using Math for uint256;\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n uint256 private constant REQUEST_ID = 0;\n uint256 private constant BPS_PRECISION = 10_000;\n\n // EIP712 TypeHash\n /// @notice EIP-712 typehash for operator authorization signatures\n /// @dev Used to construct the digest for EIP-712 signature validation in authorizeOperator()\n /// Format: \"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256\n // deadline)\" / - controller: The address authorizing the operator\n /// - operator: The address being authorized/deauthorized\n /// - approved: True to authorize, false to revoke\n /// - nonce: Unique nonce for replay protection (one-time use)\n /// - deadline: Timestamp after which signature expires\n /// @dev This typehash MUST remain constant. Any changes invalidate all existing signatures.\n /// @dev Off-chain signers must use this exact structure when creating signatures for authorizeOperator()\n bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH = keccak256(\n \"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\"\n );\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n address public share;\n IERC20 private _asset;\n uint8 private _underlyingDecimals;\n ISuperVaultStrategy public strategy;\n address public escrow;\n uint256 public PRECISION;\n\n // Core contracts\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n /// @inheritdoc IERC7540Operator\n mapping(address owner => mapping(address operator => bool)) public isOperator;\n\n // Authorization tracking\n mapping(address controller => mapping(bytes32 nonce => bool used)) private _authorizations;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address superGovernor_) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n emit SuperGovernorSet(superGovernor_);\n\n _disableInitializers();\n }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initialize the vault with required parameters\n /// @dev This function can only be called once due to initializer modifier\n /// @dev SECURITY: asset, strategy, and escrow are pre-validated in SuperVaultAggregator.createVault()\n /// to prevent initialization with invalid addresses. No additional validation needed here.\n /// @dev PRECISION is set to 10^decimals for consistent share/asset conversions\n /// @dev EIP-712 domain separator is initialized with vault name and version \"1\" for signature validation\n /// @param asset_ The underlying asset token address (pre-validated by aggregator)\n /// @param name_ The name of the vault token (used for ERC20 and EIP-712 domain)\n /// @param symbol_ The symbol of the vault token\n /// @param strategy_ The strategy contract address (pre-validated by aggregator)\n /// @param escrow_ The escrow contract address (pre-validated by aggregator)\n function initialize(\n address asset_,\n string memory name_,\n string memory symbol_,\n address strategy_,\n address escrow_\n )\n external\n initializer\n {\n /// @dev asset, strategy, and escrow already validated in SuperVaultAggregator during vault creation\n // Initialize parent contracts\n __ERC20_init(name_, symbol_);\n __ReentrancyGuard_init();\n __EIP712_init(name_, \"1\");\n\n // Set asset and precision\n _asset = IERC20(asset_);\n (bool success, uint8 assetDecimals) = asset_.tryGetAssetDecimals();\n if (!success) revert INVALID_ASSET();\n _underlyingDecimals = assetDecimals;\n PRECISION = 10 ** _underlyingDecimals;\n share = address(this);\n strategy = ISuperVaultStrategy(strategy_);\n escrow = escrow_;\n\n emit Initialized(asset_, strategy_, escrow_);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 OVERRIDES\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc IERC4626\n function deposit(uint256 assets, address receiver) public override nonReentrant returns (uint256 shares) {\n if (receiver == address(0)) revert ZERO_ADDRESS();\n if (assets == 0) revert ZERO_AMOUNT();\n\n // Forward assets from msg.sender to strategy\n _asset.safeTransferFrom(msg.sender, address(strategy), assets);\n\n // Single executor call: strategy skims entry fee, accounts on NET, returns net shares\n // Note: handleOperations4626Deposit already validates and reverts if shares == 0\n shares = strategy.handleOperations4626Deposit(receiver, assets);\n\n // Mint the net shares\n _mint(receiver, shares);\n\n emit Deposit(msg.sender, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC4626\n function mint(uint256 shares, address receiver) public override nonReentrant returns (uint256 assets) {\n if (receiver == address(0)) revert ZERO_ADDRESS();\n if (shares == 0) revert ZERO_AMOUNT();\n\n uint256 assetsNet;\n (assets, assetsNet) = strategy.quoteMintAssetsGross(shares);\n\n // Forward quoted gross assets from msg.sender to strategy\n _asset.safeTransferFrom(msg.sender, address(strategy), assets);\n\n // Single executor call: strategy handles fees and accounts on NET\n strategy.handleOperations4626Mint(receiver, shares, assets, assetsNet);\n\n // Mint the exact shares asked\n _mint(receiver, shares);\n\n emit Deposit(msg.sender, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7540Redeem\n /// @notice Once owner has authorized an operator, controller must be the owner\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256) {\n if (shares == 0) revert ZERO_AMOUNT();\n if (owner == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateController(owner);\n\n if (balanceOf(owner) < shares) revert INVALID_AMOUNT();\n if (strategy.pendingCancelRedeemRequest(owner)) revert CANCELLATION_REDEEM_REQUEST_PENDING();\n\n // Enforce auditor's invariant for current accounting model\n if (controller != owner) revert CONTROLLER_MUST_EQUAL_OWNER();\n\n // Transfer shares to escrow for temporary locking\n _approve(owner, escrow, shares);\n ISuperVaultEscrow(escrow).escrowShares(owner, shares);\n\n // Forward to strategy (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.RedeemRequest, controller, address(0), shares);\n\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function cancelRedeemRequest(\n uint256,\n /*requestId*/\n address controller\n )\n external\n {\n _validateController(controller);\n\n // Forward to strategy (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.CancelRedeemRequest, controller, address(0), 0);\n\n emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function claimCancelRedeemRequest(\n uint256, /*requestId*/\n address receiver,\n address controller\n )\n external\n returns (uint256 shares)\n {\n if (receiver == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateControllerAndReceiver(controller, receiver);\n\n shares = strategy.claimableCancelRedeemRequest(controller);\n\n // Forward to strategy (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.ClaimCancelRedeem, controller, address(0), 0);\n\n // Return shares to controller\n ISuperVaultEscrow(escrow).returnShares(receiver, shares);\n\n emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n }\n\n /// @inheritdoc IERC7540Operator\n function setOperator(address operator, bool approved) external returns (bool success) {\n if (msg.sender == operator) revert UNAUTHORIZED();\n isOperator[msg.sender][operator] = approved;\n emit OperatorSet(msg.sender, operator, approved);\n return true;\n }\n\n /// @inheritdoc IERC7741\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n )\n external\n returns (bool)\n {\n if (controller == operator) revert UNAUTHORIZED();\n if (block.timestamp > deadline) revert DEADLINE_PASSED();\n if (_authorizations[controller][nonce]) revert UNAUTHORIZED();\n\n _authorizations[controller][nonce] = true;\n\n bytes32 structHash =\n keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline));\n bytes32 digest = _hashTypedDataV4(structHash);\n\n if (!_isValidSignature(controller, digest, signature)) revert INVALID_SIGNATURE();\n\n isOperator[controller][operator] = approved;\n emit OperatorSet(controller, operator, approved);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n USER EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVault\n function getEscrowedAssets() external view returns (uint256) {\n return _asset.balanceOf(escrow);\n }\n\n //--ERC7540--\n /// @inheritdoc IERC7540Redeem\n function pendingRedeemRequest(\n uint256, /*requestId*/\n address controller\n )\n external\n view\n returns (uint256 pendingShares)\n {\n return strategy.pendingRedeemRequest(controller);\n }\n\n /// @inheritdoc IERC7540Redeem\n function claimableRedeemRequest(\n uint256, /*requestId*/\n address controller\n )\n external\n view\n returns (uint256 claimableShares)\n {\n return maxRedeem(controller);\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function pendingCancelRedeemRequest(\n uint256,\n /*requestId*/\n address controller\n )\n external\n view\n returns (bool isPending)\n {\n isPending = strategy.pendingCancelRedeemRequest(controller);\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function claimableCancelRedeemRequest(\n uint256, /*requestId*/\n address controller\n )\n external\n view\n returns (uint256 claimableShares)\n {\n return strategy.claimableCancelRedeemRequest(controller);\n }\n\n //--Operator Management--\n\n /// @inheritdoc IERC7741\n function authorizations(address controller, bytes32 nonce) external view returns (bool used) {\n return _authorizations[controller][nonce];\n }\n\n /// @inheritdoc IERC7741\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /// @inheritdoc IERC7741\n function invalidateNonce(bytes32 nonce) external {\n if (_authorizations[msg.sender][nonce]) revert INVALID_NONCE();\n _authorizations[msg.sender][nonce] = true;\n\n emit NonceInvalidated(msg.sender, nonce);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC4626 IMPLEMENTATION\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc IERC20Metadata\n function decimals() public view virtual override(ERC20Upgradeable, IERC20Metadata) returns (uint8) {\n return _underlyingDecimals;\n }\n\n /// @inheritdoc IERC4626\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /// @inheritdoc IERC4626\n function totalAssets() external view override returns (uint256) {\n uint256 supply = totalSupply();\n if (supply == 0) return 0;\n uint256 currentPPS = _getStoredPPS();\n return Math.mulDiv(supply, currentPPS, PRECISION, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function convertToShares(uint256 assets) public view override returns (uint256) {\n uint256 pps = _getStoredPPS();\n return pps == 0 ? 0 : Math.mulDiv(assets, PRECISION, pps, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function convertToAssets(uint256 shares) public view override returns (uint256) {\n uint256 currentPPS = _getStoredPPS();\n return currentPPS == 0 ? 0 : Math.mulDiv(shares, currentPPS, PRECISION, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function maxDeposit(address) public view override returns (uint256) {\n if (!_canAcceptDeposits()) return 0;\n return type(uint256).max;\n }\n\n /// @inheritdoc IERC4626\n function maxMint(address) external view override returns (uint256) {\n if (!_canAcceptDeposits()) return 0;\n return type(uint256).max;\n }\n\n /// @inheritdoc IERC4626\n function maxWithdraw(address owner) public view override returns (uint256) {\n return strategy.claimableWithdraw(owner);\n }\n\n /// @inheritdoc IERC4626\n function maxRedeem(address owner) public view override returns (uint256) {\n uint256 withdrawPrice = strategy.getAverageWithdrawPrice(owner);\n if (withdrawPrice == 0) return 0;\n return maxWithdraw(owner).mulDiv(PRECISION, withdrawPrice, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function previewDeposit(uint256 assets) public view override returns (uint256) {\n uint256 pps = _getStoredPPS();\n if (pps == 0) return 0;\n\n (uint256 feeBps,) = _getManagementFeeConfig();\n\n if (feeBps == 0) return Math.mulDiv(assets, PRECISION, pps, Math.Rounding.Floor);\n // fee-on-gross: fee = ceil(gross * feeBps / BPS)\n uint256 fee = Math.mulDiv(assets, feeBps, BPS_PRECISION, Math.Rounding.Ceil);\n\n uint256 assetsNet = assets - fee;\n return Math.mulDiv(assetsNet, PRECISION, pps, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n /// @dev Returns gross assets required to mint exact shares after management fees\n /// @dev Formula: gross = net * BPS_PRECISION / (BPS_PRECISION - feeBps)\n /// @dev Edge case: If feeBps >= 100% (10000), returns 0 (impossible to mint with 100%+ fees)\n /// This prevents division by zero and represents mathematical impossibility.\n function previewMint(uint256 shares) public view override returns (uint256) {\n uint256 pps = _getStoredPPS();\n if (pps == 0) return 0;\n\n uint256 assetsGross = Math.mulDiv(shares, pps, PRECISION, Math.Rounding.Ceil);\n\n (uint256 feeBps,) = _getManagementFeeConfig();\n if (feeBps == 0) return assetsGross;\n if (feeBps >= BPS_PRECISION) return 0; // impossible to mint (would require infinite gross)\n\n return Math.mulDiv(assetsGross, BPS_PRECISION, (BPS_PRECISION - feeBps), Math.Rounding.Ceil);\n }\n\n /// @inheritdoc IERC4626\n function previewWithdraw(\n uint256 /* assets*/\n )\n public\n pure\n override\n returns (uint256)\n {\n revert NOT_IMPLEMENTED();\n }\n\n /// @inheritdoc IERC4626\n function previewRedeem(\n uint256 /* shares*/\n )\n public\n pure\n override\n returns (uint256)\n {\n revert NOT_IMPLEMENTED();\n }\n\n /// @inheritdoc IERC4626\n function withdraw(\n uint256 assets,\n address receiver,\n address controller\n )\n public\n override\n nonReentrant\n returns (uint256 shares)\n {\n if (receiver == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateControllerAndReceiver(controller, receiver);\n\n uint256 averageWithdrawPrice = strategy.getAverageWithdrawPrice(controller);\n if (averageWithdrawPrice == 0) revert INVALID_WITHDRAW_PRICE();\n\n uint256 maxWithdrawAmount = maxWithdraw(controller);\n if (assets > maxWithdrawAmount) revert INVALID_AMOUNT();\n\n // Calculate shares based on assets and average withdraw price\n shares = assets.mulDiv(PRECISION, averageWithdrawPrice, Math.Rounding.Ceil);\n\n uint256 escrowBalance = _asset.balanceOf(escrow);\n if (assets > escrowBalance) revert NOT_ENOUGH_ASSETS();\n\n // Update strategy state (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.ClaimRedeem, controller, receiver, assets);\n\n // Transfer assets from escrow to receiver\n ISuperVaultEscrow(escrow).returnAssets(receiver, assets);\n\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc IERC4626\n function redeem(\n uint256 shares,\n address receiver,\n address controller\n )\n public\n override\n nonReentrant\n returns (uint256 assets)\n {\n if (receiver == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateControllerAndReceiver(controller, receiver);\n\n uint256 averageWithdrawPrice = strategy.getAverageWithdrawPrice(controller);\n if (averageWithdrawPrice == 0) revert INVALID_WITHDRAW_PRICE();\n\n // Calculate assets based on shares and average withdraw price\n assets = shares.mulDiv(averageWithdrawPrice, PRECISION, Math.Rounding.Floor);\n\n uint256 maxWithdrawAmount = maxWithdraw(controller);\n if (assets > maxWithdrawAmount) revert INVALID_AMOUNT();\n\n uint256 escrowBalance = _asset.balanceOf(escrow);\n if (assets > escrowBalance) revert NOT_ENOUGH_ASSETS();\n\n // Update strategy state (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.ClaimRedeem, controller, receiver, assets);\n\n // Transfer assets from escrow to receiver\n ISuperVaultEscrow(escrow).returnAssets(receiver, assets);\n\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc ISuperVault\n function burnShares(uint256 amount) external {\n if (msg.sender != address(strategy)) revert UNAUTHORIZED();\n _burn(escrow, amount);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 INTERFACE\n //////////////////////////////////////////////////////////////*/\n /// @notice Checks if contract supports a given interface\n /// @dev Implements ERC165 for ERC7540, ERC7741, ERC4626, ERC7575 support detection\n /// @param interfaceId The interface identifier to check\n /// @return True if the interface is supported, false otherwise\n function supportsInterface(bytes4 interfaceId) public pure returns (bool) {\n return interfaceId == type(IERC7540Redeem).interfaceId || interfaceId == type(IERC165).interfaceId\n || interfaceId == type(IERC7741).interfaceId || interfaceId == type(IERC4626).interfaceId\n || interfaceId == type(IERC7575).interfaceId || interfaceId == type(IERC7540Operator).interfaceId;\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Validates that the caller is authorized to act on behalf of the controller\n /// @dev Enforces ERC7540Operator pattern: either direct call from controller or authorized operator\n /// @dev Operators must be authorized via setOperator() or authorizeOperator() (EIP-712 signature)\n /// @dev Used in redemption flows to prevent unauthorized claims\n /// @param controller The controller address to validate authorization for\n /// @dev Reverts with INVALID_CONTROLLER if:\n /// - caller is not the controller AND\n /// - caller is not an authorized operator for the controller\n function _validateController(address controller) internal view {\n if (controller != msg.sender && !_isOperator(controller, msg.sender)) revert INVALID_CONTROLLER();\n }\n\n /// @notice Validates controller authorization and enforces operator receiver restrictions\n /// @dev Controllers can set any receiver; operators must set receiver == controller\n /// @param controller The controller address to validate authorization for\n /// @param receiver The receiver address to validate against operator restrictions\n function _validateControllerAndReceiver(address controller, address receiver) internal view {\n // If caller is controller, all good\n if (controller == msg.sender) return;\n\n // Caller is not controller, must be operator\n if (!_isOperator(controller, msg.sender)) revert INVALID_CONTROLLER();\n\n // Caller is operator, enforce receiver == controller\n if (receiver != controller) revert RECEIVER_MUST_EQUAL_CONTROLLER();\n }\n\n function _isOperator(address controller, address operator) internal view returns (bool) {\n return isOperator[controller][operator];\n }\n\n /// @notice Verify an EIP712 signature using OpenZeppelin's ECDSA library\n /// @param signer The signer to verify\n /// @param digest The digest to verify\n /// @param signature The signature to verify\n function _isValidSignature(address signer, bytes32 digest, bytes memory signature) internal pure returns (bool) {\n address recoveredSigner = ECDSA.recover(digest, signature);\n return recoveredSigner == signer;\n }\n\n function _getStoredPPS() internal view returns (uint256) {\n return strategy.getStoredPPS();\n }\n\n /// @notice Combined check for deposits acceptance\n /// @dev Reduces external calls by fetching aggregator address once\n /// @dev Previously: 4 external calls (2x getAddress + 2x aggregator checks)\n /// @dev Now: 3 external calls (1x getAddress + 2x aggregator checks)\n /// @return True if deposits can be accepted (not paused and PPS not stale)\n function _canAcceptDeposits() internal view returns (bool) {\n address aggregatorAddress = _getAggregatorAddress();\n ISuperVaultAggregator aggregator = ISuperVaultAggregator(aggregatorAddress);\n return !aggregator.isStrategyPaused(address(strategy)) && !aggregator.isPPSStale(address(strategy));\n }\n\n /// @notice Helper to get aggregator address once\n /// @return Address of the SuperVaultAggregator contract\n function _getAggregatorAddress() internal view returns (address) {\n return SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.SUPER_VAULT_AGGREGATOR());\n }\n\n /// @dev Read management fee config (view-only for previews)\n function _getManagementFeeConfig() internal view returns (uint256 feeBps, address recipient) {\n ISuperVaultStrategy.FeeConfig memory cfg = strategy.getConfigInfo();\n return (cfg.managementFeeBps, cfg.recipient);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS\n }\n\n /**\n * @dev The signature derives the `address(0)`.\n */\n error ECDSAInvalidSignature();\n\n /**\n * @dev The signature has an invalid length.\n */\n error ECDSAInvalidSignatureLength(uint256 length);\n\n /**\n * @dev The signature has an S value that is in the upper half order.\n */\n error ECDSAInvalidSignatureS(bytes32 s);\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n * and a bytes32 providing additional information about the error.\n *\n * If no error is returned, then the address can be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n */\n function tryRecover(\n bytes32 hash,\n bytes memory signature\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly (\"memory-safe\") {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n unchecked {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n // We do not check for an overflow here since the shift operation results in 0 or 1.\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n */\n function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS, s);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature, bytes32(0));\n }\n\n return (signer, RecoverError.NoError, bytes32(0));\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n */\n function _throwError(RecoverError error, bytes32 errorArg) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert ECDSAInvalidSignature();\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert ECDSAInvalidSignatureLength(uint256(errorArg));\n } else if (error == RecoverError.InvalidSignatureS) {\n revert ECDSAInvalidSignatureS(errorArg);\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reinitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n *\n * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n */\n function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n return INITIALIZABLE_STORAGE;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n bytes32 slot = _initializableStorageSlot();\n assembly {\n $.slot := slot\n }\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant NOT_ENTERED = 1;\n uint256 private constant ENTERED = 2;\n\n /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n struct ReentrancyGuardStorage {\n uint256 _status;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n assembly {\n $.slot := ReentrancyGuardStorageLocation\n }\n }\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if ($._status == ENTERED) {\n revert ReentrancyGuardReentrantCall();\n }\n\n // Any calls to nonReentrant after this point will fail\n $._status = ENTERED;\n }\n\n function _nonReentrantAfter() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n return $._status == ENTERED;\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {IERC20Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC-20\n * applications.\n */\nabstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {\n /// @custom:storage-location erc7201:openzeppelin.storage.ERC20\n struct ERC20Storage {\n mapping(address account => uint256) _balances;\n\n mapping(address account => mapping(address spender => uint256)) _allowances;\n\n uint256 _totalSupply;\n\n string _name;\n string _symbol;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC20\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;\n\n function _getERC20Storage() private pure returns (ERC20Storage storage $) {\n assembly {\n $.slot := ERC20StorageLocation\n }\n }\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * Both values are immutable: they can only be set once during construction.\n */\n function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __ERC20_init_unchained(name_, symbol_);\n }\n\n function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n ERC20Storage storage $ = _getERC20Storage();\n $._name = name_;\n $._symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual returns (string memory) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual returns (string memory) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual returns (uint8) {\n return 18;\n }\n\n /// @inheritdoc IERC20\n function totalSupply() public view virtual returns (uint256) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._totalSupply;\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address account) public view virtual returns (uint256) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `value`.\n */\n function transfer(address to, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, value);\n return true;\n }\n\n /// @inheritdoc IERC20\n function allowance(address owner, address spender) public view virtual returns (uint256) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Skips emitting an {Approval} event indicating an allowance update. This is not\n * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `value`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `value`.\n */\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, value);\n _transfer(from, to, value);\n return true;\n }\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _transfer(address from, address to, uint256 value) internal {\n if (from == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n if (to == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(from, to, value);\n }\n\n /**\n * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n * this function.\n *\n * Emits a {Transfer} event.\n */\n function _update(address from, address to, uint256 value) internal virtual {\n ERC20Storage storage $ = _getERC20Storage();\n if (from == address(0)) {\n // Overflow check required: The rest of the code assumes that totalSupply never overflows\n $._totalSupply += value;\n } else {\n uint256 fromBalance = $._balances[from];\n if (fromBalance < value) {\n revert ERC20InsufficientBalance(from, fromBalance, value);\n }\n unchecked {\n // Overflow not possible: value <= fromBalance <= totalSupply.\n $._balances[from] = fromBalance - value;\n }\n }\n\n if (to == address(0)) {\n unchecked {\n // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n $._totalSupply -= value;\n }\n } else {\n unchecked {\n // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n $._balances[to] += value;\n }\n }\n\n emit Transfer(from, to, value);\n }\n\n /**\n * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n * Relies on the `_update` mechanism\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _mint(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(address(0), account, value);\n }\n\n /**\n * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n * Relies on the `_update` mechanism.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead\n */\n function _burn(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n _update(account, address(0), value);\n }\n\n /**\n * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n *\n * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n */\n function _approve(address owner, address spender, uint256 value) internal {\n _approve(owner, spender, value, true);\n }\n\n /**\n * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n *\n * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n * `Approval` event during `transferFrom` operations.\n *\n * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n * true using the following override:\n *\n * ```solidity\n * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n * super._approve(owner, spender, value, true);\n * }\n * ```\n *\n * Requirements are the same as {_approve}.\n */\n function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n ERC20Storage storage $ = _getERC20Storage();\n if (owner == address(0)) {\n revert ERC20InvalidApprover(address(0));\n }\n if (spender == address(0)) {\n revert ERC20InvalidSpender(address(0));\n }\n $._allowances[owner][spender] = value;\n if (emitEvent) {\n emit Approval(owner, spender, value);\n }\n }\n\n /**\n * @dev Updates `owner`'s allowance for `spender` based on spent `value`.\n *\n * Does not update the allowance value in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Does not emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance < type(uint256).max) {\n if (currentAllowance < value) {\n revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n }\n unchecked {\n _approve(owner, spender, currentAllowance - value, false);\n }\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.20;\n\nimport {MessageHashUtils} from \"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol\";\nimport {IERC5267} from \"@openzeppelin/contracts/interfaces/IERC5267.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: The upgradeable version of this contract does not use an immutable cache and recomputes the domain separator\n * each time {_domainSeparatorV4} is called. That is cheaper than accessing a cached version in cold storage.\n */\nabstract contract EIP712Upgradeable is Initializable, IERC5267 {\n bytes32 private constant TYPE_HASH =\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n /// @custom:storage-location erc7201:openzeppelin.storage.EIP712\n struct EIP712Storage {\n /// @custom:oz-renamed-from _HASHED_NAME\n bytes32 _hashedName;\n /// @custom:oz-renamed-from _HASHED_VERSION\n bytes32 _hashedVersion;\n\n string _name;\n string _version;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.EIP712\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;\n\n function _getEIP712Storage() private pure returns (EIP712Storage storage $) {\n assembly {\n $.slot := EIP712StorageLocation\n }\n }\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n EIP712Storage storage $ = _getEIP712Storage();\n $._name = name;\n $._version = version;\n\n // Reset prior values in storage if upgrading\n $._hashedName = 0;\n $._hashedVersion = 0;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n return _buildDomainSeparator();\n }\n\n function _buildDomainSeparator() private view returns (bytes32) {\n return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\n /// @inheritdoc IERC5267\n function eip712Domain()\n public\n view\n virtual\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n )\n {\n EIP712Storage storage $ = _getEIP712Storage();\n // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized\n // and the EIP712 domain is not reliable, as it will be missing name and version.\n require($._hashedName == 0 && $._hashedVersion == 0, \"EIP712: Uninitialized\");\n\n return (\n hex\"0f\", // 01111\n _EIP712Name(),\n _EIP712Version(),\n block.chainid,\n address(this),\n bytes32(0),\n new uint256[](0)\n );\n }\n\n /**\n * @dev The name parameter for the EIP712 domain.\n *\n * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n * are a concern.\n */\n function _EIP712Name() internal view virtual returns (string memory) {\n EIP712Storage storage $ = _getEIP712Storage();\n return $._name;\n }\n\n /**\n * @dev The version parameter for the EIP712 domain.\n *\n * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n * are a concern.\n */\n function _EIP712Version() internal view virtual returns (string memory) {\n EIP712Storage storage $ = _getEIP712Storage();\n return $._version;\n }\n\n /**\n * @dev The hash of the name parameter for the EIP712 domain.\n *\n * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.\n */\n function _EIP712NameHash() internal view returns (bytes32) {\n EIP712Storage storage $ = _getEIP712Storage();\n string memory name = _EIP712Name();\n if (bytes(name).length > 0) {\n return keccak256(bytes(name));\n } else {\n // If the name is empty, the contract may have been upgraded without initializing the new storage.\n // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.\n bytes32 hashedName = $._hashedName;\n if (hashedName != 0) {\n return hashedName;\n } else {\n return keccak256(\"\");\n }\n }\n }\n\n /**\n * @dev The hash of the version parameter for the EIP712 domain.\n *\n * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.\n */\n function _EIP712VersionHash() internal view returns (bytes32) {\n EIP712Storage storage $ = _getEIP712Storage();\n string memory version = _EIP712Version();\n if (bytes(version).length > 0) {\n return keccak256(bytes(version));\n } else {\n // If the version is empty, the contract may have been upgraded without initializing the new storage.\n // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.\n bytes32 hashedVersion = $._hashedVersion;\n if (hashedVersion != 0) {\n return hashedVersion;\n } else {\n return keccak256(\"\");\n }\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n"},"src/interfaces/SuperVault/ISuperVault.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { IERC7540Redeem, IERC7540CancelRedeem } from \"../../vendor/standards/ERC7540/IERC7540Vault.sol\";\nimport { IERC7741 } from \"../../vendor/standards/ERC7741/IERC7741.sol\";\n\n/// @title ISuperVault\n/// @notice Interface for SuperVault core contract that manages share minting\n/// @author Superform Labs\ninterface ISuperVault is IERC4626, IERC7540Redeem, IERC7741, IERC7540CancelRedeem {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INVALID_ASSET();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n error INVALID_AMOUNT();\n error UNAUTHORIZED();\n error DEADLINE_PASSED();\n error INVALID_SIGNATURE();\n error NOT_IMPLEMENTED();\n error INVALID_NONCE();\n error INVALID_WITHDRAW_PRICE();\n error INVALID_CONTROLLER();\n error CONTROLLER_MUST_EQUAL_OWNER();\n error RECEIVER_MUST_EQUAL_CONTROLLER();\n error NOT_ENOUGH_ASSETS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event NonceInvalidated(address indexed sender, bytes32 indexed nonce);\n\n event SuperGovernorSet(address indexed superGovernor);\n\n event Initialized(address indexed asset, address indexed strategy, address indexed escrow);\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Burn shares, only callable by strategy\n /// @param amount The amount of shares to burn\n function burnShares(uint256 amount) external;\n\n /// @notice Get the amount of assets escrowed\n function getEscrowedAssets() external view returns (uint256);\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get the escrow address\n function escrow() external view returns (address);\n}\n"},"src/interfaces/SuperVault/ISuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { ISuperHook, Execution } from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n/// @title ISuperVaultStrategy\n/// @author Superform Labs\n/// @notice Interface for SuperVault strategy implementation that manages yield sources and executes strategies\ninterface ISuperVaultStrategy {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n error ZERO_LENGTH();\n error INVALID_HOOK();\n error ZERO_ADDRESS();\n error ACCESS_DENIED();\n error INVALID_AMOUNT();\n error OPERATION_FAILED();\n error INVALID_TIMESTAMP();\n error REQUEST_NOT_FOUND();\n error INVALID_ARRAY_LENGTH();\n error ACTION_TYPE_DISALLOWED();\n error YIELD_SOURCE_NOT_FOUND();\n error YIELD_SOURCE_ALREADY_EXISTS();\n error INVALID_PERFORMANCE_FEE_BPS();\n error MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n error MANAGER_NOT_AUTHORIZED();\n error INVALID_PPS();\n error INVALID_VAULT();\n error INVALID_ASSET();\n error OPERATIONS_BLOCKED_BY_VETO();\n error HOOK_VALIDATION_FAILED();\n error STRATEGY_PAUSED();\n error NO_PROPOSAL();\n error INVALID_REDEEM_SLIPPAGE_BPS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n error STALE_PPS();\n error PPS_EXPIRED();\n error INVALID_PPS_EXPIRY_THRESHOLD();\n error BOUNDS_EXCEEDED(uint256 minAllowed, uint256 maxAllowed, uint256 actual);\n error INSUFFICIENT_LIQUIDITY();\n error CONTROLLERS_NOT_SORTED_UNIQUE();\n error ZERO_SHARE_FULFILLMENT_DISALLOWED();\n error NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n error SKIM_TIMELOCK_ACTIVE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event SuperGovernorSet(address indexed superGovernor);\n event Initialized(address indexed vault);\n event YieldSourceAdded(address indexed source, address indexed oracle);\n event YieldSourceOracleUpdated(address indexed source, address indexed oldOracle, address indexed newOracle);\n event YieldSourceRemoved(address indexed source);\n\n event VaultFeeConfigUpdated(uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient);\n event VaultFeeConfigProposed(\n uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient, uint256 effectiveTime\n );\n event HooksExecuted(address[] hooks);\n event RedeemRequestPlaced(address indexed controller, address indexed owner, uint256 shares);\n event RedeemRequestClaimed(address indexed controller, address indexed receiver, uint256 assets, uint256 shares);\n event RedeemRequestsFulfilled(address[] controllers, uint256 processedShares, uint256 currentPPS);\n event RedeemRequestCanceled(address indexed controller, uint256 shares);\n event RedeemCancelRequestPlaced(address indexed controller);\n event RedeemCancelRequestFulfilled(address indexed controller, uint256 shares);\n event HookExecuted(\n address indexed hook,\n address indexed prevHook,\n address indexed targetedYieldSource,\n bool usePrevHookAmount,\n bytes hookCalldata\n );\n\n event PPSUpdated(uint256 newPPS, uint256 calculationBlock);\n event FeeRecipientChanged(address indexed newRecipient);\n event ManagementFeePaid(address indexed controller, address indexed recipient, uint256 feeAssets, uint256 feeBps);\n event DepositHandled(address indexed controller, uint256 assets, uint256 shares);\n event RedeemClaimable(\n address indexed controller, uint256 assetsFulfilled, uint256 sharesFulfilled, uint256 averageWithdrawPrice\n );\n event RedeemSlippageSet(address indexed controller, uint16 slippageBps);\n\n event PPSExpirationProposed(uint256 currentProposedThreshold, uint256 ppsExpiration, uint256 effectiveTime);\n event PPSExpiryThresholdUpdated(uint256 ppsExpiration);\n event PPSExpiryThresholdProposalCanceled();\n\n /// @notice Emitted when the high-water mark PPS is updated after fee collection\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n /// @param previousPps The PPS before fee collection\n /// @param profit The total profit above HWM (in assets)\n /// @param feeCollected The total fee collected (in assets)\n event HWMPPSUpdated(uint256 newHwmPps, uint256 previousPps, uint256 profit, uint256 feeCollected);\n\n /// @notice Emitted when the high-water mark PPS is reset\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n event HighWaterMarkReset(uint256 newHwmPps);\n\n /// @notice Emitted when performance fees are skimmed\n /// @param totalFee The total fee collected (in assets)\n /// @param superformFee The fee collected for Superform (in assets)\n event PerformanceFeeSkimmed(uint256 totalFee, uint256 superformFee);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n struct FeeConfig {\n uint256 performanceFeeBps; // On profit at fulfill time\n uint256 managementFeeBps; // Entry fee on deposit/mint (asset-side)\n address recipient; // Fee sink (entry + performance)\n }\n\n /// @notice Structure for hook execution arguments\n struct ExecuteArgs {\n /// @notice Array of hooks to execute\n address[] hooks;\n /// @notice Calldata for each hook (must match hooks array length)\n bytes[] hookCalldata;\n /// @notice Expected output amounts or output shares\n uint256[] expectedAssetsOrSharesOut;\n /// @notice Global Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] globalProofs;\n /// @notice Strategy-specific Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] strategyProofs;\n }\n\n struct YieldSource {\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice Comprehensive information about a yield source including its address and configuration\n struct YieldSourceInfo {\n address sourceAddress; // Address of the yield source\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice State specific to asynchronous redeem requests\n struct SuperVaultState {\n // Cancellation\n bool pendingCancelRedeemRequest;\n uint256 claimableCancelRedeemRequest;\n // Redeems\n uint256 pendingRedeemRequest; // Shares requested\n uint256 maxWithdraw; // Assets claimable after fulfillment\n uint256 averageRequestPPS; // Average PPS at the time of redeem request\n uint256 averageWithdrawPrice; // Average price for claimable assets\n uint16 redeemSlippageBps; // User-defined slippage tolerance in BPS for redeem fulfillment\n }\n\n struct ExecutionVars {\n bool success;\n address targetedYieldSource;\n uint256 outAmount;\n ISuperHook hookContract;\n Execution[] executions;\n }\n\n struct FulfillRedeemVars {\n uint256 totalRequestedShares;\n uint256 totalNetAssetsOut;\n uint256 currentPPS;\n uint256 strategyBalance;\n }\n\n /*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n enum Operation {\n RedeemRequest,\n CancelRedeemRequest,\n ClaimCancelRedeem,\n ClaimRedeem\n }\n\n /// @notice Action types for yield source management\n enum YieldSourceAction {\n Add, // 0: Add a new yield source\n UpdateOracle, // 1: Update an existing yield source's oracle\n Remove // 2: Remove a yield source\n }\n\n /// @notice Action types for PPS expiration threshold management\n enum PPSExpirationAction {\n Propose, // 0: Propose a new PPS expiration threshold\n Execute, // 1: Execute the proposed threshold update\n Cancel // 2: Cancel the pending threshold proposal\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the strategy with required parameters\n /// @param vaultAddress Address of the associated SuperVault\n /// @param feeConfigData Fee configuration\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external;\n\n /// @notice Execute a 4626 deposit by processing assets.\n /// @param controller The controller address\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @return sharesNet The amount of net shares to mint\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet);\n\n /// @notice Execute a 4626 mint by processing shares.\n /// @param controller The controller address\n /// @param sharesNet The amount of shares to mint\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @param assetsNet The amount of net assets that strategy will receive\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external;\n\n /// @notice Quotes the amount of assets that will be received for a given amount of shares.\n /// @param shares The amount of shares to mint\n /// @return assetsGross The amount of gross assets that will be received\n /// @return assetsNet The amount of net assets that will be received\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet);\n\n /// @notice Execute async redeem requests (redeem, cancel, claim).\n /// @param op The operation type (RedeemRequest, CancelRedeem, ClaimRedeem)\n /// @param controller The controller address\n /// @param receiver The receiver address\n /// @param amount The amount of assets or shares\n function handleOperations7540(Operation op, address controller, address receiver, uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Execute hooks for general strategy management (rebalancing, etc.).\n /// @param args Execution arguments containing hooks, calldata, proofs, expectations.\n function executeHooks(ExecuteArgs calldata args) external payable;\n\n /// @notice Fulfills pending cancel redeem requests by making shares claimable\n /// @dev Processes all controllers with pending cancellation flags\n /// @dev Can only be called by authorized managers\n /// @param controllers Array of controller addresses with pending cancel requests\n function fulfillCancelRedeemRequests(address[] memory controllers) external;\n\n /// @notice Fulfills pending redeem requests with exact total assets per controller (pre-fee).\n /// @dev PRE: Off-chain sort/unique controllers. Call executeHooks(sum(totalAssetsOut)) first.\n /// @dev Social: totalAssetsOut[i] = theoreticalGross[i] (full). Selective: totalAssetsOut[i] < theoreticalGross[i].\n /// @dev NOTE: totalAssetsOut includes fees - actual net amount received is calculated internally after fee\n /// deduction. @param controllers Ordered/unique controllers with pending requests.\n /// @param totalAssetsOut Total PRE-FEE assets available for each controller[i] (from executeHooks).\n function fulfillRedeemRequests(address[] calldata controllers, uint256[] calldata totalAssetsOut) external;\n\n /// @notice Skim performance fees based on per-share High Water Mark (PPS-based)\n /// @dev Can be called by any manager when vault PPS has grown above HWM PPS\n /// @dev Uses PPS growth to calculate profit: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev HWM is only updated during this function, not during deposits/redemptions\n function skimPerformanceFee() external;\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Manage a single yield source: add, update oracle, or remove\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle (used for adding/updating, ignored for removal)\n /// @param actionType Type of action (see YieldSourceAction enum)\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external;\n\n /// @notice Batch manage multiple yield sources in a single transaction\n /// @param sources Array of yield source addresses\n /// @param oracles Array of oracle addresses (used for adding/updating, ignored for removal)\n /// @param actionTypes Array of action types (see YieldSourceAction enum)\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external;\n\n /// @notice Change the fee recipient when the primary manager is changed\n /// @param newRecipient New fee recipient\n function changeFeeRecipient(address newRecipient) external;\n\n /// @notice Propose or execute a hook root update\n /// @notice Propose changes to vault-specific fee configuration\n /// @param performanceFeeBps New performance fee in basis points\n /// @param managementFeeBps New management fee in basis points\n /// @param recipient New fee recipient\n /// @dev IMPORTANT: Before executing the proposed update (via executeVaultFeeConfigUpdate),\n /// manager should call skimPerformanceFee() to collect performance fees on existing profits\n /// under the current fee structure to avoid losing profit or incorrect fee calculations.\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external;\n\n /// @notice Execute the proposed vault fee configuration update after timelock\n /// @dev IMPORTANT: Manager should call skimPerformanceFee() before executing this update\n /// to collect performance fees on existing profits under the current fee structure.\n /// Otherwise, profit earned under the old fee percentage will be lost or incorrectly calculated.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// to avoid incorrect fee calculations with the new fee structure.\n function executeVaultFeeConfigUpdate() external;\n\n /// @notice Reset the high-water mark PPS to the current PPS\n /// @dev This function is only callable by Aggregator\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// @param newHwmPps The new high-water mark PPS value\n function resetHighWaterMark(uint256 newHwmPps) external;\n\n /// @notice Manage PPS expiry threshold\n /// @param action Type of action (see PPSExpirationAction enum)\n /// @param ppsExpiration The new PPS expiry threshold\n function managePPSExpiration(PPSExpirationAction action, uint256 ppsExpiration) external;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set the slippage tolerance for all future redeem request fulfillments, until reset using this function\n /// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)\n function setRedeemSlippage(uint16 slippageBps) external;\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Get the vault info\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals);\n\n /// @notice Get the fee configurations\n function getConfigInfo() external view returns (FeeConfig memory feeConfig);\n\n /// @notice Returns the currently stored PPS value.\n function getStoredPPS() external view returns (uint256);\n\n /// @notice Get a yield source's configuration\n function getYieldSource(address source) external view returns (YieldSource memory);\n\n /// @notice Get all yield sources with their information\n /// @return Array of YieldSourceInfo structs\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory);\n\n /// @notice Get all yield source addresses\n /// @return Array of yield source addresses\n function getYieldSources() external view returns (address[] memory);\n\n /// @notice Get the count of yield sources\n /// @return Number of yield sources\n function getYieldSourcesCount() external view returns (uint256);\n\n /// @notice Check if a yield source exists\n /// @param source Address of the yield source\n /// @return True if the yield source exists\n function containsYieldSource(address source) external view returns (bool);\n\n /// @notice Get the average withdraw price for a controller\n /// @param controller The controller address\n /// @return averageWithdrawPrice The average withdraw price\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice);\n\n /// @notice Get the super vault state for a controller\n /// @param controller The controller address\n /// @return state The super vault state\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state);\n\n /// @notice Get the pending redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return pendingShares The amount of shares pending redemption\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares);\n\n /// @notice Get the pending cancellation for a redeem request for a controller\n /// @param controller The controller address\n /// @return isPending True if the redeem request is pending cancellation\n function pendingCancelRedeemRequest(address controller) external view returns (bool isPending);\n\n /// @notice Get the claimable cancel redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return claimableShares The amount of shares claimable\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares);\n\n /// @notice Get the claimable withdraw amount (assets) for a controller\n /// @param controller The controller address\n /// @return claimableAssets The amount of assets claimable\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets);\n\n /// @notice Preview exact redeem fulfillment for off-chain calculation\n /// @param controller The controller address to preview\n /// @return shares Pending redeem shares\n /// @return theoreticalAssets Theoretical assets at current PPS\n /// @return minAssets Minimum acceptable assets (slippage floor)\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets);\n\n /// @notice Batch preview exact redeem fulfillment for multiple controllers\n /// @dev Efficiently batches multiple previewExactRedeem calls to reduce RPC overhead\n /// @param controllers Array of controller addresses to preview\n /// @return totalTheoAssets Total theoretical assets across all controllers\n /// @return individualAssets Array of theoretical assets per controller\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets);\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev Returns 0 if totalSupply is 0 or currentPPS <= hwmPPS\n function vaultUnrealizedProfit() external view returns (uint256);\n}\n"},"src/interfaces/ISuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n/// @notice Enum representing different types of fees that can be managed\nenum FeeType {\n REVENUE_SHARE,\n PERFORMANCE_FEE_SHARE\n}\n/// @title ISuperGovernor\n/// @author Superform Labs\n/// @notice Interface for the SuperGovernor contract\n/// @dev Central registry for all deployed contracts in the Superform periphery\n\ninterface ISuperGovernor is IAccessControl {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Structure containing Merkle root data for a hook\n struct HookMerkleRootData {\n bytes32 currentRoot; // Current active Merkle root for the hook\n bytes32 proposedRoot; // Proposed new Merkle root (zero if no proposal exists)\n uint256 effectiveTime; // Timestamp when the proposed root becomes effective\n }\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when trying to access a contract that is not registered\n error CONTRACT_NOT_FOUND();\n /// @notice Thrown when providing an invalid address (typically zero address)\n error INVALID_ADDRESS();\n /// @notice Thrown when a hook is not approved but expected to be\n error HOOK_NOT_APPROVED();\n /// @notice Thrown when an invalid fee value is proposed (must be <= BPS_MAX)\n error INVALID_FEE_VALUE();\n /// @notice Thrown when no proposed fee exists but one is expected\n error NO_PROPOSED_FEE(FeeType feeType);\n /// @notice Thrown when timelock period has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when a validator is already registered\n error VALIDATOR_ALREADY_REGISTERED();\n /// @notice Thrown when trying to change active PPS oracle directly\n error MUST_USE_TIMELOCK_FOR_CHANGE();\n /// @notice Thrown when a SuperBank hook Merkle root is not registered but expected to be\n /// @dev This error is defined here for use by other contracts in the system (SuperVaultStrategy,\n /// SuperVaultAggregator, ECDSAPPSOracle)\n error INVALID_TIMESTAMP();\n /// @notice Thrown when attempting to set an invalid quorum value (typically zero)\n error INVALID_QUORUM();\n /// @notice Thrown when validator and public key array lengths don't match\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when trying to set validator config with an empty validator array\n error EMPTY_VALIDATOR_ARRAY();\n /// @notice Thrown when no active PPS oracle is set but one is required\n error NO_ACTIVE_PPS_ORACLE();\n /// @notice Thrown when no proposed PPS oracle exists but one is expected\n error NO_PROPOSED_PPS_ORACLE();\n /// @notice Error thrown when manager takeovers are frozen\n error MANAGER_TAKEOVERS_FROZEN();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error NO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error ZERO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed minimum staleness exists but one is expected\n error NO_PROPOSED_MIN_STALENESS();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when there's no pending change but one is expected\n error NO_PENDING_CHANGE();\n /// @notice Thrown when the super oracle is not found\n error SUPER_ORACLE_NOT_FOUND();\n /// @notice Thrown when the up token is not found\n error UP_NOT_FOUND();\n /// @notice Thrown when the upkeep token is not found\n error UPKEEP_TOKEN_NOT_FOUND();\n /// @notice Thrown when the gas info is invalid\n error INVALID_GAS_INFO();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an address is set in the registry\n /// @param key The key used to reference the address\n /// @param oldValue The old address value\n /// @param value The address value\n event AddressSet(bytes32 indexed key, address indexed oldValue, address indexed value);\n\n /// @notice Emitted when a hook is approved\n /// @param hook The address of the approved hook\n event HookApproved(address indexed hook);\n\n /// @notice Emitted when validator configuration is set\n /// @param version The version of the configuration\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys (for signature verification)\n /// @param quorum The quorum required for validator consensus\n /// @param offchainConfig Offchain configuration data\n event ValidatorConfigSet(\n uint256 version, address[] validators, bytes[] validatorPublicKeys, uint256 quorum, bytes offchainConfig\n );\n\n /// @notice Emitted when a hook is removed\n /// @param hook The address of the removed hook\n event HookRemoved(address indexed hook);\n\n /// @notice Emitted when a new fee is proposed\n /// @param feeType The type of fee being proposed\n /// @param value The proposed fee value (in basis points)\n /// @param effectiveTime The timestamp when the fee will be effective\n event FeeProposed(FeeType indexed feeType, uint256 value, uint256 effectiveTime);\n\n /// @notice Emitted when a fee is updated\n /// @param feeType The type of fee being updated\n /// @param value The new fee value (in basis points)\n event FeeUpdated(FeeType indexed feeType, uint256 value);\n\n /// @notice Emitted when a new SuperBank hook Merkle root is proposed\n /// @param hook The hook address for which the Merkle root is being proposed\n /// @param newRoot The new Merkle root\n /// @param effectiveTime The timestamp when the new root will be effective\n event SuperBankHookMerkleRootProposed(address indexed hook, bytes32 newRoot, uint256 effectiveTime);\n\n /// @notice Emitted when the SuperBank hook Merkle root is updated.\n /// @param hook The address of the hook for which the Merkle root was updated.\n /// @param newRoot The new Merkle root.\n event SuperBankHookMerkleRootUpdated(address indexed hook, bytes32 newRoot);\n\n /// @notice Emitted when an active PPS oracle is initially set\n /// @param oracle The address of the set oracle\n event ActivePPSOracleSet(address indexed oracle);\n\n /// @notice Emitted when a new PPS oracle is proposed\n /// @param oracle The address of the proposed oracle\n /// @param effectiveTime The timestamp when the proposal will be effective\n event ActivePPSOracleProposed(address indexed oracle, uint256 effectiveTime);\n\n /// @notice Emitted when the active PPS oracle is changed\n /// @param oldOracle The address of the previous oracle\n /// @param newOracle The address of the new oracle\n event ActivePPSOracleChanged(address indexed oldOracle, address indexed newOracle);\n\n /// @notice Event emitted when manager takeovers are permanently frozen\n event ManagerTakeoversFrozen();\n\n /// @notice Emitted when a change to upkeep payments status is proposed\n /// @param enabled The proposed status (enabled/disabled)\n /// @param effectiveTime The timestamp when the status change will be effective\n event UpkeepPaymentsChangeProposed(bool enabled, uint256 effectiveTime);\n\n /// @notice Emitted when upkeep payments status is changed\n /// @param enabled The new status (enabled/disabled)\n event UpkeepPaymentsChanged(bool enabled);\n\n /// @notice Emitted when a new minimum staleness is proposed\n /// @param newMinStaleness The proposed minimum staleness value\n /// @param effectiveTime The timestamp when the new value will be effective\n event MinStalenessProposed(uint256 newMinStaleness, uint256 effectiveTime);\n\n /// @notice Emitted when the minimum staleness is changed\n /// @param newMinStaleness The new minimum staleness value\n event MinStalenessChanged(uint256 newMinStaleness);\n\n /// @notice Emitted when gas info is set\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n event GasInfoSet(address indexed oracle, uint256 gasIncreasePerEntryBatch);\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets an address in the registry\n /// @param key The key to associate with the address\n /// @param value The address value\n function setAddress(bytes32 key, address value) external;\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Change the primary manager for a strategy\n /// @dev Only SuperGovernor can call this function directly\n /// @param strategy The strategy address\n /// @param newManager The new primary manager address\n /// @param feeRecipient The new fee recipient address\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Resets the high-water mark PPS to the current PPS\n /// @dev Only SuperGovernor can call this function\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value for the given strategy\n /// @param strategy Address of the strategy to reset the high-water mark for\n function resetHighWaterMark(address strategy) external;\n\n /// @notice Permanently freezes all manager takeovers globally\n function freezeManagerTakeover() external;\n\n /// @notice Changes the hooks root update timelock duration\n /// @param newTimelock New timelock duration in seconds\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes a new global hooks Merkle root\n /// @dev Only GOVERNOR_ROLE can call this function\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Sets veto status for global hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Sets veto status for a strategy-specific hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param strategy Address of the strategy to affect\n /// @param vetoed Whether to veto (true) or unveto (false) the strategy hooks root\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Sets the maximum staleness period for all oracle feeds\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleMaxStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness period for a specific oracle feed\n /// @param feed The address of the feed to set staleness for\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness periods for multiple oracle feeds in batch\n /// @param feeds The addresses of the feeds to set staleness for\n /// @param newMaxStalenessList The new maximum staleness periods in seconds\n function setOracleFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Queues an oracle update for execution after timelock period\n /// @param bases Base asset addresses\n /// @param quotes Quote asset addresses\n /// @param providers Provider identifiers\n /// @param feeds Feed addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Executes a previously queued oracle update after timelock has expired\n function executeOracleUpdate() external;\n\n /// @notice Queues a provider removal for execution after timelock period\n /// @param providers The providers to remove\n function queueOracleProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Sets uptime feeds for multiple data oracles in batch (Layer 2 only)\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Registers a hook for use in SuperVaults\n /// @param hook The address of the hook to register\n function registerHook(address hook) external;\n\n /// @notice Unregisters a hook from the approved list\n /// @param hook The address of the hook to unregister\n function unregisterHook(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the validator configuration for the protocol\n /// @dev This function atomically updates all validator configuration including quorum.\n /// The entire validator set is replaced (not incrementally updated).\n /// Version must be managed externally for cross-chain synchronization.\n /// Quorum updates require providing the full validator list.\n /// @param version The version number for the configuration (for cross-chain sync)\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys for signature verification\n /// @param quorum The number of validators required for consensus\n /// @param offchainConfig Offchain configuration data (emitted but not stored)\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the active PPS oracle (only if there is no active oracle yet)\n /// @param oracle Address of the PPS oracle to set as active\n function setActivePPSOracle(address oracle) external;\n\n /// @notice Proposes a new active PPS oracle (when there is already an active one)\n /// @param oracle Address of the PPS oracle to propose as active\n function proposeActivePPSOracle(address oracle) external;\n\n /// @notice Executes a previously proposed PPS oracle change after timelock has expired\n function executeActivePPSOracleChange() external;\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new fee value\n /// @param feeType The type of fee to propose\n /// @param value The proposed fee value (in basis points)\n function proposeFee(FeeType feeType, uint256 value) external;\n\n /// @notice Executes a previously proposed fee update after timelock has expired\n /// @param feeType The type of ffee to execute the update for\n function executeFeeUpdate(FeeType feeType) external;\n\n /// @notice Executes an upkeep claim on `SuperVaultAggregator`\n /// @param amount The amount to claim\n function executeUpkeepClaim(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets gas info for an oracle\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external;\n\n /// @notice Proposes a change to upkeep payments enabled status\n /// @param enabled The proposed enabled status\n function proposeUpkeepPaymentsChange(bool enabled) external;\n\n /// @notice Executes a previously proposed upkeep payments status change\n function executeUpkeepPaymentsChange() external;\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new minimum staleness value to prevent maxStaleness from being set too low\n /// @param newMinStaleness The proposed new minimum staleness value in seconds\n function proposeMinStaleness(uint256 newMinStaleness) external;\n\n /// @notice Executes a previously proposed minimum staleness change after timelock has expired\n function executeMinStalenessChange() external;\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to update the Merkle root for.\n /// @param proposedRoot The proposed new Merkle root.\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external;\n\n /// @notice Executes a previously proposed Merkle root update for a specific hook if the effective time has passed.\n /// @param hook The address of the hook to execute the update for.\n function executeSuperBankHookMerkleRootUpdate(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice The identifier of the role that grants access to critical governance functions\n function SUPER_GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to daily operations like hooks and validators\n function GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to bank management functions\n function BANK_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to gas management functions\n function GAS_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to oracle management functions\n function ORACLE_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to guardian functions\n function GUARDIAN_ROLE() external view returns (bytes32);\n\n /// @notice Gets an address from the registry\n /// @param key The key of the address to get\n /// @return The address value\n function getAddress(bytes32 key) external view returns (address);\n\n /// @notice Checks if manager takeovers are frozen\n /// @return True if manager takeovers are frozen, false otherwise\n function isManagerTakeoverFrozen() external view returns (bool);\n\n /// @notice Checks if a hook is registered\n /// @param hook The address of the hook to check\n /// @return True if the hook is registered, false otherwise\n function isHookRegistered(address hook) external view returns (bool);\n\n /// @notice Gets all registered hooks\n /// @return An array of registered hook addresses\n function getRegisteredHooks() external view returns (address[] memory);\n\n /// @notice Checks if an address is an approved validator\n /// @param validator The address to check\n /// @return True if the address is an approved validator, false otherwise\n function isValidator(address validator) external view returns (bool);\n\n /// @notice Checks if an address has the guardian role\n /// @param guardian Address to check\n /// @return true if the address has the GUARDIAN_ROLE\n function isGuardian(address guardian) external view returns (bool);\n\n /// @notice Returns the complete validator configuration\n /// @return version The current configuration version number\n /// @return validators Array of all registered validator addresses\n /// @return validatorPublicKeys Array of validator public keys\n /// @return quorum The number of validators required for consensus\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum);\n\n /// @notice Returns all registered validators\n /// @return List of validator addresses\n function getValidators() external view returns (address[] memory);\n\n /// @notice Returns the number of registered validators (O(1))\n function getValidatorsCount() external view returns (uint256);\n\n /// @notice Returns a validator address by index (0 … count-1)\n /// @param index The index into the validators set\n /// @return validator The validator address at the given index\n function getValidatorAt(uint256 index) external view returns (address validator);\n\n /// @notice Gets the proposed active PPS oracle and its effective time\n /// @return proposedOracle The proposed oracle address\n /// @return effectiveTime The timestamp when the proposed oracle will become effective\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime);\n\n /// @notice Gets the current quorum requirement for the active PPS Oracle\n /// @return The current quorum requirement\n function getPPSOracleQuorum() external view returns (uint256);\n\n /// @notice Gets the active PPS oracle\n /// @return The active PPS oracle address\n function getActivePPSOracle() external view returns (address);\n\n /// @notice Checks if an address is the current active PPS oracle\n /// @param oracle The address to check\n /// @return True if the address is the active PPS oracle, false otherwise\n function isActivePPSOracle(address oracle) external view returns (bool);\n\n /// @notice Gets the current fee value for a specific fee type\n /// @param feeType The type of fee to get\n /// @return The current fee value (in basis points)\n function getFee(FeeType feeType) external view returns (uint256);\n\n /// @notice Gets the current upkeep cost for an entry\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256);\n\n /// @notice Gets the proposed upkeep cost per update and its effective time\n /// @notice Gets the current minimum staleness value\n /// @return The current minimum staleness value in seconds\n function getMinStaleness() external view returns (uint256);\n\n /// @notice Gets the proposed minimum staleness value and its effective time\n /// @return proposedMinStaleness The proposed new minimum staleness value\n /// @return effectiveTime The timestamp when the new value will become effective\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime);\n\n /// @notice Returns the current Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to get the Merkle root for.\n /// @return The Merkle root for the hook's allowed targets.\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32);\n\n /// @notice Gets the proposed Merkle root and its effective time for a specific hook.\n /// @param hook The address of the hook to get the proposed Merkle root for.\n /// @return proposedRoot The proposed Merkle root.\n /// @return effectiveTime The timestamp when the proposed root will become effective.\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime);\n\n /// @notice Checks if upkeep payments are currently enabled\n /// @return enabled True if upkeep payments are enabled\n function isUpkeepPaymentsEnabled() external view returns (bool);\n\n /// @notice Gets the proposed upkeep payments status and effective time\n /// @return enabled The proposed status\n /// @return effectiveTime The timestamp when the change becomes effective\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime);\n\n /// @notice Gets the SUP strategy ID\n /// @return The ID of the SUP strategy vault\n function SUP_STRATEGY() external view returns (bytes32);\n\n /// @notice Gets the UP ID\n /// @return The ID of the UP token\n function UP() external view returns (bytes32);\n\n /// @notice Gets the UPKEEP_TOKEN ID\n /// @return The ID of the UPKEEP_TOKEN (used for upkeep payments, can be UP on mainnet or WETH/USDC on L2s)\n function UPKEEP_TOKEN() external view returns (bytes32);\n\n /// @notice Gets the Treasury ID\n /// @return The ID for the Treasury in the registry\n function TREASURY() external view returns (bytes32);\n\n /// @notice Gets the SuperOracle ID\n /// @return The ID for the SuperOracle in the registry\n function SUPER_ORACLE() external view returns (bytes32);\n\n /// @notice Gets the ECDSA PPS Oracle ID\n /// @return The ID for the ECDSA PPS Oracle in the registry\n function ECDSAPPSORACLE() external view returns (bytes32);\n\n /// @notice Gets the SuperVaultAggregator ID\n /// @return The ID for the SuperVaultAggregator in the registry\n function SUPER_VAULT_AGGREGATOR() external view returns (bytes32);\n\n /// @notice Gets the SuperBank ID\n /// @return The ID for the SuperBank in the registry\n function SUPER_BANK() external view returns (bytes32);\n\n /// @notice Gets the gas info for a specific SuperVault PPS Oracle\n /// @param oracle_ The address of the oracle to get gas info for\n /// @return The gas info for the specified oracle\n function getGasInfo(address oracle_) external view returns (uint256);\n\n /// @notice Cancels a previously proposed oracle provider removal\n function cancelOracleProviderRemoval() external;\n\n /// @notice Executes a previously proposed oracle provider removal after timelock has expired\n function executeOracleProviderRemoval() external;\n}\n"},"src/interfaces/SuperVault/ISuperVaultAggregator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { ISuperVaultStrategy } from \"../SuperVault/ISuperVaultStrategy.sol\";\n\n/// @title ISuperVaultAggregator\n/// @author Superform Labs\n/// @notice Interface for the SuperVaultAggregator contract\n/// @dev Registry and PPS oracle for all SuperVaults\ninterface ISuperVaultAggregator {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for forwarding PPS updates to avoid stack too deep errors\n /// @param strategy Address of the strategy being updated\n /// @param isExempt Whether the update is exempt from paying upkeep\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp when the value was generated\n /// @param upkeepCost Amount of upkeep tokens to charge if not exempt\n struct PPSUpdateData {\n address strategy;\n bool isExempt;\n uint256 pps;\n uint256 timestamp;\n uint256 upkeepCost;\n }\n\n /// @notice Local variables for vault creation to avoid stack too deep\n /// @param currentNonce Current vault creation nonce\n /// @param salt Salt for deterministic proxy creation\n /// @param initialPPS Initial price-per-share value\n struct VaultCreationLocalVars {\n uint256 currentNonce;\n bytes32 salt;\n uint256 initialPPS;\n }\n\n /// @notice Strategy configuration and state data\n /// @param pps Current price-per-share value\n /// @param lastUpdateTimestamp Last time PPS was updated\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param isPaused Whether the strategy is paused\n /// @param mainManager Address of the primary manager controlling the strategy\n /// @param secondaryManagers Set of secondary managers that can manage the strategy\n struct StrategyData {\n uint256 pps; // Slot 0: 32 bytes\n uint256 lastUpdateTimestamp; // Slot 1: 32 bytes\n uint256 minUpdateInterval; // Slot 2: 32 bytes\n uint256 maxStaleness; // Slot 3: 32 bytes\n // Packed slot 4: saves 2 storage slots (~4000 gas per read)\n address mainManager; // 20 bytes\n bool ppsStale; // 1 byte\n bool isPaused; // 1 byte\n bool hooksRootVetoed; // 1 byte\n uint72 __gap1; // 9 bytes padding\n EnumerableSet.AddressSet secondaryManagers;\n // Manager change proposal data\n address proposedManager;\n address proposedFeeRecipient;\n uint256 managerChangeEffectiveTime;\n // Hook validation data\n bytes32 managerHooksRoot;\n // Hook root update proposal data\n bytes32 proposedHooksRoot;\n uint256 hooksRootEffectiveTime;\n // PPS Verification thresholds\n uint256 deviationThreshold; // Threshold for abs(new - current) / current\n // Banned global leaves mapping\n mapping(bytes32 => bool) bannedLeaves; // Mapping of leaf hash to banned status\n // Min update interval proposal data\n uint256 proposedMinUpdateInterval;\n uint256 minUpdateIntervalEffectiveTime;\n uint256 lastUnpauseTimestamp; // Timestamp of last unpause (for skim timelock)\n }\n\n /// @notice Parameters for creating a new SuperVault trio\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param mainManager Address of the vault mainManager\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param feeConfig Fee configuration for the vault\n struct VaultCreationParams {\n address asset;\n string name;\n string symbol;\n address mainManager;\n address[] secondaryManagers;\n uint256 minUpdateInterval;\n uint256 maxStaleness;\n ISuperVaultStrategy.FeeConfig feeConfig;\n }\n\n /// @notice Struct to hold cached hook validation state variables to avoid stack too deep\n /// @param globalHooksRootVetoed Cached global hooks root veto status\n /// @param globalHooksRoot Cached global hooks root\n /// @param strategyHooksRootVetoed Cached strategy hooks root veto status\n /// @param strategyRoot Cached strategy hooks root\n struct HookValidationCache {\n bool globalHooksRootVetoed;\n bytes32 globalHooksRoot;\n bool strategyHooksRootVetoed;\n bytes32 strategyRoot;\n }\n\n /// @notice Arguments for validating a hook to avoid stack too deep\n /// @param hookAddress Address of the hook contract\n /// @param hookArgs Encoded arguments for the hook operation\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n struct ValidateHookArgs {\n address hookAddress;\n bytes hookArgs;\n bytes32[] globalProof;\n bytes32[] strategyProof;\n }\n\n /// @notice Two-step upkeep withdrawal request\n /// @param amount Amount to withdraw (full balance at time of request)\n /// @param effectiveTime When withdrawal can be executed (timestamp + 24h)\n struct UpkeepWithdrawalRequest {\n uint256 amount;\n uint256 effectiveTime;\n }\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when a new vault trio is created\n /// @param vault Address of the created SuperVault\n /// @param strategy Address of the created SuperVaultStrategy\n /// @param escrow Address of the created SuperVaultEscrow\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param nonce The nonce used for vault creation\n event VaultDeployed(\n address indexed vault,\n address indexed strategy,\n address escrow,\n address asset,\n string name,\n string symbol,\n uint256 indexed nonce\n );\n\n /// @notice Emitted when a PPS value is updated\n /// @param strategy Address of the strategy\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp of the update\n event PPSUpdated(address indexed strategy, uint256 pps, uint256 timestamp);\n\n /// @notice Emitted when a strategy is paused due to missed updates\n /// @param strategy Address of the paused strategy\n event StrategyPaused(address indexed strategy);\n\n /// @notice Emitted when a strategy is unpaused\n /// @param strategy Address of the unpaused strategy\n event StrategyUnpaused(address indexed strategy);\n\n /// @notice Emitted when a strategy validation check fails but execution continues\n /// @param strategy Address of the strategy that failed the check\n /// @param reason String description of which check failed\n event StrategyCheckFailed(address indexed strategy, string reason);\n\n /// @notice Emitted when upkeep tokens are deposited\n /// @param strategy Address of the strategy\n /// @param depositor Address of the depositor\n /// @param amount Amount of upkeep tokens deposited\n event UpkeepDeposited(address indexed strategy, address indexed depositor, uint256 amount);\n\n /// @notice Emitted when upkeep tokens are withdrawn\n /// @param strategy Address of the strategy\n /// @param withdrawer Address of the withdrawer (main manager of the strategy)\n /// @param amount Amount of upkeep tokens withdrawn\n event UpkeepWithdrawn(address indexed strategy, address indexed withdrawer, uint256 amount);\n\n /// @notice Emitted when an upkeep withdrawal is proposed (start of 24h timelock)\n /// @param strategy Address of the strategy\n /// @param mainManager Address of the main manager who proposed the withdrawal\n /// @param amount Amount of upkeep tokens to withdraw\n /// @param effectiveTime Timestamp when withdrawal can be executed\n event UpkeepWithdrawalProposed(\n address indexed strategy, address indexed mainManager, uint256 amount, uint256 effectiveTime\n );\n\n /// @notice Emitted when a pending upkeep withdrawal is cancelled (e.g., during governance takeover)\n /// @param strategy Address of the strategy\n event UpkeepWithdrawalCancelled(address indexed strategy);\n\n /// @notice Emitted when upkeep tokens are spent for validation\n /// @param strategy Address of the strategy\n /// @param amount Amount of upkeep tokens spent\n /// @param balance Current balance of the strategy\n /// @param claimableUpkeep Amount of upkeep tokens claimable\n event UpkeepSpent(address indexed strategy, uint256 amount, uint256 balance, uint256 claimableUpkeep);\n\n /// @notice Emitted when a secondary manager is added to a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager added\n event SecondaryManagerAdded(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a secondary manager is removed from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager removed\n event SecondaryManagerRemoved(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a primary manager is changed\n /// @param strategy Address of the strategy\n /// @param oldManager Address of the old primary manager\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n event PrimaryManagerChanged(\n address indexed strategy, address indexed oldManager, address indexed newManager, address feeRecipient\n );\n\n /// @notice Emitted when a change to primary manager is proposed by a secondary manager\n /// @param strategy Address of the strategy\n /// @param proposer Address of the secondary manager who made the proposal\n /// @param newManager Address of the proposed new primary manager\n /// @param effectiveTime Timestamp when the proposal can be executed\n event PrimaryManagerChangeProposed(\n address indexed strategy,\n address indexed proposer,\n address indexed newManager,\n address feeRecipient,\n uint256 effectiveTime\n );\n\n /// @notice Emitted when a primary manager change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledManager Address of the manager that was proposed\n event PrimaryManagerChangeCancelled(address indexed strategy, address indexed cancelledManager);\n\n /// @notice Emitted when the High Water Mark for a strategy is reset to PPS\n /// @param strategy Address of the strategy\n /// @param newHWM The new High Water Mark (PPS)\n event HighWaterMarkReset(address indexed strategy, uint256 indexed newHWM);\n\n /// @notice Emitted when a PPS update is stale (Validators could get slashed for innactivity)\n /// @param strategy Address of the strategy\n /// @param updateAuthority Address of the update authority\n /// @param timestamp Timestamp of the stale update\n event StaleUpdate(address indexed strategy, address indexed updateAuthority, uint256 timestamp);\n\n /// @notice Emitted when the global hooks Merkle root is being updated\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event GlobalHooksRootUpdateProposed(bytes32 indexed root, uint256 effectiveTime);\n\n /// @notice Emitted when the global hooks Merkle root is updated\n /// @param oldRoot Previous root value\n /// @param newRoot New root value\n event GlobalHooksRootUpdated(bytes32 indexed oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is updated\n /// @param strategy Address of the strategy\n /// @param oldRoot Previous root value (may be zero)\n /// @param newRoot New root value\n event StrategyHooksRootUpdated(address indexed strategy, bytes32 oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the account proposing the new root\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event StrategyHooksRootUpdateProposed(\n address indexed strategy, address indexed proposer, bytes32 root, uint256 effectiveTime\n );\n\n /// @notice Emitted when a proposed global hooks root update is vetoed by SuperGovernor\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event GlobalHooksRootVetoStatusChanged(bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's hooks Merkle root veto status changes\n /// @param strategy Address of the strategy\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event StrategyHooksRootVetoStatusChanged(address indexed strategy, bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's deviation threshold is updated\n /// @param strategy Address of the strategy\n /// @param deviationThreshold New deviation threshold (abs diff/current)\n event DeviationThresholdUpdated(address indexed strategy, uint256 deviationThreshold);\n\n /// @notice Emitted when the hooks root update timelock is changed\n /// @param newTimelock New timelock duration in seconds\n event HooksRootUpdateTimelockChanged(uint256 newTimelock);\n\n /// @notice Emitted when global leaves status is changed for a strategy\n /// @param strategy Address of the strategy\n /// @param leaves Array of leaf hashes that had their status changed\n /// @param statuses Array of new banned statuses (true = banned, false = allowed)\n event GlobalLeavesStatusChanged(address indexed strategy, bytes32[] leaves, bool[] statuses);\n\n /// @notice Emitted when upkeep is claimed\n /// @param superBank Address of the superBank\n /// @param amount Amount of upkeep claimed\n event UpkeepClaimed(address indexed superBank, uint256 amount);\n\n /// @notice Emitted when PPS update is too frequent (before minUpdateInterval)\n event UpdateTooFrequent();\n\n /// @notice Emitted when PPS update timestamp is not monotonically increasing\n event TimestampNotMonotonic();\n\n /// @notice Emitted when PPS update is rejected due to stale signature after unpause\n event StaleSignatureAfterUnpause(\n address indexed strategy, uint256 signatureTimestamp, uint256 lastUnpauseTimestamp\n );\n\n /// @notice Emitted when a strategy does not have enough upkeep balance\n event InsufficientUpkeep(address indexed strategy, address indexed strategyAddr, uint256 balance, uint256 cost);\n\n /// @notice Emitted when the provided timestamp is too large\n event ProvidedTimestampExceedsBlockTimestamp(\n address indexed strategy, uint256 argsTimestamp, uint256 blockTimestamp\n );\n\n /// @notice Emitted when a strategy is unknown\n event UnknownStrategy(address indexed strategy);\n\n /// @notice Emitted when the old primary manager is removed from the strategy\n /// @dev This can happen because of reaching the max number of secondary managers\n event OldPrimaryManagerRemoved(address indexed strategy, address indexed oldManager);\n\n /// @notice Emitted when a strategy's PPS is stale\n event StrategyPPSStale(address indexed strategy);\n\n /// @notice Emitted when a strategy's PPS is reset\n event StrategyPPSStaleReset(address indexed strategy);\n\n /// @notice Emitted when PPS is updated after performance fee skimming\n /// @param strategy Address of the strategy\n /// @param oldPPS Previous price-per-share value\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee skimmed that caused the PPS update\n /// @param timestamp Timestamp of the update\n event PPSUpdatedAfterSkim(\n address indexed strategy, uint256 oldPPS, uint256 newPPS, uint256 feeAmount, uint256 timestamp\n );\n\n /// @notice Emitted when a change to minUpdateInterval is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the manager who made the proposal\n /// @param newMinUpdateInterval The proposed new minimum update interval\n /// @param effectiveTime Timestamp when the proposal can be executed\n event MinUpdateIntervalChangeProposed(\n address indexed strategy, address indexed proposer, uint256 newMinUpdateInterval, uint256 effectiveTime\n );\n\n /// @notice Emitted when a minUpdateInterval change is executed\n /// @param strategy Address of the strategy\n /// @param oldMinUpdateInterval Previous minimum update interval\n /// @param newMinUpdateInterval New minimum update interval\n event MinUpdateIntervalChanged(\n address indexed strategy, uint256 oldMinUpdateInterval, uint256 newMinUpdateInterval\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is rejected due to validation failure\n /// @param strategy Address of the strategy\n /// @param proposedInterval The proposed interval that was rejected\n /// @param currentMaxStaleness The current maxStaleness value that caused rejection\n event MinUpdateIntervalChangeRejected(\n address indexed strategy, uint256 proposedInterval, uint256 currentMaxStaleness\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledInterval The proposed interval that was cancelled\n event MinUpdateIntervalChangeCancelled(address indexed strategy, uint256 cancelledInterval);\n\n /// @notice Emitted when a PPS update is rejected because strategy is paused\n /// @param strategy Address of the paused strategy\n event PPSUpdateRejectedStrategyPaused(address indexed strategy);\n\n /*///////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when address provided is zero\n error ZERO_ADDRESS();\n /// @notice Thrown when amount provided is zero\n error ZERO_AMOUNT();\n /// @notice Thrown when vault creation parameters are invalid (empty name or symbol)\n error INVALID_VAULT_PARAMS();\n /// @notice Thrown when array length is zero\n error ZERO_ARRAY_LENGTH();\n /// @notice Thrown when array length is zero\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when asset is invalid\n error INVALID_ASSET();\n /// @notice Thrown when insufficient upkeep balance for operation\n error INSUFFICIENT_UPKEEP();\n /// @notice Thrown when caller is not authorized\n error CALLER_NOT_AUTHORIZED();\n /// @notice Thrown when caller is not an approved PPS oracle\n error UNAUTHORIZED_PPS_ORACLE();\n /// @notice Thrown when caller is not authorized for update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n /// @notice Thrown when strategy address is not a known SuperVault strategy\n error UNKNOWN_STRATEGY();\n /// @notice Thrown when trying to unpause a strategy that is not paused\n error STRATEGY_NOT_PAUSED();\n /// @notice Thrown when trying to pause a strategy that is already paused\n error STRATEGY_ALREADY_PAUSED();\n /// @notice Thrown when array index is out of bounds\n error INDEX_OUT_OF_BOUNDS();\n /// @notice Thrown when attempting to add a manager that already exists\n error MANAGER_ALREADY_EXISTS();\n /// @notice Thrown when attempting to add a manager that is the primary manager\n error SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n /// @notice Thrown when there is no pending global hooks root change\n error NO_PENDING_GLOBAL_ROOT_CHANGE();\n /// @notice Thrown when attempting to execute a hooks root change before timelock has elapsed\n error ROOT_UPDATE_NOT_READY();\n /// @notice Thrown when a provided hook fails Merkle proof validation\n error HOOK_VALIDATION_FAILED();\n /// @notice Thrown when manager is not found\n error MANAGER_NOT_FOUND();\n /// @notice Thrown when there is no pending manager change proposal\n error NO_PENDING_MANAGER_CHANGE();\n /// @notice Thrown when caller is not authorized to update settings\n error UNAUTHORIZED_CALLER();\n /// @notice Thrown when the timelock for a proposed change has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when an array length is invalid\n error INVALID_ARRAY_LENGTH();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when arrays have mismatched lengths\n error MISMATCHED_ARRAY_LENGTHS();\n /// @notice Thrown when timestamp is invalid\n error INVALID_TIMESTAMP(uint256 index);\n /// @notice Thrown when too many secondary managers are added\n error TOO_MANY_SECONDARY_MANAGERS();\n /// @notice Thrown when upkeep withdrawal timelock has not passed yet\n error UPKEEP_WITHDRAWAL_NOT_READY();\n /// @notice Thrown when no pending upkeep withdrawal request exists\n error UPKEEP_WITHDRAWAL_NOT_FOUND();\n /// @notice PPS must decrease after skimming fees\n error PPS_MUST_DECREASE_AFTER_SKIM();\n /// @notice PPS deduction is larger than the maximum allowed fee rate\n error PPS_DEDUCTION_TOO_LARGE();\n /// @notice Thrown when no minUpdateInterval change proposal is pending\n error NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n /// @notice Thrown when minUpdateInterval >= maxStaleness\n error MIN_UPDATE_INTERVAL_TOO_HIGH();\n /// @notice Thrown when trying to update PPS while strategy is paused\n error STRATEGY_PAUSED();\n /// @notice Thrown when trying to update PPS while PPS is stale\n error PPS_STALE();\n\n /*//////////////////////////////////////////////////////////////\n VAULT CREATION\n //////////////////////////////////////////////////////////////*/\n /// @notice Creates a new SuperVault trio (SuperVault, SuperVaultStrategy, SuperVaultEscrow)\n /// @param params Parameters for the new vault creation\n /// @return superVault Address of the created SuperVault\n /// @return strategy Address of the created SuperVaultStrategy\n /// @return escrow Address of the created SuperVaultEscrow\n function createVault(VaultCreationParams calldata params)\n external\n returns (address superVault, address strategy, address escrow);\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for batch forwarding PPS updates\n /// @param strategies Array of strategy addresses\n /// @param ppss Array of price-per-share values\n /// @param timestamps Array of timestamps when values were generated\n /// @param updateAuthority Address of the update authority\n struct ForwardPPSArgs {\n address[] strategies;\n uint256[] ppss;\n uint256[] timestamps;\n address updateAuthority;\n }\n\n /// @notice Batch forwards validated PPS updates to multiple strategies\n /// @param args Struct containing all batch PPS update parameters\n function forwardPPS(ForwardPPSArgs calldata args) external;\n\n /// @notice Updates PPS directly after performance fee skimming\n /// @dev Only callable by the strategy contract itself (msg.sender must be a registered strategy)\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee that was skimmed (for event logging)\n function updatePPSAfterSkim(uint256 newPPS, uint256 feeAmount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Deposits upkeep tokens for strategy upkeep\n /// @dev The upkeep token is configurable per chain (UP on mainnet, WETH on L2s, etc.)\n /// @param strategy Address of the strategy to deposit for\n /// @param amount Amount of upkeep tokens to deposit\n function depositUpkeep(address strategy, uint256 amount) external;\n\n /// @notice Proposes withdrawal of upkeep tokens from strategy upkeep balance (starts 24h timelock)\n /// @dev Only the main manager can propose. Withdraws full balance at time of proposal.\n /// @param strategy Address of the strategy to withdraw from\n function proposeWithdrawUpkeep(address strategy) external;\n\n /// @notice Executes a pending upkeep withdrawal after 24h timelock\n /// @dev Anyone can execute, but funds go to the main manager of the strategy\n /// @param strategy Address of the strategy to withdraw from\n function executeWithdrawUpkeep(address strategy) external;\n\n /// @notice Claims upkeep tokens from the contract\n /// @param amount Amount of upkeep tokens to claim\n function claimUpkeep(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n PAUSE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Manually pauses a strategy\n /// @param strategy Address of the strategy to pause\n function pauseStrategy(address strategy) external;\n\n /// @notice Manually unpauses a strategy\n /// @param strategy Address of the strategy to unpause\n function unpauseStrategy(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER MANAGEMENT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Adds a secondary manager to a strategy\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to add\n function addSecondaryManager(address strategy, address manager) external;\n\n /// @notice Removes a secondary manager from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to remove\n function removeSecondaryManager(address strategy, address manager) external;\n\n /// @notice Changes the primary manager of a strategy immediately (only callable by SuperGovernor)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Proposes a change to the primary manager (callable by secondary managers)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the proposed new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function proposeChangePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Cancels a pending primary manager change proposal\n /// @dev Only the current primary manager can cancel the proposal\n /// @param strategy Address of the strategy\n function cancelChangePrimaryManager(address strategy) external;\n\n /// @notice Executes a previously proposed change to the primary manager after timelock\n /// @param strategy Address of the strategy\n function executeChangePrimaryManager(address strategy) external;\n\n /// @notice Resets the strategy's performance-fee high-water mark to PPS\n /// @dev Only callable by SuperGovernor\n /// @param strategy Address of the strategy\n function resetHighWaterMark(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK VALIDATION FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets a new hooks root update timelock duration\n /// @param newTimelock The new timelock duration in seconds\n function setHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes an update to the global hooks Merkle root\n /// @dev Only callable by SUPER_GOVERNOR\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed global hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeGlobalHooksRootUpdate() external;\n\n /// @notice Proposes an update to a strategy-specific hooks Merkle root\n /// @dev Only callable by the main manager for the strategy\n /// @param strategy Address of the strategy\n /// @param newRoot New Merkle root for strategy-specific hooks\n function proposeStrategyHooksRoot(address strategy, bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed strategy hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n /// @param strategy Address of the strategy whose root update to execute\n function executeStrategyHooksRootUpdate(address strategy) external;\n\n /// @notice Set veto status for the global hooks root\n /// @dev Only callable by SuperGovernor\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Set veto status for a strategy-specific hooks root\n /// @notice Sets the veto status of a strategy's hooks Merkle root\n /// @param strategy Address of the strategy\n /// @param vetoed Whether to veto (true) or unveto (false)\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Updates the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @param deviationThreshold_ New deviation threshold (abs diff/current ratio, scaled by 1e18)\n function updateDeviationThreshold(address strategy, uint256 deviationThreshold_) external;\n\n /// @notice Changes the banned status of global leaves for a specific strategy\n /// @dev Only callable by the primary manager of the strategy\n /// @param leaves Array of leaf hashes to change status for\n /// @param statuses Array of banned statuses (true = banned, false = allowed)\n /// @param strategy Address of the strategy to change banned leaves for\n function changeGlobalLeavesStatus(bytes32[] memory leaves, bool[] memory statuses, address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MIN UPDATE INTERVAL MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Proposes a change to the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @param newMinUpdateInterval The proposed new minimum update interval (in seconds)\n /// @dev Only the main manager can propose. Must be less than maxStaleness\n function proposeMinUpdateIntervalChange(address strategy, uint256 newMinUpdateInterval) external;\n\n /// @notice Executes a previously proposed minUpdateInterval change after timelock\n /// @param strategy Address of the strategy whose minUpdateInterval to update\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Cancels a pending minUpdateInterval change proposal\n /// @param strategy Address of the strategy\n /// @dev Only the main manager can cancel\n function cancelMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Gets the proposed minUpdateInterval and effective time\n /// @param strategy Address of the strategy\n /// @return proposedInterval The proposed minimum update interval\n /// @return effectiveTime The timestamp when the proposed interval becomes effective\n function getProposedMinUpdateInterval(address strategy)\n external\n view\n returns (uint256 proposedInterval, uint256 effectiveTime);\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the current vault creation nonce\n /// @dev This nonce is incremented every time a new vault is created\n /// @return Current vault creation nonce\n function getCurrentNonce() external view returns (uint256);\n\n /// @notice Check if the global hooks root is currently vetoed\n /// @return vetoed True if the global hooks root is vetoed\n function isGlobalHooksRootVetoed() external view returns (bool vetoed);\n\n /// @notice Check if a strategy hooks root is currently vetoed\n /// @param strategy Address of the strategy to check\n /// @return vetoed True if the strategy hooks root is vetoed\n function isStrategyHooksRootVetoed(address strategy) external view returns (bool vetoed);\n\n /// @notice Gets the current hooks root update timelock duration\n /// @return The current timelock duration in seconds\n function getHooksRootUpdateTimelock() external view returns (uint256);\n\n /// @notice Gets the current PPS (price-per-share) for a strategy\n /// @param strategy Address of the strategy\n /// @return pps Current price-per-share value\n function getPPS(address strategy) external view returns (uint256 pps);\n\n /// @notice Gets the last update timestamp for a strategy's PPS\n /// @param strategy Address of the strategy\n /// @return timestamp Last update timestamp\n function getLastUpdateTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @return interval Minimum time between updates\n function getMinUpdateInterval(address strategy) external view returns (uint256 interval);\n\n /// @notice Gets the maximum staleness period for a strategy\n /// @param strategy Address of the strategy\n /// @return staleness Maximum time allowed between updates\n function getMaxStaleness(address strategy) external view returns (uint256 staleness);\n\n /// @notice Gets the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @return deviationThreshold The current deviation threshold (abs diff/current ratio, scaled by 1e18)\n function getDeviationThreshold(address strategy) external view returns (uint256 deviationThreshold);\n\n /// @notice Checks if a strategy is currently paused\n /// @param strategy Address of the strategy\n /// @return isPaused True if paused, false otherwise\n function isStrategyPaused(address strategy) external view returns (bool isPaused);\n\n /// @notice Checks if a strategy's PPS is stale\n /// @dev PPS is automatically set to stale when the strategy is paused due to\n /// lack of upkeep payment in `SuperVaultAggregator`\n /// @param strategy Address of the strategy\n /// @return isStale True if stale, false otherwise\n function isPPSStale(address strategy) external view returns (bool isStale);\n\n /// @notice Gets the last unpause timestamp for a strategy\n /// @param strategy Address of the strategy\n /// @return timestamp Last unpause timestamp (0 if never unpaused)\n function getLastUnpauseTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the current upkeep balance for a strategy\n /// @param strategy Address of the strategy\n /// @return balance Current upkeep balance in upkeep tokens\n function getUpkeepBalance(address strategy) external view returns (uint256 balance);\n\n /// @notice Gets the main manager for a strategy\n /// @param strategy Address of the strategy\n /// @return manager Address of the main manager\n function getMainManager(address strategy) external view returns (address manager);\n\n /// @notice Gets pending primary manager change details\n /// @param strategy Address of the strategy\n /// @return proposedManager Address of the proposed new manager (address(0) if no pending change)\n /// @return effectiveTime Timestamp when the change can be executed (0 if no pending change)\n function getPendingManagerChange(address strategy)\n external\n view\n returns (address proposedManager, uint256 effectiveTime);\n\n /// @notice Checks if an address is the main manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isMainManager True if the address is the main manager, false otherwise\n function isMainManager(address manager, address strategy) external view returns (bool isMainManager);\n\n /// @notice Gets all secondary managers for a strategy\n /// @param strategy Address of the strategy\n /// @return secondaryManagers Array of secondary manager addresses\n function getSecondaryManagers(address strategy) external view returns (address[] memory secondaryManagers);\n\n /// @notice Checks if an address is a secondary manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isSecondaryManager True if the address is a secondary manager, false otherwise\n function isSecondaryManager(address manager, address strategy) external view returns (bool isSecondaryManager);\n\n /// @dev Internal helper function to check if an address is any kind of manager (primary or secondary)\n /// @param manager Address to check\n /// @param strategy The strategy to check against\n /// @return True if the address is either the primary manager or a secondary manager\n function isAnyManager(address manager, address strategy) external view returns (bool);\n\n /// @notice Gets all created SuperVaults\n /// @return Array of SuperVault addresses\n function getAllSuperVaults() external view returns (address[] memory);\n\n /// @notice Gets a SuperVault by index\n /// @param index The index of the SuperVault\n /// @return The SuperVault address at the given index\n function superVaults(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultStrategies\n /// @return Array of SuperVaultStrategy addresses\n function getAllSuperVaultStrategies() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultStrategy by index\n /// @param index The index of the SuperVaultStrategy\n /// @return The SuperVaultStrategy address at the given index\n function superVaultStrategies(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultEscrows\n /// @return Array of SuperVaultEscrow addresses\n function getAllSuperVaultEscrows() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultEscrow by index\n /// @param index The index of the SuperVaultEscrow\n /// @return The SuperVaultEscrow address at the given index\n function superVaultEscrows(uint256 index) external view returns (address);\n\n /// @notice Validates a hook against both global and strategy-specific Merkle roots\n /// @param strategy Address of the strategy\n /// @param args Arguments for hook validation\n /// @return isValid True if the hook is valid against either root\n function validateHook(address strategy, ValidateHookArgs calldata args) external view returns (bool isValid);\n\n /// @notice Batch validates multiple hooks against Merkle roots\n /// @param strategy Address of the strategy\n /// @param argsArray Array of hook validation arguments\n /// @return validHooks Array of booleans indicating which hooks are valid\n function validateHooks(\n address strategy,\n ValidateHookArgs[] calldata argsArray\n )\n external\n view\n returns (bool[] memory validHooks);\n\n /// @notice Gets the current global hooks Merkle root\n /// @return root The current global hooks Merkle root\n function getGlobalHooksRoot() external view returns (bytes32 root);\n\n /// @notice Gets the proposed global hooks root and effective time\n /// @return root The proposed global hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedGlobalHooksRoot() external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Checks if the global hooks root is active (timelock period has passed)\n /// @return isActive True if the global hooks root is active\n function isGlobalHooksRootActive() external view returns (bool);\n\n /// @notice Gets the hooks Merkle root for a specific strategy\n /// @param strategy Address of the strategy\n /// @return root The strategy-specific hooks Merkle root\n function getStrategyHooksRoot(address strategy) external view returns (bytes32 root);\n\n /// @notice Gets the proposed strategy hooks root and effective time\n /// @param strategy Address of the strategy\n /// @return root The proposed strategy hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedStrategyHooksRoot(address strategy) external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Gets the total number of SuperVaults\n /// @return count The total number of SuperVaults\n function getSuperVaultsCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultStrategies\n /// @return count The total number of SuperVaultStrategies\n function getSuperVaultStrategiesCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultEscrows\n /// @return count The total number of SuperVaultEscrows\n function getSuperVaultEscrowsCount() external view returns (uint256);\n}\n"},"src/vendor/standards/ERC7540/IERC7540Vault.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport { IERC7741 } from \"../ERC7741/IERC7741.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller) external view returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller) external view returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7540CancelDeposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 assets);\n}\n\n//IERC7887Redeem\ninterface IERC7540CancelRedeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 shares);\n}\n\n/**\n * @title IERC7540\n * @dev Fully async ERC7540 implementation according to the standard\n * @dev Adapted from Centrifuge's IERC7540 implementation\n */\ninterface IERC7540 is IERC7540Deposit, IERC7540Redeem { }\n\n/**\n * @title IERC7540Vault\n * @dev This is the specific set of interfaces used by the SuperVaults\n */\ninterface IERC7540Vault is IERC7540, IERC7741 {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n}\n"},"src/vendor/standards/ERC7741/IERC7741.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n )\n external\n returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},"src/vendor/standards/ERC7575/IERC7575.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n event Withdraw(\n address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the address of the share token\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function share() external view returns (address shareTokenAddress);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"src/interfaces/SuperVault/ISuperVaultEscrow.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperVaultEscrow\n/// @notice Interface for SuperVault escrow contract that holds shares during request/claim process\n/// @author Superform Labs\ninterface ISuperVaultEscrow {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error ALREADY_INITIALIZED();\n error UNAUTHORIZED();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when escrow is initialized\n /// @param vault The vault contract address\n event Initialized(address indexed vault);\n\n /// @notice Emitted when shares are transferred to escrow\n /// @param from The address shares were transferred from\n /// @param amount The amount of shares escrowed\n event SharesEscrowed(address indexed from, uint256 amount);\n\n /// @notice Emitted when shares are returned from escrow\n /// @param to The address shares were returned to\n /// @param amount The amount of shares returned\n event SharesReturned(address indexed to, uint256 amount);\n\n /// @notice Emitted when assets are returned from escrow\n /// @param to The address assets were returned to\n /// @param amount The amount of assets returned\n event AssetsReturned(address indexed to, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initialize the escrow with required parameters\n /// @param vaultAddress The vault contract address\n function initialize(address vaultAddress) external;\n\n /*//////////////////////////////////////////////////////////////\n VAULT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Transfer shares from user to escrow during redeem request\n /// @param from The address to transfer shares from\n /// @param amount The amount of shares to transfer\n function escrowShares(address from, uint256 amount) external;\n\n /// @notice Return shares from escrow to user during redeem cancellation\n /// @param to The address to return shares to\n /// @param amount The amount of shares to return\n function returnShares(address to, uint256 amount) external;\n\n /// @notice Return assets from escrow to vault during deposit cancellation\n /// @param to The address to return assets to\n /// @param amount The amount of assets to return\n function returnAssets(address to, uint256 amount) external;\n}\n"},"src/libraries/AssetMetadataLib.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/interfaces/IERC20Metadata.sol\";\n\n/// @title AssetMetadataLib\n/// @author Superform Labs\n/// @notice Library for handling ERC20 metadata operations\nlibrary AssetMetadataLib {\n error INVALID_ASSET();\n\n /**\n * @notice Attempts to fetch an asset's decimals\n * @dev A return value of false indicates that the attempt failed in some way\n * @param asset_ The address of the token to query\n * @return ok Boolean indicating if the operation was successful\n * @return assetDecimals The token's decimals if successful, 0 otherwise\n */\n function tryGetAssetDecimals(address asset_) internal view returns (bool ok, uint8 assetDecimals) {\n if (asset_.code.length == 0) revert INVALID_ASSET();\n\n (bool success, bytes memory encodedDecimals) =\n address(asset_).staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));\n if (success && encodedDecimals.length >= 32) {\n uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n if (returnedDecimals <= type(uint8).max) {\n // casting to 'uint8' is safe because the returned decimals is a valid uint8\n // forge-lint: disable-next-line(unsafe-typecast)\n return (true, uint8(returnedDecimals));\n }\n }\n return (false, 0);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)\npragma solidity >=0.8.4;\n\n/**\n * @dev Standard ERC-20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.\n */\ninterface IERC20Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC20InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC20InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n * @param allowance Amount of tokens a `spender` is allowed to operate with.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC20InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC-721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.\n */\ninterface IERC721Errors {\n /**\n * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.\n * Used in balance queries.\n * @param owner Address of the current owner of a token.\n */\n error ERC721InvalidOwner(address owner);\n\n /**\n * @dev Indicates a `tokenId` whose `owner` is the zero address.\n * @param tokenId Identifier number of a token.\n */\n error ERC721NonexistentToken(uint256 tokenId);\n\n /**\n * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param tokenId Identifier number of a token.\n * @param owner Address of the current owner of a token.\n */\n error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC721InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC721InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param tokenId Identifier number of a token.\n */\n error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC721InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC-1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.\n */\ninterface IERC1155Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n * @param tokenId Identifier number of a token.\n */\n error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC1155InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC1155InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param owner Address of the current owner of a token.\n */\n error ERC1155MissingApprovalForAll(address operator, address owner);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC1155InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC1155InvalidOperator(address operator);\n\n /**\n * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n * Used in batch transfers.\n * @param idsLength Length of the array of token identifiers\n * @param valuesLength Length of the array of token amounts\n */\n error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing a bytes32 `messageHash` with\n * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n * keccak256, although any bytes32 value can be safely used because the final digest will\n * be re-hashed.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing an arbitrary `message` with\n * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n return\n keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x00` (data with intended validator).\n *\n * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n * `validator` address. Then hashing the result.\n *\n * See {ECDSA-recover}.\n */\n function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n }\n\n /**\n * @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.\n */\n function toDataWithIntendedValidatorHash(\n address validator,\n bytes32 messageHash\n ) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, hex\"19_00\")\n mstore(0x02, shl(96, validator))\n mstore(0x16, messageHash)\n digest := keccak256(0x00, 0x36)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).\n *\n * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n *\n * See {ECDSA-recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n mstore(ptr, hex\"19_01\")\n mstore(add(ptr, 0x02), domainSeparator)\n mstore(add(ptr, 0x22), structHash)\n digest := keccak256(ptr, 0x42)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)\n\npragma solidity >=0.4.16;\n\ninterface IERC5267 {\n /**\n * @dev MAY be emitted to signal that the domain could have changed.\n */\n event EIP712DomainChanged();\n\n /**\n * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n * signature.\n */\n function eip712Domain()\n external\n view\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n );\n}\n"},"lib/v2-core/src/interfaces/ISuperHook.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { Execution } from \"modulekit/accounts/erc7579/lib/ExecutionLib.sol\";\n\n/**\n * @title SuperHook System\n * @author Superform Labs\n * @notice The hook system provides a modular and composable way to execute operations on assets\n * @dev The hook system architecture consists of several interfaces that work together:\n * - ISuperHook: The base interface all hooks implement, with lifecycle methods\n * - ISuperHookResult: Provides execution results and output information\n * - Specialized interfaces (ISuperHookOutflow, ISuperHookLoans, etc.) for specific behaviors\n *\n * Hooks are executed in sequence, where each hook can access the results from previous hooks.\n * The three main types of hooks are:\n * - NONACCOUNTING: Utility hooks that don't update the accounting system\n * - INFLOW: Hooks that process deposits or additions to positions\n * - OUTFLOW: Hooks that process withdrawals or reductions to positions\n */\ninterface ISuperLockableHook {\n /// @notice The vault bank address used to lock SuperPositions\n /// @dev Only relevant for cross-chain operations where positions are locked\n /// @return The vault bank address, or address(0) if not applicable\n function vaultBank() external view returns (address);\n\n /// @notice The destination chain ID for cross-chain operations\n /// @dev Used to identify the target chain for cross-chain position transfers\n /// @return The destination chain ID, or 0 if not a cross-chain operation\n function dstChainId() external view returns (uint256);\n}\n\ninterface ISuperHookSetter {\n /// @notice Sets the output amount for the hook\n /// @dev Used for updating `outAmount` when fees were deducted\n /// @param outAmount The amount of tokens processed by the hook\n /// @param caller The caller address for context identification\n function setOutAmount(uint256 outAmount, address caller) external;\n}\n/// @title ISuperHookInspector\n/// @author Superform Labs\n/// @notice Interface for the SuperHookInspector contract that manages hook inspection\n\ninterface ISuperHookInspector {\n /// @notice Inspect the hook\n /// @param data The hook data to inspect\n /// @return argsEncoded The arguments of the hook encoded\n function inspect(bytes calldata data) external view returns (bytes memory argsEncoded);\n}\n\n/// @title ISuperHookResult\n/// @author Superform Labs\n/// @notice Interface that exposes the result of a hook execution\n/// @dev All hooks must implement this interface to provide standardized access to execution results.\n/// These results are used by subsequent hooks in the execution chain and by the executor.\ninterface ISuperHookResult {\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The type of hook\n /// @dev Used to determine how accounting should process this hook's results\n /// @return The hook type (NONACCOUNTING, INFLOW, or OUTFLOW)\n function hookType() external view returns (ISuperHook.HookType);\n\n /// @notice The SuperPosition (SP) token associated with this hook\n /// @dev For vault hooks, this would be the tokenized position representing shares\n /// @return The address of the SP token, or address(0) if not applicable\n function spToken() external view returns (address);\n\n /// @notice The underlying asset token being processed\n /// @dev For most hooks, this is the actual token being deposited or withdrawn\n /// @return The address of the asset token, or address(0) for native assets\n function asset() external view returns (address);\n\n /// @notice The amount of tokens processed by the hook in a given caller context, subject to fees after update\n /// @dev This is the primary output value used by subsequent hooks\n /// @param caller The caller address for context identification\n /// @return The amount of tokens (assets or shares) processed\n function getOutAmount(address caller) external view returns (uint256);\n}\n\n/// @title ISuperHookContextAware\n/// @author Superform Labs\n/// @notice Interface for hooks that can use previous hook results in their execution\n/// @dev Enables contextual awareness and data flow between hooks in a chain\ninterface ISuperHookContextAware {\n /// @notice Determines if this hook should use the amount from the previous hook\n /// @dev Used to create hook chains where output from one hook becomes input to the next\n /// @param data The hook-specific data containing configuration\n /// @return True if the hook should use the previous hook's output amount\n function decodeUsePrevHookAmount(bytes memory data) external pure returns (bool);\n}\n\n/// @title ISuperHookInflowOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that handle both inflows and outflows\n/// @dev Provides standardized amount extraction for both deposit and withdrawal operations\ninterface ISuperHookInflowOutflow {\n /// @notice Extracts the amount from the hook's calldata\n /// @dev Used to determine the quantity of assets or shares being processed\n /// @param data The hook-specific calldata containing the amount\n /// @return The amount of tokens to process\n function decodeAmount(bytes memory data) external pure returns (uint256);\n}\n\n/// @title ISuperHookOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that specifically handle outflows (withdrawals)\n/// @dev Provides additional functionality needed only for outflow operations\ninterface ISuperHookOutflow {\n /// @notice Replace the amount in the calldata\n /// @param data The data to replace the amount in\n /// @param amount The amount to replace\n /// @return data The data with the replaced amount\n function replaceCalldataAmount(bytes memory data, uint256 amount) external pure returns (bytes memory);\n}\n\n/// @title ISuperHookResultOutflow\n/// @author Superform Labs\n/// @notice Extended result interface for outflow hook operations\n/// @dev Extends the base result interface with outflow-specific information\ninterface ISuperHookResultOutflow is ISuperHookResult {\n /// @notice The amount of shares consumed during outflow processing\n /// @dev Used for cost basis calculation in the accounting system\n /// @return The amount of shares consumed from the user's position\n function usedShares() external view returns (uint256);\n}\n\n/// @title ISuperHookLoans\n/// @author Superform Labs\n/// @notice Interface for hooks that interact with lending protocols\n/// @dev Extends context awareness to enable loan operations within hook chains\ninterface ISuperHookLoans is ISuperHookContextAware {\n /// @notice Gets the address of the token being borrowed\n /// @dev Used to identify which asset is being borrowed from the lending protocol\n /// @param data The hook-specific data containing loan information\n /// @return The address of the borrowed token\n function getLoanTokenAddress(bytes memory data) external pure returns (address);\n\n /// @notice Gets the address of the token used as collateral\n /// @dev Used to identify which asset is being used to secure the loan\n /// @param data The hook-specific data containing collateral information\n /// @return The address of the collateral token\n function getCollateralTokenAddress(bytes memory data) external view returns (address);\n\n /// @notice Gets the current loan token balance for an account\n /// @dev Used to track outstanding loan amounts\n /// @param account The account to check the loan balance for\n /// @param data The hook-specific data containing loan parameters\n /// @return The amount of tokens currently borrowed\n function getLoanTokenBalance(address account, bytes memory data) external view returns (uint256);\n\n /// @notice Gets the current collateral token balance for an account\n /// @dev Used to track collateral positions\n /// @param account The account to check the collateral balance for\n /// @param data The hook-specific data containing collateral parameters\n /// @return The amount of tokens currently used as collateral\n function getCollateralTokenBalance(address account, bytes memory data) external view returns (uint256);\n}\n\n/// @title ISuperHookAsyncCancelations\n/// @author Superform Labs\n/// @notice Interface for hooks that can cancel asynchronous operations\n/// @dev Used to handle cancellation of pending operations that haven't completed\ninterface ISuperHookAsyncCancelations {\n /// @notice Types of cancellations that can be performed\n /// @dev Distinguishes between different operation types that can be canceled\n enum CancelationType {\n NONE, // Not a cancelation hook\n INFLOW, // Cancels a pending deposit operation\n OUTFLOW // Cancels a pending withdrawal operation\n\n }\n\n /// @notice Identifies the type of async operation this hook can cancel\n /// @dev Used to verify the hook is appropriate for the operation being canceled\n /// @return asyncType The type of cancellation this hook performs\n function isAsyncCancelHook() external pure returns (CancelationType asyncType);\n}\n\n/// @title ISuperHook\n/// @author Superform Labs\n/// @notice The core hook interface that all hooks must implement\n/// @dev Defines the lifecycle methods and execution flow for the hook system\n/// Hooks are executed in sequence with results passed between them\ninterface ISuperHook {\n /*//////////////////////////////////////////////////////////////\n\n ENUMS\n //////////////////////////////////////////////////////////////*/\n /// @notice Defines the possible types of hooks in the system\n /// @dev Used to determine how the hook affects accounting and what operations it performs\n enum HookType {\n NONACCOUNTING, // Hook doesn't affect accounting (e.g., a swap or bridge)\n INFLOW, // Hook processes deposits or positions being added\n OUTFLOW // Hook processes withdrawals or positions being removed\n\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Builds the execution array for the hook operation\n /// @dev This is the core method where hooks define their on-chain interactions\n /// The returned executions are a sequence of contract calls to perform\n /// No state changes should occur in this method\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform executions for (usually an ERC7579 account)\n /// @param data The hook-specific parameters and configuration data\n /// @return executions Array of Execution structs defining calls to make\n function build(\n address prevHook,\n address account,\n bytes calldata data\n )\n external\n view\n returns (Execution[] memory executions);\n\n /*//////////////////////////////////////////////////////////////\n PUBLIC METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Prepares the hook for execution\n /// @dev Called before the main execution, used to validate inputs and set execution context\n /// This method may perform state changes to set up the hook's execution state\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform operations for\n /// @param data The hook-specific parameters and configuration data\n function preExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Finalizes the hook after execution\n /// @dev Called after the main execution, used to update hook state and calculate results\n /// Sets output values (outAmount, usedShares, etc.) for subsequent hooks\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account operations were performed for\n /// @param data The hook-specific parameters and configuration data\n function postExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Returns the specific subtype identification for this hook\n /// @dev Used to categorize hooks beyond the basic HookType\n /// For example, a hook might be of type INFLOW but subtype VAULT_DEPOSIT\n /// @return A bytes32 identifier for the specific hook functionality\n function subtype() external view returns (bytes32);\n\n /// @notice Resets hook mutexes\n /// @param caller The caller address for context identification\n function resetExecutionState(address caller) external;\n\n /// @notice Sets the caller address that initiated the execution\n /// @dev Used for security validation between preExecute and postExecute calls\n /// @param caller The caller address for context identification\n function setExecutionContext(address caller) external;\n\n /// @notice Returns the execution nonce for the current execution context\n /// @dev Used to ensure unique execution contexts and prevent replay attacks\n /// @return The execution nonce\n function executionNonce() external view returns (uint256);\n\n /// @notice Returns the last caller registered by `setExecutionContext`\n /// @return The last caller address\n function lastCaller() external view returns (address);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\nimport {Math} from \"../math/Math.sol\";\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * The following types are supported:\n *\n * - `bytes32` (`Bytes32Set`) since v3.3.0\n * - `address` (`AddressSet`) since v3.3.0\n * - `uint256` (`UintSet`) since v3.3.0\n * - `string` (`StringSet`) since v5.4.0\n * - `bytes` (`BytesSet`) since v5.4.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that\n * using it may render the function uncallable if the set grows to the point where clearing it consumes too much\n * gas to fit in a block.\n */\n function _clear(Set storage set) private {\n uint256 len = _length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {\n unchecked {\n end = Math.min(end, _length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes32[] memory result = new bytes32[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(Bytes32Set storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(AddressSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(UintSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n struct StringSet {\n // Storage of set values\n string[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(string value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(StringSet storage set, string memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(StringSet storage set, string memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n string memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(StringSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(StringSet storage set, string memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(StringSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(StringSet storage set, uint256 index) internal view returns (string memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set) internal view returns (string[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n string[] memory result = new string[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n struct BytesSet {\n // Storage of set values\n bytes[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(BytesSet storage set, bytes memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(BytesSet storage set, bytes memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(BytesSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(BytesSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set) internal view returns (bytes[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes[] memory result = new bytes[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Strings.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SafeCast} from \"./math/SafeCast.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n using SafeCast for *;\n\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n uint8 private constant ADDRESS_LENGTH = 20;\n uint256 private constant SPECIAL_CHARS_LOOKUP =\n (1 << 0x08) | // backspace\n (1 << 0x09) | // tab\n (1 << 0x0a) | // newline\n (1 << 0x0c) | // form feed\n (1 << 0x0d) | // carriage return\n (1 << 0x22) | // double quote\n (1 << 0x5c); // backslash\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n /**\n * @dev The string being parsed contains characters that are not in scope of the given base.\n */\n error StringsInvalidChar();\n\n /**\n * @dev The string being parsed is not a properly formatted address.\n */\n error StringsInvalidAddressFormat();\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n assembly (\"memory-safe\") {\n ptr := add(add(buffer, 0x20), length)\n }\n while (true) {\n ptr--;\n assembly (\"memory-safe\") {\n mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toStringSigned(int256 value) internal pure returns (string memory) {\n return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n * representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal\n * representation, according to EIP-55.\n */\n function toChecksumHexString(address addr) internal pure returns (string memory) {\n bytes memory buffer = bytes(toHexString(addr));\n\n // hash the hex part of buffer (skip length + 2 bytes, length 40)\n uint256 hashValue;\n assembly (\"memory-safe\") {\n hashValue := shr(96, keccak256(add(buffer, 0x22), 40))\n }\n\n for (uint256 i = 41; i > 1; --i) {\n // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)\n if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {\n // case shift by xoring with 0x20\n buffer[i] ^= 0x20;\n }\n hashValue >>= 4;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `bytes` buffer to its ASCII `string` hexadecimal representation.\n */\n function toHexString(bytes memory input) internal pure returns (string memory) {\n unchecked {\n bytes memory buffer = new bytes(2 * input.length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 0; i < input.length; ++i) {\n uint8 v = uint8(input[i]);\n buffer[2 * i + 2] = HEX_DIGITS[v >> 4];\n buffer[2 * i + 3] = HEX_DIGITS[v & 0xf];\n }\n return string(buffer);\n }\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input) internal pure returns (uint256) {\n return parseUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n uint256 result = 0;\n for (uint256 i = begin; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 9) return (false, 0);\n result *= 10;\n result += chr;\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `int256`.\n *\n * Requirements:\n * - The string must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input) internal pure returns (int256) {\n return parseInt(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {\n (bool success, int256 value) = tryParseInt(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if\n * the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {\n return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);\n }\n\n uint256 private constant ABS_MIN_INT256 = 2 ** 255;\n\n /**\n * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character or if the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, int256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseIntUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseIntUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, int256 value) {\n bytes memory buffer = bytes(input);\n\n // Check presence of a negative sign.\n bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n bool positiveSign = sign == bytes1(\"+\");\n bool negativeSign = sign == bytes1(\"-\");\n uint256 offset = (positiveSign || negativeSign).toUint();\n\n (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);\n\n if (absSuccess && absValue < ABS_MIN_INT256) {\n return (true, negativeSign ? -int256(absValue) : int256(absValue));\n } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {\n return (true, type(int256).min);\n } else return (false, 0);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input) internal pure returns (uint256) {\n return parseHexUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseHexUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an\n * invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseHexUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseHexUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n // skip 0x prefix if present\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 offset = hasPrefix.toUint() * 2;\n\n uint256 result = 0;\n for (uint256 i = begin + offset; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 15) return (false, 0);\n result *= 16;\n unchecked {\n // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).\n // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.\n result += chr;\n }\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as an `address`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input) internal pure returns (address) {\n return parseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {\n (bool success, address value) = tryParseAddress(input, begin, end);\n if (!success) revert StringsInvalidAddressFormat();\n return value;\n }\n\n /**\n * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly\n * formatted address. See {parseAddress-string} requirements.\n */\n function tryParseAddress(string memory input) internal pure returns (bool success, address value) {\n return tryParseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly\n * formatted address. See {parseAddress-string-uint256-uint256} requirements.\n */\n function tryParseAddress(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, address value) {\n if (end > bytes(input).length || begin > end) return (false, address(0));\n\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 expectedLength = 40 + hasPrefix.toUint() * 2;\n\n // check that input is the correct length\n if (end - begin == expectedLength) {\n // length guarantees that this does not overflow, and value is at most type(uint160).max\n (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);\n return (s, address(uint160(v)));\n } else {\n return (false, address(0));\n }\n }\n\n function _tryParseChr(bytes1 chr) private pure returns (uint8) {\n uint8 value = uint8(chr);\n\n // Try to parse `chr`:\n // - Case 1: [0-9]\n // - Case 2: [a-f]\n // - Case 3: [A-F]\n // - otherwise not supported\n unchecked {\n if (value > 47 && value < 58) value -= 48;\n else if (value > 96 && value < 103) value -= 87;\n else if (value > 64 && value < 71) value -= 55;\n else return type(uint8).max;\n }\n\n return value;\n }\n\n /**\n * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.\n *\n * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.\n *\n * NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of\n * RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode\n * characters that are not in this range, but other tooling may provide different results.\n */\n function escapeJSON(string memory input) internal pure returns (string memory) {\n bytes memory buffer = bytes(input);\n bytes memory output = new bytes(2 * buffer.length); // worst case scenario\n uint256 outputLength = 0;\n\n for (uint256 i; i < buffer.length; ++i) {\n bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));\n if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {\n output[outputLength++] = \"\\\\\";\n if (char == 0x08) output[outputLength++] = \"b\";\n else if (char == 0x09) output[outputLength++] = \"t\";\n else if (char == 0x0a) output[outputLength++] = \"n\";\n else if (char == 0x0c) output[outputLength++] = \"f\";\n else if (char == 0x0d) output[outputLength++] = \"r\";\n else if (char == 0x5c) output[outputLength++] = \"\\\\\";\n else if (char == 0x22) {\n // solhint-disable-next-line quotes\n output[outputLength++] = '\"';\n }\n } else {\n output[outputLength++] = char;\n }\n }\n // write the actual length and deallocate unused memory\n assembly (\"memory-safe\") {\n mstore(output, outputLength)\n mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))\n }\n\n return string(output);\n }\n\n /**\n * @dev Reads a bytes32 from a bytes array without bounds checking.\n *\n * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the\n * assembly block as such would prevent some optimizations.\n */\n function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {\n // This is not memory safe in the general case, but all calls to this private function are within bounds.\n assembly (\"memory-safe\") {\n value := mload(add(add(buffer, 0x20), offset))\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n// Types\nimport { Execution } from \"../../common/interfaces/IERC7579Account.sol\";\n\n/**\n * Helper Library for decoding Execution calldata\n * malloc for memory allocation is bad for gas. use this assembly instead\n */\nlibrary ExecutionLib {\n error ERC7579DecodingError();\n\n /**\n * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.\n * @dev code is copied from solady's LibERC7579.sol\n * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146\n * Credits to Vectorized and the Solady Team\n */\n function decodeBatch(bytes calldata executionCalldata)\n internal\n pure\n returns (Execution[] calldata executionBatch)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let u := calldataload(executionCalldata.offset)\n let s := add(executionCalldata.offset, u)\n let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)\n executionBatch.offset := add(s, 0x20)\n executionBatch.length := calldataload(s)\n if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if executionBatch.length {\n // Perform bounds checks on the decoded `executionBatch`.\n // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.\n for { let i := executionBatch.length } 1 { } {\n i := sub(i, 1)\n let p := calldataload(add(executionBatch.offset, shl(5, i)))\n let c := add(executionBatch.offset, p)\n let q := calldataload(add(c, 0x40))\n let o := add(c, q)\n // forgefmt: disable-next-item\n if or(shr(64, or(calldataload(o), or(p, q))),\n or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if iszero(i) { break }\n }\n }\n }\n }\n\n function encodeBatch(Execution[] memory executions)\n internal\n pure\n returns (bytes memory callData)\n {\n callData = abi.encode(executions);\n }\n\n function decodeSingle(bytes calldata executionCalldata)\n internal\n pure\n returns (address target, uint256 value, bytes calldata callData)\n {\n target = address(bytes20(executionCalldata[0:20]));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n function encodeSingle(\n address target,\n uint256 value,\n bytes memory callData\n )\n internal\n pure\n returns (bytes memory userOpCalldata)\n {\n userOpCalldata = abi.encodePacked(target, value, callData);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Arrays.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n using SlotDerivation for bytes32;\n using StorageSlot for bytes32;\n\n /**\n * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n uint256[] memory array,\n function(uint256, uint256) pure returns (bool) comp\n ) internal pure returns (uint256[] memory) {\n _quickSort(_begin(array), _end(array), comp);\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n */\n function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n sort(array, Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of address (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n address[] memory array,\n function(address, address) pure returns (bool) comp\n ) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of address in increasing order.\n */\n function sort(address[] memory array) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n bytes32[] memory array,\n function(bytes32, bytes32) pure returns (bool) comp\n ) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n */\n function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n * at end (exclusive). Sorting follows the `comp` comparator.\n *\n * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n *\n * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n * be used only if the limits are within a memory array.\n */\n function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n unchecked {\n if (end - begin < 0x40) return;\n\n // Use first element as pivot\n uint256 pivot = _mload(begin);\n // Position where the pivot should be at the end of the loop\n uint256 pos = begin;\n\n for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n if (comp(_mload(it), pivot)) {\n // If the value stored at the iterator's position comes before the pivot, we increment the\n // position of the pivot and move the value there.\n pos += 0x20;\n _swap(pos, it);\n }\n }\n\n _swap(begin, pos); // Swap pivot into place\n _quickSort(begin, pos, comp); // Sort the left side of the pivot\n _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first element of `array`.\n */\n function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := add(array, 0x20)\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n * that comes just after the last element of the array.\n */\n function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n unchecked {\n return _begin(array) + array.length * 0x20;\n }\n }\n\n /**\n * @dev Load memory word (as a uint256) at location `ptr`.\n */\n function _mload(uint256 ptr) private pure returns (uint256 value) {\n assembly {\n value := mload(ptr)\n }\n }\n\n /**\n * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n */\n function _swap(uint256 ptr1, uint256 ptr2) private pure {\n assembly {\n let value1 := mload(ptr1)\n let value2 := mload(ptr2)\n mstore(ptr1, value2)\n mstore(ptr2, value1)\n }\n }\n\n /// @dev Helper: low level cast address memory array to uint256 memory array\n function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast address comp function to uint256 comp function\n function _castToUint256Comp(\n function(address, address) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n function _castToUint256Comp(\n function(bytes32, bytes32) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /**\n * @dev Searches a sorted `array` and returns the first index that contains\n * a value greater or equal to `element`. If no such index exists (i.e. all\n * values in the array are strictly less than `element`), the array length is\n * returned. Time complexity O(log n).\n *\n * NOTE: The `array` is expected to be sorted in ascending order, and to\n * contain no repeated elements.\n *\n * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n * support for repeated elements in the array. The {lowerBound} function should\n * be used instead.\n */\n function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n return low - 1;\n } else {\n return low;\n }\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value greater or equal than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n */\n function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value strictly greater than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n */\n function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {lowerBound}, but with an array in memory.\n */\n function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {upperBound}, but with an array in memory.\n */\n function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getAddressSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytes32Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getUint256Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytesSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getStringSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(address[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(string[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));\n }\n }\n\n /**\n * @dev Returns the largest of two signed numbers.\n */\n function max(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two signed numbers.\n */\n function min(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two signed numbers without overflow.\n * The result is rounded towards zero.\n */\n function average(int256 a, int256 b) internal pure returns (int256) {\n // Formula from the book \"Hacker's Delight\"\n int256 x = (a & b) + ((a ^ b) >> 1);\n return x + (int256(uint256(x) >> 255) & (a ^ b));\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // Formula from the \"Bit Twiddling Hacks\" by Sean Eron Anderson.\n // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,\n // taking advantage of the most significant (or \"sign\" bit) in two's complement representation.\n // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,\n // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).\n int256 mask = n >> 255;\n\n // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.\n return uint256((n + mask) ^ mask);\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n/* solhint-disable no-unused-import */\n\n// Types\nimport { CallType, ExecType, ModeCode } from \"../lib/ModeLib.sol\";\n\n// Structs\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\ninterface IERC7579Account {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by ERC-4337 EntryPoint.sol\n * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @dev Ensure adequate authorization control: i.e. onlyExecutorModule\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function executeFromExecutor(\n ModeCode mode,\n bytes calldata executionCalldata\n )\n external\n payable\n returns (bytes[] memory returnData);\n\n /**\n * @dev ERC-1271 isValidSignature\n * This function is intended to be used to validate a smart account signature\n * and may forward the call to a validator module\n *\n * @param hash The hash of the data that is signed\n * @param data The data that is signed\n */\n function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);\n\n /**\n * @dev installs a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be required on the module during `onInstall`\n * initialization.\n */\n function installModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata initData\n )\n external\n payable;\n\n /**\n * @dev uninstalls a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be required on the module during `onUninstall`\n * de-initialization.\n */\n function uninstallModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata deInitData\n )\n external\n payable;\n\n /**\n * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)\n * @param encodedMode the encoded mode\n */\n function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);\n\n /**\n * Function to check if the account supports installation of a certain module type Id\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n\n /**\n * Function to check if the account has a certain module installed\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * Note: keep in mind that some contracts can be multiple module types at the same time. It\n * thus may be necessary to query multiple module types\n * @param module the module address\n * @param additionalContext additional context data that the smart account may interpret to\n * identifiy conditions under which the module is installed.\n * usually this is not necessary, but for some special hooks that\n * are stored in mappings, this param might be needed\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n )\n external\n view\n returns (bool);\n\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n * the accountId should be structured like so:\n * \"vendorname.accountname.semver\"\n */\n function accountId() external view returns (string memory accountImplementationId);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Comparators.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n function lt(uint256 a, uint256 b) internal pure returns (bool) {\n return a < b;\n }\n\n function gt(uint256 a, uint256 b) internal pure returns (bool) {\n return a > b;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using StorageSlot for bytes32;\n * using SlotDerivation for bytes32;\n *\n * // Declare a namespace\n * string private constant _NAMESPACE = \"\"; // eg. OpenZeppelin.Slot\n *\n * function setValueInNamespace(uint256 key, address newValue) internal {\n * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n * }\n *\n * function getValueInNamespace(uint256 key) internal view returns (address) {\n * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n /**\n * @dev Derive an ERC-7201 slot from a string (namespace).\n */\n function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n assembly (\"memory-safe\") {\n mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n slot := and(keccak256(0x00, 0x20), not(0xff))\n }\n }\n\n /**\n * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n */\n function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n unchecked {\n return bytes32(uint256(slot) + pos);\n }\n }\n\n /**\n * @dev Derive the location of the first element in an array from the slot where the length is stored.\n */\n function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, slot)\n result := keccak256(0x00, 0x20)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, and(key, shr(96, not(0))))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, iszero(iszero(key)))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/lib/ModeLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title ModeLib\n * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat)\n * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode\n * encoding is used.\n * Function Signature of execute function:\n * function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and\n * context.\n * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that\n * implement\n * more complex execution modes may use the entire bytes32.\n *\n * |--------------------------------------------------------------------|\n * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload |\n * |--------------------------------------------------------------------|\n * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes |\n * |--------------------------------------------------------------------|\n *\n * CALLTYPE: 1 byte\n * CallType is used to determine how the executeCalldata paramter of the execute function has to be\n * decoded.\n * It can be either single, batch or delegatecall. In the future different calls could be added.\n * CALLTYPE can be used by a validation module to determine how to decode .\n *\n * EXECTYPE: 1 byte\n * ExecType is used to determine how the account should handle the execution.\n * It can indicate if the execution should revert on failure or continue execution.\n * In the future more execution modes may be added.\n * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in\n * a batch fails, the entire batch is reverted\n *\n * UNUSED: 4 bytes\n * Unused bytes are reserved for future use.\n *\n * ModeSelector: bytes4\n * The \"optional\" mode selector can be used by account vendors, to implement custom behavior in\n * their accounts.\n * the way a ModeSelector is to be calculated is bytes4(keccak256(\"vendorname.featurename\"))\n * this is to prevent collisions between different vendors, while allowing innovation and the\n * development of new features without coordination between ERC-7579 implementing accounts\n *\n * ModePayload: 22 bytes\n * Mode payload is used to pass additional data to the smart account execution, this may be\n * interpreted depending on the ModeSelector\n *\n * ExecutionCallData: n bytes\n * single, delegatecall or batch exec abi.encoded as bytes\n */\n\n// Custom type for improved developer experience\ntype ModeCode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ModeSelector is bytes4;\n\ntype ModePayload is bytes22;\n\n// Default CallType\nCallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n// Batched CallType\nCallType constant CALLTYPE_BATCH = CallType.wrap(0x01);\nCallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);\n// @dev Implementing delegatecall is OPTIONAL!\n// implement delegatecall with extreme care.\nCallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n// @dev default behavior is to revert on failure\n// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure\n// Since this is value 0x00, no additional encoding is required for simple accounts\nExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n// @dev account may elect to change execution behavior. For example \"try exec\" / \"allow fail\"\nExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\nModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));\n// Example declaration of a custom mode selector\nModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256(\"default.mode.offset\")));\n\n/**\n * @dev ModeLib is a helper library to encode/decode ModeCodes\n */\nlibrary ModeLib {\n function decode(ModeCode mode)\n internal\n pure\n returns (\n CallType _calltype,\n ExecType _execType,\n ModeSelector _modeSelector,\n ModePayload _modePayload\n )\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _calltype := mode\n _execType := shl(8, mode)\n _modeSelector := shl(48, mode)\n _modePayload := shl(80, mode)\n }\n }\n\n function encode(\n CallType callType,\n ExecType execType,\n ModeSelector mode,\n ModePayload payload\n )\n internal\n pure\n returns (ModeCode)\n {\n return ModeCode.wrap(\n bytes32(\n abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)\n )\n );\n }\n\n function encodeSimpleBatch() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function encodeSimpleSingle() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function getCallType(ModeCode mode) internal pure returns (CallType calltype) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n calltype := mode\n }\n }\n}\n\nusing { eqModeSelector as == } for ModeSelector global;\nusing { eqCallType as == } for CallType global;\nusing { neqCallType as != } for CallType global;\nusing { eqExecType as == } for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction neqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperVaultAggregator.standard-json-input.json b/script/locked-bytecode-dev/SuperVaultAggregator.standard-json-input.json new file mode 100644 index 000000000..9cef8fce2 --- /dev/null +++ b/script/locked-bytecode-dev/SuperVaultAggregator.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperVault/SuperVaultAggregator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { Clones } from \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { MerkleProof } from \"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol\";\n\n// Superform\nimport { SuperVault } from \"./SuperVault.sol\";\nimport { SuperVaultStrategy } from \"./SuperVaultStrategy.sol\";\nimport { ISuperVaultStrategy } from \"../interfaces/SuperVault/ISuperVaultStrategy.sol\";\nimport { SuperVaultEscrow } from \"./SuperVaultEscrow.sol\";\nimport { ISuperGovernor } from \"../interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"../interfaces/SuperVault/ISuperVaultAggregator.sol\";\n// Libraries\nimport { AssetMetadataLib } from \"../libraries/AssetMetadataLib.sol\";\n\n/// @title SuperVaultAggregator\n/// @author Superform Labs\n/// @notice Registry and PPS oracle for all SuperVaults\n/// @dev Creates new SuperVault trios and manages PPS updates\ncontract SuperVaultAggregator is ISuperVaultAggregator {\n using AssetMetadataLib for address;\n using Clones for address;\n using SafeERC20 for IERC20;\n using Math for uint256;\n using EnumerableSet for EnumerableSet.AddressSet;\n\n /*//////////////////////////////////////////////////////////////\n STORAGE\n //////////////////////////////////////////////////////////////*/\n // Vault implementation contracts\n address public immutable VAULT_IMPLEMENTATION;\n address public immutable STRATEGY_IMPLEMENTATION;\n address public immutable ESCROW_IMPLEMENTATION;\n\n // Governance\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n // Claimable upkeep\n uint256 public claimableUpkeep;\n\n // Strategy data storage\n mapping(address strategy => StrategyData) private _strategyData;\n\n // Upkeep balances (per strategy)\n mapping(address strategy => uint256 upkeep) private _strategyUpkeepBalance;\n\n // Two-step upkeep withdrawal system\n mapping(address strategy => UpkeepWithdrawalRequest) public pendingUpkeepWithdrawals;\n\n // Registry of created vaults\n EnumerableSet.AddressSet private _superVaults;\n EnumerableSet.AddressSet private _superVaultStrategies;\n EnumerableSet.AddressSet private _superVaultEscrows;\n\n // Constant for basis points precision (100% = 10,000 bps)\n uint256 private constant BPS_PRECISION = 10_000;\n\n // Maximum performance fee allowed (51%)\n uint256 private constant MAX_PERFORMANCE_FEE = 5100;\n\n // Maximum number of secondary managers per strategy to prevent governance DoS on manager replacement\n uint256 public constant MAX_SECONDARY_MANAGERS = 5;\n\n // Default deviation threshold for new strategies (50% in 1e18 scale)\n uint256 private constant DEFAULT_DEVIATION_THRESHOLD = 5e17;\n\n // Timelock for upkeep withdrawal (24 hours)\n uint256 public constant UPKEEP_WITHDRAWAL_TIMELOCK = 24 hours;\n\n // Timelock for manager changes and Merkle root updates\n uint256 private constant _MANAGER_CHANGE_TIMELOCK = 7 days;\n uint256 private _hooksRootUpdateTimelock = 15 minutes;\n\n // Timelock for parameter changes (3 days)\n uint256 private constant _PARAMETER_CHANGE_TIMELOCK = 3 days;\n\n // Global hooks Merkle root data\n bytes32 private _globalHooksRoot;\n bytes32 private _proposedGlobalHooksRoot;\n uint256 private _globalHooksRootEffectiveTime;\n bool private _globalHooksRootVetoed;\n\n // Nonce for vault creation tracking\n uint256 private _vaultCreationNonce;\n\n /*//////////////////////////////////////////////////////////////\n MODIFIERS\n //////////////////////////////////////////////////////////////*/\n /// @notice Validates that msg.sender is the active PPS Oracle\n modifier onlyPPSOracle() {\n _onlyPPSOracle();\n _;\n }\n\n function _onlyPPSOracle() internal view {\n if (!SUPER_GOVERNOR.isActivePPSOracle(msg.sender)) {\n revert UNAUTHORIZED_PPS_ORACLE();\n }\n }\n\n /// @notice Validates that a strategy exists (has been created by this aggregator)\n modifier validStrategy(address strategy) {\n _validStrategy(strategy);\n _;\n }\n\n function _validStrategy(address strategy) internal view {\n if (!_superVaultStrategies.contains(strategy)) revert UNKNOWN_STRATEGY();\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n /// @notice Initializes the SuperVaultAggregator\n /// @param superGovernor_ Address of the SuperGovernor contract\n /// @param vaultImpl_ Address of the pre-deployed SuperVault implementation\n /// @param strategyImpl_ Address of the pre-deployed SuperVaultStrategy implementation\n /// @param escrowImpl_ Address of the pre-deployed SuperVaultEscrow implementation\n constructor(address superGovernor_, address vaultImpl_, address strategyImpl_, address escrowImpl_) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n if (vaultImpl_ == address(0)) revert ZERO_ADDRESS();\n if (strategyImpl_ == address(0)) revert ZERO_ADDRESS();\n if (escrowImpl_ == address(0)) revert ZERO_ADDRESS();\n\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n VAULT_IMPLEMENTATION = vaultImpl_;\n STRATEGY_IMPLEMENTATION = strategyImpl_;\n ESCROW_IMPLEMENTATION = escrowImpl_;\n }\n\n /*//////////////////////////////////////////////////////////////\n VAULT CREATION\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultAggregator\n function createVault(VaultCreationParams calldata params)\n external\n returns (address superVault, address strategy, address escrow)\n {\n // Input validation\n if (params.asset == address(0) || params.mainManager == address(0) || params.feeConfig.recipient == address(0))\n {\n revert ZERO_ADDRESS();\n }\n\n /// @dev Check that name and symbol are not empty\n /// We don't check for anything else and\n /// it's up to the creator to ensure that the vault\n /// is created with valid parameters\n if (bytes(params.name).length == 0 || bytes(params.symbol).length == 0) {\n revert INVALID_VAULT_PARAMS();\n }\n\n // Initialize local variables struct to avoid stack too deep\n VaultCreationLocalVars memory vars;\n\n vars.currentNonce = _vaultCreationNonce++;\n vars.salt = keccak256(abi.encode(msg.sender, params.asset, params.name, params.symbol, vars.currentNonce));\n\n // Create minimal proxies\n superVault = VAULT_IMPLEMENTATION.cloneDeterministic(vars.salt);\n escrow = ESCROW_IMPLEMENTATION.cloneDeterministic(vars.salt);\n strategy = STRATEGY_IMPLEMENTATION.cloneDeterministic(vars.salt);\n\n // Initialize superVault\n SuperVault(superVault).initialize(params.asset, params.name, params.symbol, strategy, escrow);\n\n // Initialize escrow\n SuperVaultEscrow(escrow).initialize(superVault);\n\n // Initialize strategy\n SuperVaultStrategy(payable(strategy)).initialize(superVault, params.feeConfig);\n\n // Store vault trio in registry\n _superVaults.add(superVault);\n _superVaultStrategies.add(strategy);\n _superVaultEscrows.add(escrow);\n\n // Get asset decimals\n (bool success, uint8 assetDecimals) = params.asset.tryGetAssetDecimals();\n if (!success) revert INVALID_ASSET();\n // Initial PPS is always 1.0 (scaled by asset decimals) for new vaults\n // This means 1 vault share = 1 unit of underlying asset at inception\n vars.initialPPS = 10 ** assetDecimals;\n\n // Validate maxStaleness against minimum required staleness\n if (params.maxStaleness < SUPER_GOVERNOR.getMinStaleness()) {\n revert MAX_STALENESS_TOO_LOW();\n }\n\n // Validate minUpdateInterval against minimum required staleness\n if (params.minUpdateInterval >= params.maxStaleness) {\n revert INVALID_VAULT_PARAMS();\n }\n\n // Initialize StrategyData individually to avoid mapping assignment issues\n _strategyData[strategy].pps = vars.initialPPS;\n _strategyData[strategy].lastUpdateTimestamp = block.timestamp;\n _strategyData[strategy].minUpdateInterval = params.minUpdateInterval;\n _strategyData[strategy].maxStaleness = params.maxStaleness;\n _strategyData[strategy].isPaused = false;\n _strategyData[strategy].mainManager = params.mainManager;\n\n uint256 secondaryLen = params.secondaryManagers.length;\n if (secondaryLen > MAX_SECONDARY_MANAGERS) revert TOO_MANY_SECONDARY_MANAGERS();\n\n for (uint256 i; i < secondaryLen; ++i) {\n address _secondaryManager = params.secondaryManagers[i];\n\n // Check if manager is a zero address\n if (_secondaryManager == address(0)) revert ZERO_ADDRESS();\n\n // Check if manager is already the primary manager\n if (_strategyData[strategy].mainManager == _secondaryManager) revert SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n\n // Add secondary manager and revert if it already exists\n if (!_strategyData[strategy].secondaryManagers.add(_secondaryManager)) {\n revert MANAGER_ALREADY_EXISTS();\n }\n }\n\n _strategyData[strategy].deviationThreshold = DEFAULT_DEVIATION_THRESHOLD;\n\n emit VaultDeployed(superVault, strategy, escrow, params.asset, params.name, params.symbol, vars.currentNonce);\n emit PPSUpdated(strategy, vars.initialPPS, _strategyData[strategy].lastUpdateTimestamp);\n\n return (superVault, strategy, escrow);\n }\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultAggregator\n function forwardPPS(ForwardPPSArgs calldata args) external onlyPPSOracle {\n bool paymentsEnabled = SUPER_GOVERNOR.isUpkeepPaymentsEnabled();\n\n uint256 strategiesLength = args.strategies.length;\n for (uint256 i; i < strategiesLength; ++i) {\n address strategy = args.strategies[i];\n\n // Skip invalid strategy\n if (!_superVaultStrategies.contains(strategy)) {\n emit UnknownStrategy(strategy);\n continue;\n }\n\n // Skip invalid timestamp\n uint256 ts = args.timestamps[i];\n\n // [Property 4: Future Timestamp Rejection]\n // Reject updates with timestamps in the future. This prevents validators from\n // creating signatures with future timestamps that could be used later.\n if (ts > block.timestamp) {\n emit ProvidedTimestampExceedsBlockTimestamp(strategy, ts, block.timestamp);\n continue;\n }\n\n StrategyData storage data = _strategyData[strategy];\n\n // [Property 5: Pause Rejection]\n // Always skip paused strategies, regardless of payment settings.\n // Paused strategies should not accept any PPS updates until explicitly unpaused.\n // This check happens early to avoid unnecessary processing and gas costs.\n if (data.isPaused) {\n emit PPSUpdateRejectedStrategyPaused(strategy);\n continue; // Skip processing paused strategies\n }\n\n // [Property 6: Staleness Enforcement (Absolute Time)]\n // Always enforce staleness check, regardless of payment status.\n // This prevents attackers from submitting stale signatures to manipulate PPS.\n // The check must occur before payment calculation to protect all strategies.\n if (block.timestamp - ts > data.maxStaleness) {\n emit StaleUpdate(strategy, args.updateAuthority, ts);\n continue; // Skip processing stale updates\n }\n\n uint256 upkeepCost = 0;\n if (paymentsEnabled) {\n // Query cost directly per entry\n // Everyone pays the upkeep cost\n try SUPER_GOVERNOR.getUpkeepCostPerSingleUpdate(msg.sender) returns (uint256 cost) {\n upkeepCost = cost;\n } catch {\n // If upkeep cost computation fails (e.g., oracle misconfiguration),\n // allow PPS update to proceed without charging upkeep.\n upkeepCost = 0;\n }\n }\n\n _forwardPPS(\n PPSUpdateData({\n strategy: strategy,\n // isExempt when upkeepCost is 0 (covers both paymentsDisabled and oracle failures)\n isExempt: upkeepCost == 0,\n pps: args.ppss[i],\n timestamp: ts,\n upkeepCost: upkeepCost\n })\n );\n }\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function updatePPSAfterSkim(uint256 newPPS, uint256 feeAmount) external validStrategy(msg.sender) {\n // msg.sender must be a registered strategy (validated by modifier)\n address strategy = msg.sender;\n\n StrategyData storage data = _strategyData[strategy];\n // Disallow PPS updates after skim when strategy is paused or PPS is stale\n if (data.isPaused) revert STRATEGY_PAUSED();\n if (data.ppsStale) revert PPS_STALE();\n uint256 oldPPS = data.pps;\n\n // VALIDATION 1: PPS must decrease after fee skim\n if (newPPS >= oldPPS) revert PPS_MUST_DECREASE_AFTER_SKIM();\n\n // VALIDATION 2: PPS must be positive\n if (newPPS == 0) revert INVALID_ASSET();\n\n // VALIDATION 3: Range check - deduction must be within max fee bounds\n // Use MAX_PERFORMANCE_FEE to avoid external call to strategy\n // Max possible PPS after skim: oldPPS * (1 - MAX_PERFORMANCE_FEE)\n // Use Ceil rounding to ensure strict enforcement of MAX_PERFORMANCE_FEE (51%) limit\n uint256 minAllowedPPS = oldPPS.mulDiv(BPS_PRECISION - MAX_PERFORMANCE_FEE, BPS_PRECISION, Math.Rounding.Ceil);\n\n if (newPPS < minAllowedPPS) revert PPS_DEDUCTION_TOO_LARGE();\n\n // VALIDATION 4: Fee amount must be non-zero when PPS decreases\n // This ensures consistent reporting between PPS change and claimed fee amount\n if (feeAmount == 0) revert INVALID_ASSET();\n\n // UPDATE: Store new PPS\n data.pps = newPPS;\n\n // UPDATE TIMESTAMP\n // Update timestamp to reflect when this PPS change occurred\n // NOTE: This may interact with oracle submissions - to be discussed\n data.lastUpdateTimestamp = block.timestamp;\n\n // NOTE: We do NOT reset ppsStale flag here\n // The skim function can only be called if _validateStrategyState doesn't revert\n // So if we reach here, the strategy state is valid\n\n emit PPSUpdatedAfterSkim(strategy, oldPPS, newPPS, feeAmount, block.timestamp);\n }\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultAggregator\n function depositUpkeep(address strategy, uint256 amount) external validStrategy(strategy) {\n if (amount == 0) revert ZERO_AMOUNT();\n\n // Get the UPKEEP_TOKEN address from SUPER_GOVERNOR\n address upkeepToken = SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.UPKEEP_TOKEN());\n\n // Transfer UPKEEP_TOKEN from msg.sender to this contract\n IERC20(upkeepToken).safeTransferFrom(msg.sender, address(this), amount);\n\n // Update upkeep balance for this strategy\n _strategyUpkeepBalance[strategy] += amount;\n\n emit UpkeepDeposited(strategy, msg.sender, amount);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function claimUpkeep(uint256 amount) external {\n // Only SUPER_GOVERNOR can claim upkeep\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert CALLER_NOT_AUTHORIZED();\n }\n\n if (claimableUpkeep < amount) revert INSUFFICIENT_UPKEEP();\n claimableUpkeep -= amount;\n\n // Get the UPKEEP_TOKEN address from SUPER_GOVERNOR\n address upkeepToken = SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.UPKEEP_TOKEN());\n\n // Transfer UPKEEP_TOKEN to `SuperBank`\n address _superBank = _getSuperBank();\n IERC20(upkeepToken).safeTransfer(_superBank, amount);\n emit UpkeepClaimed(_superBank, amount);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function proposeWithdrawUpkeep(address strategy) external validStrategy(strategy) {\n // Only mainManager can propose upkeep withdrawal from a strategy\n if (msg.sender != _strategyData[strategy].mainManager) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Get current strategy upkeep balance (full balance withdrawal)\n uint256 currentBalance = _strategyUpkeepBalance[strategy];\n if (currentBalance == 0) revert ZERO_AMOUNT();\n\n // Create withdrawal request\n pendingUpkeepWithdrawals[strategy] = UpkeepWithdrawalRequest({\n amount: currentBalance, effectiveTime: block.timestamp + UPKEEP_WITHDRAWAL_TIMELOCK\n });\n\n emit UpkeepWithdrawalProposed(\n strategy, msg.sender, currentBalance, block.timestamp + UPKEEP_WITHDRAWAL_TIMELOCK\n );\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function executeWithdrawUpkeep(address strategy) external validStrategy(strategy) {\n UpkeepWithdrawalRequest memory request = pendingUpkeepWithdrawals[strategy];\n\n // Check that a request exists\n if (request.effectiveTime == 0) revert UPKEEP_WITHDRAWAL_NOT_FOUND();\n\n // Check that timelock has passed\n if (block.timestamp < request.effectiveTime) revert UPKEEP_WITHDRAWAL_NOT_READY();\n\n // Calculate actual withdrawal amount (use current balance, may be less if upkeep was spent)\n uint256 currentBalance = _strategyUpkeepBalance[strategy];\n uint256 withdrawalAmount = currentBalance < request.amount ? currentBalance : request.amount;\n\n if (withdrawalAmount == 0) revert ZERO_AMOUNT();\n\n // Clear the pending request\n delete pendingUpkeepWithdrawals[strategy];\n\n // Get the UPKEEP_TOKEN address from SUPER_GOVERNOR\n address upkeepToken = SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.UPKEEP_TOKEN());\n\n // Update upkeep balance\n unchecked {\n _strategyUpkeepBalance[strategy] -= withdrawalAmount;\n }\n\n // Transfer UPKEEP_TOKEN to the original main manager (not msg.sender)\n address mainManager = _strategyData[strategy].mainManager;\n IERC20(upkeepToken).safeTransfer(mainManager, withdrawalAmount);\n\n emit UpkeepWithdrawn(strategy, mainManager, withdrawalAmount);\n }\n\n /*//////////////////////////////////////////////////////////////\n PAUSE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Manually pauses a strategy\n /// @param strategy Address of the strategy to pause\n /// @dev Only the main or secondary manager of the strategy can pause it\n function pauseStrategy(address strategy) external validStrategy(strategy) {\n // Either primary or secondary manager can pause\n if (!isAnyManager(msg.sender, strategy)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Check if strategy is already paused\n if (_strategyData[strategy].isPaused) {\n revert STRATEGY_ALREADY_PAUSED();\n }\n\n // Pause the strategy\n _strategyData[strategy].isPaused = true;\n _strategyData[strategy].ppsStale = true;\n emit StrategyPaused(strategy);\n }\n\n /// @notice Manually unpauses a strategy\n /// @param strategy Address of the strategy to unpause\n /// @dev unpausing marks PPS stale until a fresh oracle update\n function unpauseStrategy(address strategy) external validStrategy(strategy) {\n if (!isAnyManager(msg.sender, strategy)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Check if strategy is currently paused\n if (!_strategyData[strategy].isPaused) {\n revert STRATEGY_NOT_PAUSED();\n }\n\n // Unpause the strategy and track unpause timestamp\n _strategyData[strategy].isPaused = false;\n _strategyData[strategy].lastUnpauseTimestamp = block.timestamp; // Track for skim timelock\n // ppsStale already true from pause - no need to set again (gas savings)\n emit StrategyUnpaused(strategy);\n }\n\n /*//////////////////////////////////////////////////////////////\n MANAGER MANAGEMENT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultAggregator\n function addSecondaryManager(address strategy, address manager) external validStrategy(strategy) {\n // Only the primary manager can add secondary managers\n if (msg.sender != _strategyData[strategy].mainManager) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n if (manager == address(0)) revert ZERO_ADDRESS();\n\n // Check if manager is already the primary manager\n if (_strategyData[strategy].mainManager == manager) revert SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n\n // Enforce a cap on secondary managers to prevent governance DoS on changePrimaryManager\n if (_strategyData[strategy].secondaryManagers.length() >= MAX_SECONDARY_MANAGERS) {\n revert TOO_MANY_SECONDARY_MANAGERS();\n }\n\n // Add as secondary manager using EnumerableSet\n if (!_strategyData[strategy].secondaryManagers.add(manager)) revert MANAGER_ALREADY_EXISTS();\n\n emit SecondaryManagerAdded(strategy, manager);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function removeSecondaryManager(address strategy, address manager) external validStrategy(strategy) {\n // Only the primary manager can remove secondary managers\n if (msg.sender != _strategyData[strategy].mainManager) revert UNAUTHORIZED_UPDATE_AUTHORITY();\n\n // Remove the manager using EnumerableSet\n if (!_strategyData[strategy].secondaryManagers.remove(manager)) revert MANAGER_NOT_FOUND();\n\n emit SecondaryManagerRemoved(strategy, manager);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function updateDeviationThreshold(address strategy, uint256 deviationThreshold_) external validStrategy(strategy) {\n // Since this is a risky call, we only allow main managers as callers\n if (msg.sender != _strategyData[strategy].mainManager) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Update the threshold\n _strategyData[strategy].deviationThreshold = deviationThreshold_;\n\n // Emit the event\n emit DeviationThresholdUpdated(strategy, deviationThreshold_);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function changeGlobalLeavesStatus(\n bytes32[] memory leaves,\n bool[] memory statuses,\n address strategy\n )\n external\n validStrategy(strategy)\n {\n // Only the primary manager can change global leaves status\n if (msg.sender != _strategyData[strategy].mainManager) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n uint256 leavesLen = leaves.length;\n // Check array lengths match\n if (leavesLen != statuses.length) {\n revert MISMATCHED_ARRAY_LENGTHS();\n }\n\n // Update banned status for each leaf\n for (uint256 i; i < leavesLen; i++) {\n _strategyData[strategy].bannedLeaves[leaves[i]] = statuses[i];\n }\n\n // Emit event\n emit GlobalLeavesStatusChanged(strategy, leaves, statuses);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n /// @dev SECURITY: This is the emergency governance override function\n /// @dev Clears ALL pending proposals and secondary managers to prevent malicious manager attacks:\n /// - Pending manager change proposals\n /// - Pending hooks root proposals\n /// - Pending minUpdateInterval proposals\n /// - ALL secondary managers (they may be controlled by malicious manager)\n /// @dev This ensures clean slate for new manager without inherited vulnerabilities\n /// @dev This function is only callable by SUPER_GOVERNOR\n function changePrimaryManager(\n address strategy,\n address newManager,\n address feeRecipient\n )\n external\n validStrategy(strategy)\n {\n // Only SuperGovernor can call this\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n if (newManager == address(0) || feeRecipient == address(0)) revert ZERO_ADDRESS();\n\n // Check if new manager is already the primary manager to prevent malicious feeRecipient update\n if (newManager == _strategyData[strategy].mainManager) revert MANAGER_ALREADY_EXISTS();\n\n address oldManager = _strategyData[strategy].mainManager;\n\n // SECURITY: Clear any pending manager proposals to prevent malicious re-takeover\n _strategyData[strategy].proposedManager = address(0);\n _strategyData[strategy].managerChangeEffectiveTime = 0;\n\n // SECURITY: Clear any pending fee recipient proposals to prevent malicious change\n _strategyData[strategy].proposedFeeRecipient = address(0);\n\n // SECURITY: Clear any pending hooks root proposals to prevent malicious hook updates\n _strategyData[strategy].proposedHooksRoot = bytes32(0);\n _strategyData[strategy].hooksRootEffectiveTime = 0;\n\n // SECURITY: Clear any pending minUpdateInterval proposals\n _strategyData[strategy].proposedMinUpdateInterval = 0;\n _strategyData[strategy].minUpdateIntervalEffectiveTime = 0;\n\n // SECURITY: Clear all secondary managers as they may be controlled by malicious manager\n // Get all secondary managers first to emit proper events\n address[] memory clearedSecondaryManagers = _strategyData[strategy].secondaryManagers.values();\n\n // Clear the entire secondary managers set\n for (uint256 i = 0; i < clearedSecondaryManagers.length; i++) {\n _strategyData[strategy].secondaryManagers.remove(clearedSecondaryManagers[i]);\n emit SecondaryManagerRemoved(strategy, clearedSecondaryManagers[i]);\n }\n\n // SECURITY: Cancel any pending upkeep withdrawal to prevent old manager from withdrawing\n if (pendingUpkeepWithdrawals[strategy].effectiveTime != 0) {\n delete pendingUpkeepWithdrawals[strategy];\n emit UpkeepWithdrawalCancelled(strategy);\n }\n\n // Set the new primary manager\n _strategyData[strategy].mainManager = newManager;\n\n // Set the new fee recipient\n ISuperVaultStrategy(strategy).changeFeeRecipient(feeRecipient);\n\n emit PrimaryManagerChanged(strategy, oldManager, newManager, feeRecipient);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function proposeChangePrimaryManager(\n address strategy,\n address newManager,\n address feeRecipient\n )\n external\n validStrategy(strategy)\n {\n // Only secondary managers can propose changes to the primary manager\n if (!_strategyData[strategy].secondaryManagers.contains(msg.sender)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n if (newManager == address(0) || feeRecipient == address(0)) revert ZERO_ADDRESS();\n\n // Check if new manager is already the primary manager to prevent malicious feeRecipient update\n if (newManager == _strategyData[strategy].mainManager) revert MANAGER_ALREADY_EXISTS();\n\n // Set up the proposal with 7-day timelock\n uint256 effectiveTime = block.timestamp + _MANAGER_CHANGE_TIMELOCK;\n\n // Store proposal in the strategy data\n _strategyData[strategy].proposedManager = newManager;\n _strategyData[strategy].proposedFeeRecipient = feeRecipient;\n _strategyData[strategy].managerChangeEffectiveTime = effectiveTime;\n\n emit PrimaryManagerChangeProposed(strategy, msg.sender, newManager, feeRecipient, effectiveTime);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function cancelChangePrimaryManager(address strategy) external validStrategy(strategy) {\n // Only the current main manager can cancel the proposal\n if (_strategyData[strategy].mainManager != msg.sender) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Check if there is a pending proposal\n if (_strategyData[strategy].proposedManager == address(0)) {\n revert NO_PENDING_MANAGER_CHANGE();\n }\n\n address cancelledManager = _strategyData[strategy].proposedManager;\n\n // Clear the proposal\n _strategyData[strategy].proposedManager = address(0);\n _strategyData[strategy].proposedFeeRecipient = address(0);\n _strategyData[strategy].managerChangeEffectiveTime = 0;\n\n emit PrimaryManagerChangeCancelled(strategy, cancelledManager);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function executeChangePrimaryManager(address strategy) external validStrategy(strategy) {\n // Check if there is a pending proposal\n if (_strategyData[strategy].proposedManager == address(0)) revert NO_PENDING_MANAGER_CHANGE();\n\n // Check if the timelock period has passed\n if (block.timestamp < _strategyData[strategy].managerChangeEffectiveTime) revert TIMELOCK_NOT_EXPIRED();\n\n address newManager = _strategyData[strategy].proposedManager;\n address feeRecipient = _strategyData[strategy].proposedFeeRecipient;\n\n // Validate proposed values are not zero addresses (defense in depth)\n if (newManager == address(0) || feeRecipient == address(0)) revert ZERO_ADDRESS();\n\n address oldManager = _strategyData[strategy].mainManager;\n\n // If new manager is already a secondary manager, remove them\n _strategyData[strategy].secondaryManagers.remove(newManager);\n\n // SECURITY: Clear all secondary managers to prevent privilege retntion\n _strategyData[strategy].secondaryManagers.clear();\n\n // Cancel any pending upkeep withdrawal to ensure clean transition\n if (pendingUpkeepWithdrawals[strategy].effectiveTime != 0) {\n delete pendingUpkeepWithdrawals[strategy];\n emit UpkeepWithdrawalCancelled(strategy);\n }\n\n _strategyData[strategy].proposedHooksRoot = bytes32(0);\n _strategyData[strategy].hooksRootEffectiveTime = 0;\n _strategyData[strategy].proposedMinUpdateInterval = 0;\n _strategyData[strategy].minUpdateIntervalEffectiveTime = 0;\n\n // Set the new primary manager\n _strategyData[strategy].mainManager = newManager;\n\n // Set the new fee recipient\n ISuperVaultStrategy(strategy).changeFeeRecipient(feeRecipient);\n\n // Clear the proposal\n _strategyData[strategy].proposedManager = address(0);\n _strategyData[strategy].proposedFeeRecipient = address(0);\n _strategyData[strategy].managerChangeEffectiveTime = 0;\n\n emit PrimaryManagerChanged(strategy, oldManager, newManager, feeRecipient);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n /// @dev SECURITY: This function is intended to be used by governance to onboard a new manager without penalizing\n /// them for the previous manager's performance.\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev Calling this function resets the HWM to the current PPS, allowing a newly appointed manager to start from a\n /// neutral baseline. @dev This function is only callable by SUPER_GOVERNOR\n function resetHighWaterMark(address strategy) external validStrategy(strategy) {\n // Only SuperGovernor can call this\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n uint256 newHwmPps = _strategyData[strategy].pps;\n\n // Reset the High Water Mark to the current PPS\n ISuperVaultStrategy(strategy).resetHighWaterMark(newHwmPps);\n\n emit HighWaterMarkReset(strategy, newHwmPps);\n }\n\n /*//////////////////////////////////////////////////////////////\n HOOK VALIDATION FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultAggregator\n function setHooksRootUpdateTimelock(uint256 newTimelock) external {\n // Only SUPER_GOVERNOR can update the timelock\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Update the timelock\n _hooksRootUpdateTimelock = newTimelock;\n\n emit HooksRootUpdateTimelockChanged(newTimelock);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function proposeGlobalHooksRoot(bytes32 newRoot) external {\n // Only SUPER_GOVERNOR can update the global hooks root\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Set new root with timelock\n _proposedGlobalHooksRoot = newRoot;\n uint256 effectiveTime = block.timestamp + _hooksRootUpdateTimelock;\n _globalHooksRootEffectiveTime = effectiveTime;\n\n emit GlobalHooksRootUpdateProposed(newRoot, effectiveTime);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function executeGlobalHooksRootUpdate() external {\n bytes32 proposedRoot = _proposedGlobalHooksRoot;\n // Ensure there is a pending proposal\n if (proposedRoot == bytes32(0)) {\n revert NO_PENDING_GLOBAL_ROOT_CHANGE();\n }\n\n // Check if timelock period has elapsed\n if (block.timestamp < _globalHooksRootEffectiveTime) {\n revert ROOT_UPDATE_NOT_READY();\n }\n\n // Update the global hooks root\n bytes32 oldRoot = _globalHooksRoot;\n _globalHooksRoot = proposedRoot;\n _globalHooksRootEffectiveTime = 0;\n _proposedGlobalHooksRoot = bytes32(0);\n\n emit GlobalHooksRootUpdated(oldRoot, proposedRoot);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function setGlobalHooksRootVetoStatus(bool vetoed) external {\n // Only SuperGovernor can call this\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Don't emit event if status doesn't change\n if (_globalHooksRootVetoed == vetoed) {\n return;\n }\n\n // Update veto status\n _globalHooksRootVetoed = vetoed;\n\n emit GlobalHooksRootVetoStatusChanged(vetoed, _globalHooksRoot);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function proposeStrategyHooksRoot(address strategy, bytes32 newRoot) external validStrategy(strategy) {\n // Only the main manager can propose strategy-specific hooks root\n if (_strategyData[strategy].mainManager != msg.sender) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Set proposed root with timelock\n _strategyData[strategy].proposedHooksRoot = newRoot;\n uint256 effectiveTime = block.timestamp + _hooksRootUpdateTimelock;\n _strategyData[strategy].hooksRootEffectiveTime = effectiveTime;\n\n emit StrategyHooksRootUpdateProposed(strategy, msg.sender, newRoot, effectiveTime);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function executeStrategyHooksRootUpdate(address strategy) external validStrategy(strategy) {\n bytes32 proposedRoot = _strategyData[strategy].proposedHooksRoot;\n // Ensure there is a pending proposal\n if (proposedRoot == bytes32(0)) {\n revert NO_PENDING_MANAGER_CHANGE(); // Reusing error for simplicity\n }\n\n // Check if timelock period has elapsed\n if (block.timestamp < _strategyData[strategy].hooksRootEffectiveTime) {\n revert ROOT_UPDATE_NOT_READY();\n }\n\n // Update the strategy's hooks root\n bytes32 oldRoot = _strategyData[strategy].managerHooksRoot;\n _strategyData[strategy].managerHooksRoot = proposedRoot;\n\n // Reset proposal state\n _strategyData[strategy].proposedHooksRoot = bytes32(0);\n _strategyData[strategy].hooksRootEffectiveTime = 0;\n\n emit StrategyHooksRootUpdated(strategy, oldRoot, proposedRoot);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external validStrategy(strategy) {\n // Only SuperGovernor can call this\n if (msg.sender != address(SUPER_GOVERNOR)) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Don't emit event if status doesn't change\n if (_strategyData[strategy].hooksRootVetoed == vetoed) {\n return;\n }\n\n // Update veto status\n _strategyData[strategy].hooksRootVetoed = vetoed;\n\n emit StrategyHooksRootVetoStatusChanged(strategy, vetoed, _strategyData[strategy].managerHooksRoot);\n }\n\n /*//////////////////////////////////////////////////////////////\n MIN UPDATE INTERVAL MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultAggregator\n function proposeMinUpdateIntervalChange(\n address strategy,\n uint256 newMinUpdateInterval\n )\n external\n validStrategy(strategy)\n {\n // Only the main manager can propose changes\n if (_strategyData[strategy].mainManager != msg.sender) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Validate: newMinUpdateInterval must be less than maxStaleness\n // This ensures updates can occur before data becomes stale\n if (newMinUpdateInterval >= _strategyData[strategy].maxStaleness) {\n revert MIN_UPDATE_INTERVAL_TOO_HIGH();\n }\n\n // Set proposed interval with timelock\n uint256 effectiveTime = block.timestamp + _PARAMETER_CHANGE_TIMELOCK;\n _strategyData[strategy].proposedMinUpdateInterval = newMinUpdateInterval;\n _strategyData[strategy].minUpdateIntervalEffectiveTime = effectiveTime;\n\n emit MinUpdateIntervalChangeProposed(strategy, msg.sender, newMinUpdateInterval, effectiveTime);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function executeMinUpdateIntervalChange(address strategy) external validStrategy(strategy) {\n // Check if there is a pending proposal\n if (_strategyData[strategy].minUpdateIntervalEffectiveTime == 0) {\n revert NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n }\n\n // Check if the timelock period has passed\n if (block.timestamp < _strategyData[strategy].minUpdateIntervalEffectiveTime) {\n revert TIMELOCK_NOT_EXPIRED();\n }\n\n uint256 newInterval = _strategyData[strategy].proposedMinUpdateInterval;\n uint256 oldInterval = _strategyData[strategy].minUpdateInterval;\n\n // Clear the proposal first\n _strategyData[strategy].proposedMinUpdateInterval = 0;\n _strategyData[strategy].minUpdateIntervalEffectiveTime = 0;\n\n // Update the minUpdateInterval\n _strategyData[strategy].minUpdateInterval = newInterval;\n\n emit MinUpdateIntervalChanged(strategy, oldInterval, newInterval);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function cancelMinUpdateIntervalChange(address strategy) external validStrategy(strategy) {\n // Only the main manager can cancel\n if (_strategyData[strategy].mainManager != msg.sender) {\n revert UNAUTHORIZED_UPDATE_AUTHORITY();\n }\n\n // Check if there is a pending proposal\n if (_strategyData[strategy].minUpdateIntervalEffectiveTime == 0) {\n revert NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n }\n\n uint256 cancelledInterval = _strategyData[strategy].proposedMinUpdateInterval;\n\n // Clear the proposal\n _strategyData[strategy].proposedMinUpdateInterval = 0;\n _strategyData[strategy].minUpdateIntervalEffectiveTime = 0;\n\n emit MinUpdateIntervalChangeCancelled(strategy, cancelledInterval);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getProposedMinUpdateInterval(address strategy)\n external\n view\n returns (uint256 proposedInterval, uint256 effectiveTime)\n {\n return (\n _strategyData[strategy].proposedMinUpdateInterval, _strategyData[strategy].minUpdateIntervalEffectiveTime\n );\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isGlobalHooksRootVetoed() external view returns (bool vetoed) {\n return _globalHooksRootVetoed;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isStrategyHooksRootVetoed(address strategy) external view returns (bool vetoed) {\n return _strategyData[strategy].hooksRootVetoed;\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultAggregator\n function getSuperVaultsCount() external view returns (uint256) {\n return _superVaults.length();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getSuperVaultStrategiesCount() external view returns (uint256) {\n return _superVaultStrategies.length();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getSuperVaultEscrowsCount() external view returns (uint256) {\n return _superVaultEscrows.length();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getCurrentNonce() external view returns (uint256) {\n return _vaultCreationNonce;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getHooksRootUpdateTimelock() external view returns (uint256) {\n return _hooksRootUpdateTimelock;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getPPS(address strategy) external view validStrategy(strategy) returns (uint256 pps) {\n return _strategyData[strategy].pps;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getLastUpdateTimestamp(address strategy) external view returns (uint256 timestamp) {\n return _strategyData[strategy].lastUpdateTimestamp;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getMinUpdateInterval(address strategy) external view returns (uint256 interval) {\n return _strategyData[strategy].minUpdateInterval;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getMaxStaleness(address strategy) external view returns (uint256 staleness) {\n return _strategyData[strategy].maxStaleness;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getDeviationThreshold(address strategy)\n external\n view\n validStrategy(strategy)\n returns (uint256 deviationThreshold)\n {\n return _strategyData[strategy].deviationThreshold;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isStrategyPaused(address strategy) external view returns (bool isPaused) {\n return _strategyData[strategy].isPaused;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isPPSStale(address strategy) external view returns (bool isStale) {\n return _strategyData[strategy].ppsStale;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getLastUnpauseTimestamp(address strategy) external view returns (uint256 timestamp) {\n return _strategyData[strategy].lastUnpauseTimestamp;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getUpkeepBalance(address strategy) external view returns (uint256 balance) {\n return _strategyUpkeepBalance[strategy];\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getMainManager(address strategy) external view returns (address manager) {\n return _strategyData[strategy].mainManager;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getPendingManagerChange(address strategy)\n external\n view\n returns (address proposedManager, uint256 effectiveTime)\n {\n return (_strategyData[strategy].proposedManager, _strategyData[strategy].managerChangeEffectiveTime);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isMainManager(address manager, address strategy) public view returns (bool) {\n return _strategyData[strategy].mainManager == manager;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getSecondaryManagers(address strategy) external view returns (address[] memory) {\n return _strategyData[strategy].secondaryManagers.values();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isSecondaryManager(address manager, address strategy) external view returns (bool) {\n return _strategyData[strategy].secondaryManagers.contains(manager);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function isAnyManager(address manager, address strategy) public view returns (bool) {\n // Single storage pointer read instead of multiple\n StrategyData storage data = _strategyData[strategy];\n return (data.mainManager == manager) || data.secondaryManagers.contains(manager);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getAllSuperVaults() external view returns (address[] memory) {\n return _superVaults.values();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function superVaults(uint256 index) external view returns (address) {\n if (index >= _superVaults.length()) revert INDEX_OUT_OF_BOUNDS();\n return _superVaults.at(index);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getAllSuperVaultStrategies() external view returns (address[] memory) {\n return _superVaultStrategies.values();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function superVaultStrategies(uint256 index) external view returns (address) {\n if (index >= _superVaultStrategies.length()) revert INDEX_OUT_OF_BOUNDS();\n return _superVaultStrategies.at(index);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getAllSuperVaultEscrows() external view returns (address[] memory) {\n return _superVaultEscrows.values();\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function superVaultEscrows(uint256 index) external view returns (address) {\n if (index >= _superVaultEscrows.length()) revert INDEX_OUT_OF_BOUNDS();\n return _superVaultEscrows.at(index);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function validateHook(address strategy, ValidateHookArgs calldata args) external view returns (bool isValid) {\n // Cache all state variables in struct\n HookValidationCache memory cache = HookValidationCache({\n globalHooksRootVetoed: _globalHooksRootVetoed,\n globalHooksRoot: _globalHooksRoot,\n strategyHooksRootVetoed: _strategyData[strategy].hooksRootVetoed,\n strategyRoot: _strategyData[strategy].managerHooksRoot\n });\n\n // Early return false if either global or strategy hooks root is vetoed\n if (cache.globalHooksRootVetoed || cache.strategyHooksRootVetoed) {\n return false;\n }\n\n // Try to validate against global root first\n if (_validateSingleHook(args.hookAddress, args.hookArgs, args.globalProof, true, cache, strategy)) {\n return true;\n }\n\n // If global validation fails, try strategy root\n return _validateSingleHook(args.hookAddress, args.hookArgs, args.strategyProof, false, cache, strategy);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function validateHooks(\n address strategy,\n ValidateHookArgs[] calldata argsArray\n )\n external\n view\n returns (bool[] memory validHooks)\n {\n uint256 length = argsArray.length;\n\n // Cache all state variables in struct\n HookValidationCache memory cache = HookValidationCache({\n globalHooksRootVetoed: _globalHooksRootVetoed,\n globalHooksRoot: _globalHooksRoot,\n strategyHooksRootVetoed: _strategyData[strategy].hooksRootVetoed,\n strategyRoot: _strategyData[strategy].managerHooksRoot\n });\n\n // Early return all false if either global or strategy hooks root is vetoed\n if (cache.globalHooksRootVetoed || cache.strategyHooksRootVetoed) {\n return new bool[](length); // Array initialized with all false values\n }\n\n // Validate each hook\n validHooks = new bool[](length);\n for (uint256 i; i < length; i++) {\n // Try global root first\n if (_validateSingleHook(\n argsArray[i].hookAddress, argsArray[i].hookArgs, argsArray[i].globalProof, true, cache, strategy\n )) {\n validHooks[i] = true;\n } else {\n // Try strategy root\n validHooks[i] = _validateSingleHook(\n argsArray[i].hookAddress, argsArray[i].hookArgs, argsArray[i].strategyProof, false, cache, strategy\n );\n }\n // If both conditions fail, validHooks[i] remains false (default value)\n }\n\n return validHooks;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getGlobalHooksRoot() external view returns (bytes32 root) {\n return _globalHooksRoot;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getProposedGlobalHooksRoot() external view returns (bytes32 root, uint256 effectiveTime) {\n return (_proposedGlobalHooksRoot, _globalHooksRootEffectiveTime);\n }\n\n /// @notice Checks if the global hooks root is active (timelock period has passed)\n /// @return isActive True if the global hooks root is active\n function isGlobalHooksRootActive() external view returns (bool) {\n return block.timestamp >= _globalHooksRootEffectiveTime && _globalHooksRoot != bytes32(0);\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getStrategyHooksRoot(address strategy) external view returns (bytes32 root) {\n return _strategyData[strategy].managerHooksRoot;\n }\n\n /// @inheritdoc ISuperVaultAggregator\n function getProposedStrategyHooksRoot(address strategy)\n external\n view\n returns (bytes32 root, uint256 effectiveTime)\n {\n return (_strategyData[strategy].proposedHooksRoot, _strategyData[strategy].hooksRootEffectiveTime);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL HELPER FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Internal implementation of forwarding PPS updates\n /// @dev Implements Properties 7-11 from /security/security_properties.md:\n /// - Property 7: Timestamp Monotonicity (line 1213)\n /// - Property 8: Post-Unpause Timestamp Validation / C1-RE_ANCHOR (line 1222)\n /// - Property 9: Rate Limit Enforcement (line 1231)\n /// - Property 10: Deviation Threshold / C1 Check (line 1242)\n /// - Property 11: Upkeep Balance Check (line 1284)\n /// @dev Uses 'return' (not 'revert') for business logic rejections to enable batch processing\n /// @dev Auto-pauses strategy and marks PPS stale on validation failures\n /// @param args Struct containing all parameters for PPS update\n function _forwardPPS(PPSUpdateData memory args) internal {\n // Check rate limiting\n // Use the minimum of minUpdateInterval and maxStaleness to ensure minInterval is never higher than maxStaleness\n uint256 minInterval = _strategyData[args.strategy].minUpdateInterval;\n uint256 lastUpdate = _strategyData[args.strategy].lastUpdateTimestamp;\n\n // [Property 7: Timestamp Monotonicity]\n // Ensure timestamps are strictly increasing to prevent out-of-order updates.\n // This guarantees that PPS updates reflect the true chronological order of market conditions.\n if (args.timestamp <= lastUpdate) {\n emit TimestampNotMonotonic();\n return;\n }\n\n // [Property 8: Post-Unpause Timestamp Validation (C1-RE_ANCHOR)]\n // After unpause, only accept signatures timestamped AFTER the unpause event.\n // Note: lastUnpauseTimestamp is 0 for never-paused strategies (check skipped via short-circuit).\n uint256 lastUnpauseTimestamp = _strategyData[args.strategy].lastUnpauseTimestamp;\n if (lastUnpauseTimestamp > 0 && args.timestamp <= lastUnpauseTimestamp) {\n emit StaleSignatureAfterUnpause(args.strategy, args.timestamp, lastUnpauseTimestamp);\n return;\n }\n\n // [Property 9: Rate Limit Enforcement]\n // Enforce minimum time interval between PPS updates to prevent spam and ensure\n // adequate time for market conditions to change meaningfully.\n if (args.timestamp - lastUpdate < minInterval) {\n emit UpdateTooFrequent();\n return;\n }\n\n // Flag to track if any check failed\n bool checksFailed;\n\n // [Property 10: Deviation Threshold (C1 Check)]\n // Check if PPS deviation exceeds the configured threshold.\n // Large deviations may indicate data errors or extreme market conditions requiring review.\n // Skip this check if: threshold disabled (type(uint256).max), no previous PPS, or PPS marked stale.\n // Stale PPS skip allows emergency updates during liquidation scenarios.\n // Failures trigger auto-pause and mark PPS as stale (handled below).\n uint256 currentPPS = _strategyData[args.strategy].pps;\n if (\n _strategyData[args.strategy].deviationThreshold != type(uint256).max && currentPPS > 0\n && !_strategyData[args.strategy].ppsStale\n ) {\n // Skip deviation check if stale\n // Calculate absolute deviation, scaled by 1e18\n uint256 absDiff = args.pps > currentPPS ? (args.pps - currentPPS) : (currentPPS - args.pps);\n uint256 relativeDeviation = Math.mulDiv(absDiff, 1e18, currentPPS);\n if (relativeDeviation > _strategyData[args.strategy].deviationThreshold) {\n checksFailed = true;\n emit StrategyCheckFailed(args.strategy, \"HIGH_PPS_DEVIATION\");\n }\n }\n\n // [Property 11: Upkeep Balance Check]\n // Ensure the strategy has sufficient upkeep balance to pay for this update.\n // If insufficient, auto-pause the strategy and mark PPS as stale to protect against\n // continued operation without proper oracle funding.\n uint256 strategyUpkeepBalance = _strategyUpkeepBalance[args.strategy];\n if (!args.isExempt) {\n // Check if strategy has sufficient upkeep balance\n if (strategyUpkeepBalance < args.upkeepCost) {\n _strategyData[args.strategy].isPaused = true;\n _strategyData[args.strategy].ppsStale = true;\n emit StrategyPaused(args.strategy);\n emit StrategyPPSStale(args.strategy);\n emit InsufficientUpkeep(args.strategy, args.strategy, strategyUpkeepBalance, args.upkeepCost);\n return;\n }\n\n // Deduct the upkeep cost and emit event\n _strategyUpkeepBalance[args.strategy] -= args.upkeepCost;\n\n // Add claimable upkeep for the `feeRecipient`\n claimableUpkeep += args.upkeepCost;\n\n emit UpkeepSpent(args.strategy, args.upkeepCost, strategyUpkeepBalance, claimableUpkeep);\n }\n\n // Pause strategy if any check failed and mark PPS as stale\n if ((checksFailed || args.pps == 0)) {\n _strategyData[args.strategy].isPaused = true;\n _strategyData[args.strategy].ppsStale = true; // Mark stale when auto-pausing\n emit StrategyPaused(args.strategy);\n emit StrategyPPSStale(args.strategy);\n } else {\n // Only store PPS, timestamp and clear stale flag when validation passes\n _strategyData[args.strategy].pps = args.pps;\n _strategyData[args.strategy].lastUpdateTimestamp = args.timestamp;\n // Only reset stale flag if it was previously stale (gas optimization)\n if (_strategyData[args.strategy].ppsStale) {\n _strategyData[args.strategy].ppsStale = false;\n emit StrategyPPSStaleReset(args.strategy);\n }\n emit PPSUpdated(args.strategy, args.pps, args.timestamp);\n }\n // If checks failed, PPS remains at old value (safer for external integrators)\n }\n\n /// @notice Creates a leaf node for Merkle verification from hook address and arguments\n /// @param hookAddress The address of the hook contract\n /// @param hookArgs The packed-encoded hook arguments (from solidityPack in JS)\n /// @return leaf The leaf node hash\n function _createLeaf(address hookAddress, bytes calldata hookArgs) internal pure returns (bytes32) {\n /// @dev The leaf now includes both hook address and args to prevent cross-hook replay attacks\n /// @dev Different hooks with identical encoded args will have different authorization leaves\n /// @dev This matches StandardMerkleTree's standardLeafHash: keccak256(keccak256(abi.encode(hookAddress,\n /// hookArgs)))\n /// @dev but uses bytes.concat for explicit concatenation\n return keccak256(bytes.concat(keccak256(abi.encode(hookAddress, hookArgs))));\n }\n\n /**\n * @dev Internal function to validate a single hook against either global or strategy root\n * @param hookAddress The address of the hook contract\n * @param hookArgs Hook arguments\n * @param proof Merkle proof for the specified root\n * @param isGlobalProof Whether to validate against global root (true) or strategy root (false)\n * @param cache Cached hook validation state variables\n * @param strategy Address of the strategy (needed to check banned leaves for global proofs)\n * @return True if hook is valid, false otherwise\n */\n function _validateSingleHook(\n address hookAddress,\n bytes calldata hookArgs,\n bytes32[] calldata proof,\n bool isGlobalProof,\n HookValidationCache memory cache,\n address strategy\n )\n internal\n view\n returns (bool)\n {\n // Early return for common veto cases (avoid leaf creation cost)\n if (isGlobalProof) {\n if (cache.globalHooksRootVetoed || cache.globalHooksRoot == bytes32(0)) {\n return false;\n }\n } else {\n if (cache.strategyHooksRootVetoed || cache.strategyRoot == bytes32(0)) {\n return false;\n }\n }\n\n // Only create leaf if checks pass\n bytes32 leaf = _createLeaf(hookAddress, hookArgs);\n\n if (isGlobalProof) {\n // Check if this leaf is banned by the manager\n if (_strategyData[strategy].bannedLeaves[leaf]) {\n return false;\n }\n\n // For single-leaf trees, empty proof is valid when root equals leaf\n if (proof.length == 0) {\n return cache.globalHooksRoot == leaf;\n }\n return MerkleProof.verify(proof, cache.globalHooksRoot, leaf);\n } else {\n // For single-leaf trees, empty proof is valid when root equals leaf\n if (proof.length == 0) {\n return cache.strategyRoot == leaf;\n }\n return MerkleProof.verify(proof, cache.strategyRoot, leaf);\n }\n }\n\n /**\n * @dev Internal function to return the `SuperBank` address\n * @return superBank The superBank address\n */\n function _getSuperBank() internal view returns (address) {\n return SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.SUPER_BANK());\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/proxy/Clones.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/Clones.sol)\n\npragma solidity ^0.8.20;\n\nimport {Create2} from \"../utils/Create2.sol\";\nimport {Errors} from \"../utils/Errors.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n */\nlibrary Clones {\n error CloneArgumentsTooLong();\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n return clone(implementation, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency\n * to the new contract.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function clone(address implementation, uint256 value) internal returns (address instance) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n assembly (\"memory-safe\") {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create(value, 0x09, 0x37)\n }\n if (instance == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple times will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n return cloneDeterministic(implementation, salt, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with\n * a `value` parameter to send native currency to the new contract.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function cloneDeterministic(\n address implementation,\n bytes32 salt,\n uint256 value\n ) internal returns (address instance) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n assembly (\"memory-safe\") {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create2(value, 0x09, 0x37, salt)\n }\n if (instance == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n mstore(add(ptr, 0x38), deployer)\n mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)\n mstore(add(ptr, 0x14), implementation)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)\n mstore(add(ptr, 0x58), salt)\n mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))\n predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt\n ) internal view returns (address predicted) {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom\n * immutable arguments. These are provided through `args` and cannot be changed after deployment. To\n * access the arguments within the implementation, use {fetchCloneArgs}.\n *\n * This function uses the create opcode, which should never revert.\n */\n function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {\n return cloneWithImmutableArgs(implementation, args, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`\n * parameter to send native currency to the new contract.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function cloneWithImmutableArgs(\n address implementation,\n bytes memory args,\n uint256 value\n ) internal returns (address instance) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);\n assembly (\"memory-safe\") {\n instance := create(value, add(bytecode, 0x20), mload(bytecode))\n }\n if (instance == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom\n * immutable arguments. These are provided through `args` and cannot be changed after deployment. To\n * access the arguments within the implementation, use {fetchCloneArgs}.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same\n * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice\n * at the same address.\n */\n function cloneDeterministicWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt\n ) internal returns (address instance) {\n return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],\n * but with a `value` parameter to send native currency to the new contract.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function cloneDeterministicWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt,\n uint256 value\n ) internal returns (address instance) {\n bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);\n return Create2.deploy(value, salt, bytecode);\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.\n */\n function predictDeterministicAddressWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);\n return Create2.computeAddress(salt, keccak256(bytecode), deployer);\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.\n */\n function predictDeterministicAddressWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt\n ) internal view returns (address predicted) {\n return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));\n }\n\n /**\n * @dev Get the immutable args attached to a clone.\n *\n * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this\n * function will return an empty array.\n * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or\n * `cloneDeterministicWithImmutableArgs`, this function will return the args array used at\n * creation.\n * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This\n * function should only be used to check addresses that are known to be clones.\n */\n function fetchCloneArgs(address instance) internal view returns (bytes memory) {\n bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short\n assembly (\"memory-safe\") {\n extcodecopy(instance, add(result, 32), 45, mload(result))\n }\n return result;\n }\n\n /**\n * @dev Helper that prepares the initcode of the proxy with immutable args.\n *\n * An assembly variant of this function requires copying the `args` array, which can be efficiently done using\n * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using\n * abi.encodePacked is more expensive but also more portable and easier to review.\n *\n * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.\n * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.\n */\n function _cloneCodeWithImmutableArgs(\n address implementation,\n bytes memory args\n ) private pure returns (bytes memory) {\n if (args.length > 24531) revert CloneArgumentsTooLong();\n return\n abi.encodePacked(\n hex\"61\",\n uint16(args.length + 45),\n hex\"3d81600a3d39f3363d3d373d3d3d363d73\",\n implementation,\n hex\"5af43d82803e903d91602b57fd5bf3\",\n args\n );\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\nimport {Math} from \"../math/Math.sol\";\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * The following types are supported:\n *\n * - `bytes32` (`Bytes32Set`) since v3.3.0\n * - `address` (`AddressSet`) since v3.3.0\n * - `uint256` (`UintSet`) since v3.3.0\n * - `string` (`StringSet`) since v5.4.0\n * - `bytes` (`BytesSet`) since v5.4.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that\n * using it may render the function uncallable if the set grows to the point where clearing it consumes too much\n * gas to fit in a block.\n */\n function _clear(Set storage set) private {\n uint256 len = _length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {\n unchecked {\n end = Math.min(end, _length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes32[] memory result = new bytes32[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(Bytes32Set storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(AddressSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(UintSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n struct StringSet {\n // Storage of set values\n string[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(string value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(StringSet storage set, string memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(StringSet storage set, string memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n string memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(StringSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(StringSet storage set, string memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(StringSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(StringSet storage set, uint256 index) internal view returns (string memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set) internal view returns (string[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n string[] memory result = new string[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n struct BytesSet {\n // Storage of set values\n bytes[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(BytesSet storage set, bytes memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(BytesSet storage set, bytes memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(BytesSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(BytesSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set) internal view returns (bytes[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes[] memory result = new bytes[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol)\n// This file was procedurally generated from scripts/generate/templates/MerkleProof.js.\n\npragma solidity ^0.8.20;\n\nimport {Hashes} from \"./Hashes.sol\";\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The tree and the proofs can be generated using our\n * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].\n * You will find a quickstart guide in the readme.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the Merkle tree could be reinterpreted as a leaf value.\n * OpenZeppelin's JavaScript library generates Merkle trees that are safe\n * against this attack out of the box.\n *\n * IMPORTANT: Consider memory side-effects when using custom hashing functions\n * that access memory in an unsafe way.\n *\n * NOTE: This library supports proof verification for merkle trees built using\n * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving\n * leaf inclusion in trees built using non-commutative hashing functions requires\n * additional logic that is not supported by this library.\n */\nlibrary MerkleProof {\n /**\n *@dev The multiproof provided is not valid.\n */\n error MerkleProofInvalidMultiproof();\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with the default hashing function.\n */\n function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with the default hashing function.\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with a custom hashing function.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processProof(proof, leaf, hasher) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in memory with a custom hashing function.\n */\n function processProof(\n bytes32[] memory proof,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = hasher(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with the default hashing function.\n */\n function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with the default hashing function.\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with a custom hashing function.\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processProofCalldata(proof, leaf, hasher) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leaves & pre-images are assumed to be sorted.\n *\n * This version handles proofs in calldata with a custom hashing function.\n */\n function processProofCalldata(\n bytes32[] calldata proof,\n bytes32 leaf,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = hasher(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in memory with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProof}.\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in memory with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = Hashes.commutativeKeccak256(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in memory with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProof}.\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processMultiProof(proof, proofFlags, leaves, hasher) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in memory with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = hasher(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in calldata with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProofCalldata}.\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in calldata with the default hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = Hashes.commutativeKeccak256(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * This version handles multiproofs in calldata with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.\n * The `leaves` must be validated independently. See {processMultiProofCalldata}.\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * This version handles multiproofs in calldata with a custom hashing function.\n *\n * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,\n * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not\n * validating the leaves elsewhere.\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves,\n function(bytes32, bytes32) view returns (bytes32) hasher\n ) internal view returns (bytes32 merkleRoot) {\n // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the Merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 proofFlagsLen = proofFlags.length;\n\n // Check proof validity.\n if (leavesLen + proof.length != proofFlagsLen + 1) {\n revert MerkleProofInvalidMultiproof();\n }\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](proofFlagsLen);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value from the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < proofFlagsLen; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i]\n ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])\n : proof[proofPos++];\n hashes[i] = hasher(a, b);\n }\n\n if (proofFlagsLen > 0) {\n if (proofPos != proof.length) {\n revert MerkleProofInvalidMultiproof();\n }\n unchecked {\n return hashes[proofFlagsLen - 1];\n }\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n}\n"},"src/SuperVault/SuperVault.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ECDSA } from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\n\n// OpenZeppelin Upgradeable\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC165 } from \"@openzeppelin/contracts/interfaces/IERC165.sol\";\nimport { EIP712Upgradeable } from \"@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/interfaces/IERC20Metadata.sol\";\n\n// Interfaces\nimport { ISuperVault } from \"../interfaces/SuperVault/ISuperVault.sol\";\nimport { ISuperVaultStrategy } from \"../interfaces/SuperVault/ISuperVaultStrategy.sol\";\nimport { ISuperGovernor } from \"../interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"../interfaces/SuperVault/ISuperVaultAggregator.sol\";\nimport { IERC7540Operator, IERC7540Redeem, IERC7540CancelRedeem } from \"../vendor/standards/ERC7540/IERC7540Vault.sol\";\nimport { IERC7741 } from \"../vendor/standards/ERC7741/IERC7741.sol\";\nimport { IERC7575 } from \"../vendor/standards/ERC7575/IERC7575.sol\";\nimport { ISuperVaultEscrow } from \"../interfaces/SuperVault/ISuperVaultEscrow.sol\";\n\n// Libraries\nimport { AssetMetadataLib } from \"../libraries/AssetMetadataLib.sol\";\n\n/// @title SuperVault\n/// @author Superform Labs\n/// @notice SuperVault vault contract implementing ERC4626 with synchronous deposits and asynchronous redeems via\n/// ERC7540\ncontract SuperVault is Initializable, ERC20Upgradeable, ISuperVault, ReentrancyGuardUpgradeable, EIP712Upgradeable {\n using AssetMetadataLib for address;\n using SafeERC20 for IERC20;\n using Math for uint256;\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n uint256 private constant REQUEST_ID = 0;\n uint256 private constant BPS_PRECISION = 10_000;\n\n // EIP712 TypeHash\n /// @notice EIP-712 typehash for operator authorization signatures\n /// @dev Used to construct the digest for EIP-712 signature validation in authorizeOperator()\n /// Format: \"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256\n // deadline)\" / - controller: The address authorizing the operator\n /// - operator: The address being authorized/deauthorized\n /// - approved: True to authorize, false to revoke\n /// - nonce: Unique nonce for replay protection (one-time use)\n /// - deadline: Timestamp after which signature expires\n /// @dev This typehash MUST remain constant. Any changes invalidate all existing signatures.\n /// @dev Off-chain signers must use this exact structure when creating signatures for authorizeOperator()\n bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH = keccak256(\n \"AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)\"\n );\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n address public share;\n IERC20 private _asset;\n uint8 private _underlyingDecimals;\n ISuperVaultStrategy public strategy;\n address public escrow;\n uint256 public PRECISION;\n\n // Core contracts\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n /// @inheritdoc IERC7540Operator\n mapping(address owner => mapping(address operator => bool)) public isOperator;\n\n // Authorization tracking\n mapping(address controller => mapping(bytes32 nonce => bool used)) private _authorizations;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address superGovernor_) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n emit SuperGovernorSet(superGovernor_);\n\n _disableInitializers();\n }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initialize the vault with required parameters\n /// @dev This function can only be called once due to initializer modifier\n /// @dev SECURITY: asset, strategy, and escrow are pre-validated in SuperVaultAggregator.createVault()\n /// to prevent initialization with invalid addresses. No additional validation needed here.\n /// @dev PRECISION is set to 10^decimals for consistent share/asset conversions\n /// @dev EIP-712 domain separator is initialized with vault name and version \"1\" for signature validation\n /// @param asset_ The underlying asset token address (pre-validated by aggregator)\n /// @param name_ The name of the vault token (used for ERC20 and EIP-712 domain)\n /// @param symbol_ The symbol of the vault token\n /// @param strategy_ The strategy contract address (pre-validated by aggregator)\n /// @param escrow_ The escrow contract address (pre-validated by aggregator)\n function initialize(\n address asset_,\n string memory name_,\n string memory symbol_,\n address strategy_,\n address escrow_\n )\n external\n initializer\n {\n /// @dev asset, strategy, and escrow already validated in SuperVaultAggregator during vault creation\n // Initialize parent contracts\n __ERC20_init(name_, symbol_);\n __ReentrancyGuard_init();\n __EIP712_init(name_, \"1\");\n\n // Set asset and precision\n _asset = IERC20(asset_);\n (bool success, uint8 assetDecimals) = asset_.tryGetAssetDecimals();\n if (!success) revert INVALID_ASSET();\n _underlyingDecimals = assetDecimals;\n PRECISION = 10 ** _underlyingDecimals;\n share = address(this);\n strategy = ISuperVaultStrategy(strategy_);\n escrow = escrow_;\n\n emit Initialized(asset_, strategy_, escrow_);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 OVERRIDES\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc IERC4626\n function deposit(uint256 assets, address receiver) public override nonReentrant returns (uint256 shares) {\n if (receiver == address(0)) revert ZERO_ADDRESS();\n if (assets == 0) revert ZERO_AMOUNT();\n\n // Forward assets from msg.sender to strategy\n _asset.safeTransferFrom(msg.sender, address(strategy), assets);\n\n // Single executor call: strategy skims entry fee, accounts on NET, returns net shares\n // Note: handleOperations4626Deposit already validates and reverts if shares == 0\n shares = strategy.handleOperations4626Deposit(receiver, assets);\n\n // Mint the net shares\n _mint(receiver, shares);\n\n emit Deposit(msg.sender, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC4626\n function mint(uint256 shares, address receiver) public override nonReentrant returns (uint256 assets) {\n if (receiver == address(0)) revert ZERO_ADDRESS();\n if (shares == 0) revert ZERO_AMOUNT();\n\n uint256 assetsNet;\n (assets, assetsNet) = strategy.quoteMintAssetsGross(shares);\n\n // Forward quoted gross assets from msg.sender to strategy\n _asset.safeTransferFrom(msg.sender, address(strategy), assets);\n\n // Single executor call: strategy handles fees and accounts on NET\n strategy.handleOperations4626Mint(receiver, shares, assets, assetsNet);\n\n // Mint the exact shares asked\n _mint(receiver, shares);\n\n emit Deposit(msg.sender, receiver, assets, shares);\n }\n\n /// @inheritdoc IERC7540Redeem\n /// @notice Once owner has authorized an operator, controller must be the owner\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256) {\n if (shares == 0) revert ZERO_AMOUNT();\n if (owner == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateController(owner);\n\n if (balanceOf(owner) < shares) revert INVALID_AMOUNT();\n if (strategy.pendingCancelRedeemRequest(owner)) revert CANCELLATION_REDEEM_REQUEST_PENDING();\n\n // Enforce auditor's invariant for current accounting model\n if (controller != owner) revert CONTROLLER_MUST_EQUAL_OWNER();\n\n // Transfer shares to escrow for temporary locking\n _approve(owner, escrow, shares);\n ISuperVaultEscrow(escrow).escrowShares(owner, shares);\n\n // Forward to strategy (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.RedeemRequest, controller, address(0), shares);\n\n emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);\n return REQUEST_ID;\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function cancelRedeemRequest(\n uint256,\n /*requestId*/\n address controller\n )\n external\n {\n _validateController(controller);\n\n // Forward to strategy (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.CancelRedeemRequest, controller, address(0), 0);\n\n emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function claimCancelRedeemRequest(\n uint256, /*requestId*/\n address receiver,\n address controller\n )\n external\n returns (uint256 shares)\n {\n if (receiver == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateControllerAndReceiver(controller, receiver);\n\n shares = strategy.claimableCancelRedeemRequest(controller);\n\n // Forward to strategy (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.ClaimCancelRedeem, controller, address(0), 0);\n\n // Return shares to controller\n ISuperVaultEscrow(escrow).returnShares(receiver, shares);\n\n emit CancelRedeemClaim(receiver, controller, REQUEST_ID, msg.sender, shares);\n }\n\n /// @inheritdoc IERC7540Operator\n function setOperator(address operator, bool approved) external returns (bool success) {\n if (msg.sender == operator) revert UNAUTHORIZED();\n isOperator[msg.sender][operator] = approved;\n emit OperatorSet(msg.sender, operator, approved);\n return true;\n }\n\n /// @inheritdoc IERC7741\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n )\n external\n returns (bool)\n {\n if (controller == operator) revert UNAUTHORIZED();\n if (block.timestamp > deadline) revert DEADLINE_PASSED();\n if (_authorizations[controller][nonce]) revert UNAUTHORIZED();\n\n _authorizations[controller][nonce] = true;\n\n bytes32 structHash =\n keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline));\n bytes32 digest = _hashTypedDataV4(structHash);\n\n if (!_isValidSignature(controller, digest, signature)) revert INVALID_SIGNATURE();\n\n isOperator[controller][operator] = approved;\n emit OperatorSet(controller, operator, approved);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n USER EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVault\n function getEscrowedAssets() external view returns (uint256) {\n return _asset.balanceOf(escrow);\n }\n\n //--ERC7540--\n /// @inheritdoc IERC7540Redeem\n function pendingRedeemRequest(\n uint256, /*requestId*/\n address controller\n )\n external\n view\n returns (uint256 pendingShares)\n {\n return strategy.pendingRedeemRequest(controller);\n }\n\n /// @inheritdoc IERC7540Redeem\n function claimableRedeemRequest(\n uint256, /*requestId*/\n address controller\n )\n external\n view\n returns (uint256 claimableShares)\n {\n return maxRedeem(controller);\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function pendingCancelRedeemRequest(\n uint256,\n /*requestId*/\n address controller\n )\n external\n view\n returns (bool isPending)\n {\n isPending = strategy.pendingCancelRedeemRequest(controller);\n }\n\n /// @inheritdoc IERC7540CancelRedeem\n function claimableCancelRedeemRequest(\n uint256, /*requestId*/\n address controller\n )\n external\n view\n returns (uint256 claimableShares)\n {\n return strategy.claimableCancelRedeemRequest(controller);\n }\n\n //--Operator Management--\n\n /// @inheritdoc IERC7741\n function authorizations(address controller, bytes32 nonce) external view returns (bool used) {\n return _authorizations[controller][nonce];\n }\n\n /// @inheritdoc IERC7741\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /// @inheritdoc IERC7741\n function invalidateNonce(bytes32 nonce) external {\n if (_authorizations[msg.sender][nonce]) revert INVALID_NONCE();\n _authorizations[msg.sender][nonce] = true;\n\n emit NonceInvalidated(msg.sender, nonce);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC4626 IMPLEMENTATION\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc IERC20Metadata\n function decimals() public view virtual override(ERC20Upgradeable, IERC20Metadata) returns (uint8) {\n return _underlyingDecimals;\n }\n\n /// @inheritdoc IERC4626\n function asset() public view virtual override returns (address) {\n return address(_asset);\n }\n\n /// @inheritdoc IERC4626\n function totalAssets() external view override returns (uint256) {\n uint256 supply = totalSupply();\n if (supply == 0) return 0;\n uint256 currentPPS = _getStoredPPS();\n return Math.mulDiv(supply, currentPPS, PRECISION, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function convertToShares(uint256 assets) public view override returns (uint256) {\n uint256 pps = _getStoredPPS();\n return pps == 0 ? 0 : Math.mulDiv(assets, PRECISION, pps, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function convertToAssets(uint256 shares) public view override returns (uint256) {\n uint256 currentPPS = _getStoredPPS();\n return currentPPS == 0 ? 0 : Math.mulDiv(shares, currentPPS, PRECISION, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function maxDeposit(address) public view override returns (uint256) {\n if (!_canAcceptDeposits()) return 0;\n return type(uint256).max;\n }\n\n /// @inheritdoc IERC4626\n function maxMint(address) external view override returns (uint256) {\n if (!_canAcceptDeposits()) return 0;\n return type(uint256).max;\n }\n\n /// @inheritdoc IERC4626\n function maxWithdraw(address owner) public view override returns (uint256) {\n return strategy.claimableWithdraw(owner);\n }\n\n /// @inheritdoc IERC4626\n function maxRedeem(address owner) public view override returns (uint256) {\n uint256 withdrawPrice = strategy.getAverageWithdrawPrice(owner);\n if (withdrawPrice == 0) return 0;\n return maxWithdraw(owner).mulDiv(PRECISION, withdrawPrice, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n function previewDeposit(uint256 assets) public view override returns (uint256) {\n uint256 pps = _getStoredPPS();\n if (pps == 0) return 0;\n\n (uint256 feeBps,) = _getManagementFeeConfig();\n\n if (feeBps == 0) return Math.mulDiv(assets, PRECISION, pps, Math.Rounding.Floor);\n // fee-on-gross: fee = ceil(gross * feeBps / BPS)\n uint256 fee = Math.mulDiv(assets, feeBps, BPS_PRECISION, Math.Rounding.Ceil);\n\n uint256 assetsNet = assets - fee;\n return Math.mulDiv(assetsNet, PRECISION, pps, Math.Rounding.Floor);\n }\n\n /// @inheritdoc IERC4626\n /// @dev Returns gross assets required to mint exact shares after management fees\n /// @dev Formula: gross = net * BPS_PRECISION / (BPS_PRECISION - feeBps)\n /// @dev Edge case: If feeBps >= 100% (10000), returns 0 (impossible to mint with 100%+ fees)\n /// This prevents division by zero and represents mathematical impossibility.\n function previewMint(uint256 shares) public view override returns (uint256) {\n uint256 pps = _getStoredPPS();\n if (pps == 0) return 0;\n\n uint256 assetsGross = Math.mulDiv(shares, pps, PRECISION, Math.Rounding.Ceil);\n\n (uint256 feeBps,) = _getManagementFeeConfig();\n if (feeBps == 0) return assetsGross;\n if (feeBps >= BPS_PRECISION) return 0; // impossible to mint (would require infinite gross)\n\n return Math.mulDiv(assetsGross, BPS_PRECISION, (BPS_PRECISION - feeBps), Math.Rounding.Ceil);\n }\n\n /// @inheritdoc IERC4626\n function previewWithdraw(\n uint256 /* assets*/\n )\n public\n pure\n override\n returns (uint256)\n {\n revert NOT_IMPLEMENTED();\n }\n\n /// @inheritdoc IERC4626\n function previewRedeem(\n uint256 /* shares*/\n )\n public\n pure\n override\n returns (uint256)\n {\n revert NOT_IMPLEMENTED();\n }\n\n /// @inheritdoc IERC4626\n function withdraw(\n uint256 assets,\n address receiver,\n address controller\n )\n public\n override\n nonReentrant\n returns (uint256 shares)\n {\n if (receiver == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateControllerAndReceiver(controller, receiver);\n\n uint256 averageWithdrawPrice = strategy.getAverageWithdrawPrice(controller);\n if (averageWithdrawPrice == 0) revert INVALID_WITHDRAW_PRICE();\n\n uint256 maxWithdrawAmount = maxWithdraw(controller);\n if (assets > maxWithdrawAmount) revert INVALID_AMOUNT();\n\n // Calculate shares based on assets and average withdraw price\n shares = assets.mulDiv(PRECISION, averageWithdrawPrice, Math.Rounding.Ceil);\n\n uint256 escrowBalance = _asset.balanceOf(escrow);\n if (assets > escrowBalance) revert NOT_ENOUGH_ASSETS();\n\n // Update strategy state (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.ClaimRedeem, controller, receiver, assets);\n\n // Transfer assets from escrow to receiver\n ISuperVaultEscrow(escrow).returnAssets(receiver, assets);\n\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc IERC4626\n function redeem(\n uint256 shares,\n address receiver,\n address controller\n )\n public\n override\n nonReentrant\n returns (uint256 assets)\n {\n if (receiver == address(0) || controller == address(0)) revert ZERO_ADDRESS();\n _validateControllerAndReceiver(controller, receiver);\n\n uint256 averageWithdrawPrice = strategy.getAverageWithdrawPrice(controller);\n if (averageWithdrawPrice == 0) revert INVALID_WITHDRAW_PRICE();\n\n // Calculate assets based on shares and average withdraw price\n assets = shares.mulDiv(averageWithdrawPrice, PRECISION, Math.Rounding.Floor);\n\n uint256 maxWithdrawAmount = maxWithdraw(controller);\n if (assets > maxWithdrawAmount) revert INVALID_AMOUNT();\n\n uint256 escrowBalance = _asset.balanceOf(escrow);\n if (assets > escrowBalance) revert NOT_ENOUGH_ASSETS();\n\n // Update strategy state (7540 path)\n strategy.handleOperations7540(ISuperVaultStrategy.Operation.ClaimRedeem, controller, receiver, assets);\n\n // Transfer assets from escrow to receiver\n ISuperVaultEscrow(escrow).returnAssets(receiver, assets);\n\n emit Withdraw(msg.sender, receiver, controller, assets, shares);\n }\n\n /// @inheritdoc ISuperVault\n function burnShares(uint256 amount) external {\n if (msg.sender != address(strategy)) revert UNAUTHORIZED();\n _burn(escrow, amount);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 INTERFACE\n //////////////////////////////////////////////////////////////*/\n /// @notice Checks if contract supports a given interface\n /// @dev Implements ERC165 for ERC7540, ERC7741, ERC4626, ERC7575 support detection\n /// @param interfaceId The interface identifier to check\n /// @return True if the interface is supported, false otherwise\n function supportsInterface(bytes4 interfaceId) public pure returns (bool) {\n return interfaceId == type(IERC7540Redeem).interfaceId || interfaceId == type(IERC165).interfaceId\n || interfaceId == type(IERC7741).interfaceId || interfaceId == type(IERC4626).interfaceId\n || interfaceId == type(IERC7575).interfaceId || interfaceId == type(IERC7540Operator).interfaceId;\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Validates that the caller is authorized to act on behalf of the controller\n /// @dev Enforces ERC7540Operator pattern: either direct call from controller or authorized operator\n /// @dev Operators must be authorized via setOperator() or authorizeOperator() (EIP-712 signature)\n /// @dev Used in redemption flows to prevent unauthorized claims\n /// @param controller The controller address to validate authorization for\n /// @dev Reverts with INVALID_CONTROLLER if:\n /// - caller is not the controller AND\n /// - caller is not an authorized operator for the controller\n function _validateController(address controller) internal view {\n if (controller != msg.sender && !_isOperator(controller, msg.sender)) revert INVALID_CONTROLLER();\n }\n\n /// @notice Validates controller authorization and enforces operator receiver restrictions\n /// @dev Controllers can set any receiver; operators must set receiver == controller\n /// @param controller The controller address to validate authorization for\n /// @param receiver The receiver address to validate against operator restrictions\n function _validateControllerAndReceiver(address controller, address receiver) internal view {\n // If caller is controller, all good\n if (controller == msg.sender) return;\n\n // Caller is not controller, must be operator\n if (!_isOperator(controller, msg.sender)) revert INVALID_CONTROLLER();\n\n // Caller is operator, enforce receiver == controller\n if (receiver != controller) revert RECEIVER_MUST_EQUAL_CONTROLLER();\n }\n\n function _isOperator(address controller, address operator) internal view returns (bool) {\n return isOperator[controller][operator];\n }\n\n /// @notice Verify an EIP712 signature using OpenZeppelin's ECDSA library\n /// @param signer The signer to verify\n /// @param digest The digest to verify\n /// @param signature The signature to verify\n function _isValidSignature(address signer, bytes32 digest, bytes memory signature) internal pure returns (bool) {\n address recoveredSigner = ECDSA.recover(digest, signature);\n return recoveredSigner == signer;\n }\n\n function _getStoredPPS() internal view returns (uint256) {\n return strategy.getStoredPPS();\n }\n\n /// @notice Combined check for deposits acceptance\n /// @dev Reduces external calls by fetching aggregator address once\n /// @dev Previously: 4 external calls (2x getAddress + 2x aggregator checks)\n /// @dev Now: 3 external calls (1x getAddress + 2x aggregator checks)\n /// @return True if deposits can be accepted (not paused and PPS not stale)\n function _canAcceptDeposits() internal view returns (bool) {\n address aggregatorAddress = _getAggregatorAddress();\n ISuperVaultAggregator aggregator = ISuperVaultAggregator(aggregatorAddress);\n return !aggregator.isStrategyPaused(address(strategy)) && !aggregator.isPPSStale(address(strategy));\n }\n\n /// @notice Helper to get aggregator address once\n /// @return Address of the SuperVaultAggregator contract\n function _getAggregatorAddress() internal view returns (address) {\n return SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.SUPER_VAULT_AGGREGATOR());\n }\n\n /// @dev Read management fee config (view-only for previews)\n function _getManagementFeeConfig() internal view returns (uint256 feeBps, address recipient) {\n ISuperVaultStrategy.FeeConfig memory cfg = strategy.getConfigInfo();\n return (cfg.managementFeeBps, cfg.recipient);\n }\n}\n"},"src/SuperVault/SuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { LibSort } from \"solady/utils/LibSort.sol\";\n\n// Core Interfaces\nimport {\n ISuperHook,\n ISuperHookResult,\n ISuperHookContextAware,\n ISuperHookInspector\n} from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n// Periphery Interfaces\nimport { ISuperVault } from \"../interfaces/SuperVault/ISuperVault.sol\";\nimport { HookDataDecoder } from \"@superform-v2-core/src/libraries/HookDataDecoder.sol\";\nimport { ISuperVaultStrategy } from \"../interfaces/SuperVault/ISuperVaultStrategy.sol\";\nimport { ISuperGovernor, FeeType } from \"../interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"../interfaces/SuperVault/ISuperVaultAggregator.sol\";\nimport { SuperVaultAccountingLib } from \"../libraries/SuperVaultAccountingLib.sol\";\nimport { AssetMetadataLib } from \"../libraries/AssetMetadataLib.sol\";\n\n/// @title SuperVaultStrategy\n/// @author Superform Labs\n/// @notice Strategy implementation for SuperVault that executes strategies\ncontract SuperVaultStrategy is ISuperVaultStrategy, Initializable, ReentrancyGuardUpgradeable {\n using LibSort for address[];\n\n using EnumerableSet for EnumerableSet.AddressSet;\n using SafeERC20 for IERC20;\n using Math for uint256;\n using AssetMetadataLib for address;\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n uint256 private constant BPS_PRECISION = 10_000;\n uint256 private constant MAX_PERFORMANCE_FEE = 5100; // 51% max performance fee\n\n /// @dev Default redeem slippage tolerance when user hasn't set their own (0.5%)\n uint16 public constant DEFAULT_REDEEM_SLIPPAGE_BPS = 50;\n\n /// @dev Minimum allowed staleness threshold for PPS updates (prevents too-frequent validation)\n uint256 private constant MIN_PPS_EXPIRATION_THRESHOLD = 1 minutes;\n\n /// @dev Maximum allowed staleness threshold for PPS updates (prevents indefinite stale data usage)\n uint256 private constant MAX_PPS_EXPIRATION_THRESHOLD = 1 weeks;\n\n /// @dev Timelock period after unpause during which performance fee skimming is disabled (rug prevention)\n uint256 private constant POST_UNPAUSE_SKIM_TIMELOCK = 12 hours;\n\n /// @dev Timelock duration for fee config and PPS expiration threshold updates\n uint256 private constant PROPOSAL_TIMELOCK = 1 weeks;\n\n uint256 public PRECISION; // Slot 0: 32 bytes\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n // Packed slot 1: saves 1 storage slot\n address private _vault; // 20 bytes\n uint8 private _vaultDecimals; // 1 byte\n uint88 private __gap1; // 11 bytes padding\n\n // Packed slot 2\n IERC20 private _asset; // 20 bytes (address)\n uint96 private __gap2; // 12 bytes padding\n\n // Global configuration\n\n // Fee configuration\n FeeConfig private feeConfig; // Slots 3-5 (96 bytes: 2 uint256 + 1 address)\n FeeConfig private proposedFeeConfig;\n uint256 private feeConfigEffectiveTime;\n\n // Core contracts\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n // PPS expiry threshold\n uint256 public proposedPPSExpiryThreshold;\n uint256 public ppsExpiryThresholdEffectiveTime;\n uint256 public ppsExpiration;\n\n // Yield source configuration - simplified mapping from source to oracle\n mapping(address source => address oracle) private yieldSources;\n EnumerableSet.AddressSet private yieldSourcesList;\n\n // --- Global Vault High-Water Mark (PPS-based) ---\n /// @notice High-water mark price-per-share for performance fee calculation\n /// @dev Represents the PPS at which performance fees were last collected\n /// Scaled by PRECISION (e.g., 1e6 for USDC vaults, 1e18 for 18-decimal vaults)\n /// Updated during skimPerformanceFee() when fees are taken, and in executeVaultFeeConfigUpdate()\n uint256 public vaultHwmPps;\n\n // --- Redeem Request State ---\n mapping(address controller => SuperVaultState state) private superVaultState;\n\n constructor(address superGovernor_) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n emit SuperGovernorSet(superGovernor_);\n _disableInitializers();\n }\n\n /// @notice Allows the contract to receive native ETH\n /// @dev Required for hooks that may send ETH back to the strategy\n receive() external payable { }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external initializer {\n if (vaultAddress == address(0)) revert INVALID_VAULT();\n // if either fee is configured, check if recipient is address (0), if it is revert with ZERO ADDRESS\n // if both fees are 0, no need check address (it just passes the if). Recipient can be configured later\n if (\n (feeConfigData.performanceFeeBps > 0 || feeConfigData.managementFeeBps > 0)\n && feeConfigData.recipient == address(0)\n ) revert ZERO_ADDRESS();\n if (feeConfigData.performanceFeeBps > MAX_PERFORMANCE_FEE) revert INVALID_PERFORMANCE_FEE_BPS();\n if (feeConfigData.managementFeeBps > BPS_PRECISION) revert INVALID_PERFORMANCE_FEE_BPS();\n\n __ReentrancyGuard_init();\n\n _vault = vaultAddress;\n _asset = IERC20(IERC4626(vaultAddress).asset());\n _vaultDecimals = IERC20Metadata(vaultAddress).decimals();\n PRECISION = 10 ** _vaultDecimals;\n feeConfig = feeConfigData;\n\n ppsExpiration = 1 days;\n\n // Initialize HWM to 1.0 using asset decimals (same as aggregator)\n // Get asset decimals the same way aggregator does\n (bool success, uint8 assetDecimals) = address(_asset).tryGetAssetDecimals();\n if (!success) revert INVALID_ASSET();\n vaultHwmPps = 10 ** assetDecimals; // 1.0 as initial PPS (matches aggregator)\n\n emit Initialized(_vault);\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultStrategy\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet) {\n _requireVault();\n\n if (assetsGross == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n\n if (aggregator.isGlobalHooksRootVetoed()) {\n revert OPERATIONS_BLOCKED_BY_VETO();\n }\n\n _validateStrategyState(aggregator);\n\n // Fee skim in ASSETS (asset-side entry fee)\n uint256 feeBps = feeConfig.managementFeeBps;\n uint256 feeAssets = feeBps == 0 ? 0 : Math.mulDiv(assetsGross, feeBps, BPS_PRECISION, Math.Rounding.Ceil);\n\n uint256 assetsNet = assetsGross - feeAssets;\n if (assetsNet == 0) revert INVALID_AMOUNT();\n\n if (feeAssets != 0) {\n address recipient = feeConfig.recipient;\n if (recipient == address(0)) revert ZERO_ADDRESS();\n _safeTokenTransfer(address(_asset), recipient, feeAssets);\n emit ManagementFeePaid(controller, recipient, feeAssets, feeBps);\n }\n\n // Compute shares on NET using current PPS\n uint256 pps = getStoredPPS();\n if (pps == 0) revert INVALID_PPS();\n sharesNet = Math.mulDiv(assetsNet, PRECISION, pps, Math.Rounding.Floor);\n if (sharesNet == 0) revert INVALID_AMOUNT();\n\n // No HWM update needed - deposits are PPS-neutral by design\n\n emit DepositHandled(controller, assetsNet, sharesNet);\n return sharesNet;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external\n {\n _requireVault();\n\n if (sharesNet == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n\n if (aggregator.isGlobalHooksRootVetoed()) {\n revert OPERATIONS_BLOCKED_BY_VETO();\n }\n\n _validateStrategyState(aggregator);\n\n uint256 feeBps = feeConfig.managementFeeBps;\n // Transfer fee if needed\n if (feeBps != 0) {\n uint256 feeAssets = assetsGross - assetsNet;\n if (feeAssets != 0) {\n address recipient = feeConfig.recipient;\n if (recipient == address(0)) revert ZERO_ADDRESS();\n _safeTokenTransfer(address(_asset), recipient, feeAssets);\n emit ManagementFeePaid(controller, recipient, feeAssets, feeBps);\n }\n }\n\n // No HWM update needed - mints are PPS-neutral by design\n\n emit DepositHandled(controller, assetsNet, sharesNet);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet) {\n uint256 pps = getStoredPPS();\n if (pps == 0) revert INVALID_PPS();\n assetsNet = Math.mulDiv(shares, pps, PRECISION, Math.Rounding.Ceil);\n if (assetsNet == 0) revert INVALID_AMOUNT();\n\n uint256 feeBps = feeConfig.managementFeeBps;\n if (feeBps == 0) return (assetsNet, assetsNet);\n if (feeBps >= BPS_PRECISION) revert INVALID_AMOUNT(); // prevents div-by-zero (100% fee)\n assetsGross = Math.mulDiv(assetsNet, BPS_PRECISION, (BPS_PRECISION - feeBps), Math.Rounding.Ceil);\n return (assetsGross, assetsNet);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function handleOperations7540(Operation operation, address controller, address receiver, uint256 amount) external {\n _requireVault();\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n\n if (operation == Operation.RedeemRequest) {\n _validateStrategyState(aggregator);\n _handleRequestRedeem(controller, amount); // amount = shares\n } else if (operation == Operation.ClaimCancelRedeem) {\n _handleClaimCancelRedeem(controller);\n } else if (operation == Operation.ClaimRedeem) {\n _handleClaimRedeem(controller, receiver, amount); // amount = assets\n } else if (operation == Operation.CancelRedeemRequest) {\n _handleCancelRedeemRequest(controller);\n } else {\n revert ACTION_TYPE_DISALLOWED();\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function executeHooks(ExecuteArgs calldata args) external payable nonReentrant {\n _isManager(msg.sender);\n\n uint256 hooksLength = args.hooks.length;\n if (hooksLength == 0) revert ZERO_LENGTH();\n if (args.hookCalldata.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n if (args.expectedAssetsOrSharesOut.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n if (args.globalProofs.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n if (args.strategyProofs.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n\n address prevHook;\n for (uint256 i; i < hooksLength; ++i) {\n address hook = args.hooks[i];\n if (!_isRegisteredHook(hook)) revert INVALID_HOOK();\n\n // Check if the hook was validated\n if (!_validateHook(hook, args.hookCalldata[i], args.globalProofs[i], args.strategyProofs[i])) {\n revert HOOK_VALIDATION_FAILED();\n }\n\n prevHook =\n _processSingleHookExecution(hook, prevHook, args.hookCalldata[i], args.expectedAssetsOrSharesOut[i]);\n }\n emit HooksExecuted(args.hooks);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function fulfillCancelRedeemRequests(address[] memory controllers) external nonReentrant {\n _isManager(msg.sender);\n\n uint256 controllersLength = controllers.length;\n if (controllersLength == 0) revert ZERO_LENGTH();\n\n for (uint256 i; i < controllersLength; ++i) {\n SuperVaultState storage state = superVaultState[controllers[i]];\n if (state.pendingCancelRedeemRequest) {\n state.claimableCancelRedeemRequest += state.pendingRedeemRequest;\n state.pendingRedeemRequest = 0;\n state.averageRequestPPS = 0;\n emit RedeemCancelRequestFulfilled(controllers[i], state.claimableCancelRedeemRequest);\n }\n }\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function fulfillRedeemRequests(\n address[] calldata controllers,\n uint256[] calldata totalAssetsOut\n )\n external\n nonReentrant\n {\n _isManager(msg.sender);\n\n _validateStrategyState(_getSuperVaultAggregator());\n\n uint256 len = controllers.length;\n if (len == 0 || totalAssetsOut.length != len) revert INVALID_ARRAY_LENGTH();\n\n FulfillRedeemVars memory vars;\n vars.currentPPS = getStoredPPS();\n if (vars.currentPPS == 0) revert INVALID_PPS();\n\n // Process each controller with all validations in one loop\n for (uint256 i; i < len; ++i) {\n // Validate controllers are sorted and unique\n if (i > 0 && controllers[i] <= controllers[i - 1]) revert CONTROLLERS_NOT_SORTED_UNIQUE();\n\n // Load pending shares into memory and accumulate total\n uint256 pendingShares = superVaultState[controllers[i]].pendingRedeemRequest;\n vars.totalRequestedShares += pendingShares;\n\n // Disallow fulfillment for controllers with zero pending shares\n if (pendingShares == 0) revert ZERO_SHARE_FULFILLMENT_DISALLOWED();\n\n // Process fulfillment and accumulate assets\n _processExactFulfillmentBatch(controllers[i], totalAssetsOut[i], vars.currentPPS, pendingShares);\n vars.totalNetAssetsOut += totalAssetsOut[i];\n }\n\n // Balance check (no fees expected)\n vars.strategyBalance = _getTokenBalance(address(_asset), address(this));\n if (vars.strategyBalance < vars.totalNetAssetsOut) {\n revert INSUFFICIENT_LIQUIDITY();\n }\n\n // Burn shares\n ISuperVault(_vault).burnShares(vars.totalRequestedShares);\n\n // Transfer net assets to escrow\n if (vars.totalNetAssetsOut > 0) {\n _asset.safeTransfer(ISuperVault(_vault).escrow(), vars.totalNetAssetsOut);\n }\n\n emit RedeemRequestsFulfilled(controllers, vars.totalRequestedShares, vars.currentPPS);\n }\n\n /// @notice Skim performance fees based on per-share High Water Mark\n /// @dev Can be called by any manager when vault PPS has grown above HWM\n /// @dev Uses PPS-based HWM which eliminates redemption-related vulnerabilities\n function skimPerformanceFee() external nonReentrant {\n _isManager(msg.sender);\n\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n _validateStrategyState(aggregator);\n\n // Prevent skim for 12 hours after unpause\n // This timelock gives a detection window for potential abuse of fee skimming\n // post unpausing with an abnormal PPS update\n uint256 lastUnpause = aggregator.getLastUnpauseTimestamp(address(this));\n if (block.timestamp < lastUnpause + POST_UNPAUSE_SKIM_TIMELOCK) {\n revert SKIM_TIMELOCK_ACTIVE();\n }\n\n IERC4626 vault = IERC4626(_vault);\n uint256 totalSupplyLocal = vault.totalSupply();\n\n // Early return if no supply - cannot calculate PPS or collect fees\n if (totalSupplyLocal == 0) return;\n\n // Get current PPS from aggregator\n uint256 currentPPS = aggregator.getPPS(address(this));\n if (currentPPS == 0) revert INVALID_PPS();\n\n // Get the high-water mark PPS (baseline for fee calculation)\n uint256 hwmPps = vaultHwmPps;\n\n // Check if there's any per-share growth above HWM\n if (currentPPS <= hwmPps) {\n // No growth above HWM, no fee to collect\n return;\n }\n\n // Calculate PPS growth above HWM\n uint256 ppsGrowth = currentPPS - hwmPps;\n\n // Calculate total profit: (PPS growth) * (total shares) / PRECISION\n // This represents the total assets gained above the high-water mark\n uint256 profit = Math.mulDiv(ppsGrowth, totalSupplyLocal, PRECISION, Math.Rounding.Floor);\n\n // Safety check: profit must be non-zero to collect fees\n if (profit == 0) return;\n\n // Calculate fee as percentage of profit\n uint256 fee = Math.mulDiv(profit, feeConfig.performanceFeeBps, BPS_PRECISION, Math.Rounding.Ceil);\n\n // Edge case: profit exists but fee rounds to zero\n if (fee == 0) return;\n\n // Split fee between Superform treasury and strategy recipient\n uint256 sfFee =\n Math.mulDiv(fee, SUPER_GOVERNOR.getFee(FeeType.PERFORMANCE_FEE_SHARE), BPS_PRECISION, Math.Rounding.Floor);\n uint256 recipientFee = fee - sfFee;\n\n // Check if strategy has sufficient liquid assets for fee transfer\n if (_getTokenBalance(address(_asset), address(this)) < fee) revert NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n\n // Transfer fees to recipients\n _safeTokenTransfer(address(_asset), SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.TREASURY()), sfFee);\n _safeTokenTransfer(address(_asset), feeConfig.recipient, recipientFee);\n\n emit PerformanceFeeSkimmed(fee, sfFee);\n\n // Calculate the new PPS after fee extraction\n // Fee extraction reduces vault assets while shares stay constant, lowering PPS\n uint256 ppsReduction = Math.mulDiv(fee, PRECISION, totalSupplyLocal, Math.Rounding.Floor);\n\n // Safety check: ensure reduction doesn't crash PPS to zero\n if (ppsReduction >= currentPPS) revert INVALID_PPS();\n\n uint256 newPPS = currentPPS - ppsReduction;\n\n // Safety check: new PPS must be positive\n if (newPPS == 0) revert INVALID_PPS();\n\n // Update HWM to the new post-fee PPS\n // This becomes the new baseline for future fee calculations\n vaultHwmPps = newPPS;\n\n emit HWMPPSUpdated(newPPS, currentPPS, profit, fee);\n\n // Update PPS in aggregator to reflect fee extraction\n aggregator.updatePPSAfterSkim(newPPS, fee);\n }\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external {\n _isPrimaryManager(msg.sender);\n _manageYieldSource(source, oracle, actionType);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external\n {\n _isPrimaryManager(msg.sender);\n\n uint256 length = sources.length;\n if (length == 0) revert ZERO_LENGTH();\n if (oracles.length != length) revert INVALID_ARRAY_LENGTH();\n if (actionTypes.length != length) revert INVALID_ARRAY_LENGTH();\n\n for (uint256 i; i < length; ++i) {\n _manageYieldSource(sources[i], oracles[i], actionTypes[i]);\n }\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function changeFeeRecipient(address newRecipient) external {\n if (msg.sender != address(_getSuperVaultAggregator())) revert ACCESS_DENIED();\n\n feeConfig.recipient = newRecipient;\n emit FeeRecipientChanged(newRecipient);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external\n {\n _isPrimaryManager(msg.sender);\n\n if (performanceFeeBps > MAX_PERFORMANCE_FEE) revert INVALID_PERFORMANCE_FEE_BPS();\n if (managementFeeBps > BPS_PRECISION) revert INVALID_PERFORMANCE_FEE_BPS();\n if (recipient == address(0)) revert ZERO_ADDRESS();\n proposedFeeConfig = FeeConfig({\n performanceFeeBps: performanceFeeBps, managementFeeBps: managementFeeBps, recipient: recipient\n });\n feeConfigEffectiveTime = block.timestamp + PROPOSAL_TIMELOCK;\n emit VaultFeeConfigProposed(performanceFeeBps, managementFeeBps, recipient, feeConfigEffectiveTime);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function executeVaultFeeConfigUpdate() external {\n _isPrimaryManager(msg.sender);\n\n if (block.timestamp < feeConfigEffectiveTime) revert INVALID_TIMESTAMP();\n if (proposedFeeConfig.recipient == address(0)) revert ZERO_ADDRESS();\n\n // Get current PPS before updating fee config\n uint256 currentPPS = getStoredPPS();\n uint256 oldHwmPps = vaultHwmPps;\n\n // Update fee config\n feeConfig = proposedFeeConfig;\n delete proposedFeeConfig;\n feeConfigEffectiveTime = 0;\n\n // Reset HWM PPS to current PPS to avoid incorrect fee calculations with new fee structure\n vaultHwmPps = currentPPS;\n\n emit VaultFeeConfigUpdated(feeConfig.performanceFeeBps, feeConfig.managementFeeBps, feeConfig.recipient);\n emit HWMPPSUpdated(currentPPS, oldHwmPps, 0, 0);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function resetHighWaterMark(uint256 newHwmPps) external {\n if (msg.sender != address(_getSuperVaultAggregator())) revert ACCESS_DENIED();\n\n if (newHwmPps == 0) revert INVALID_PPS();\n\n vaultHwmPps = newHwmPps;\n\n emit HighWaterMarkReset(newHwmPps);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function managePPSExpiration(PPSExpirationAction action, uint256 staleness_) external {\n if (action == PPSExpirationAction.Propose) {\n _proposePPSExpiration(staleness_);\n } else if (action == PPSExpirationAction.Execute) {\n _updatePPSExpiration();\n } else if (action == PPSExpirationAction.Cancel) {\n _cancelPPSExpirationProposalUpdate();\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function setRedeemSlippage(uint16 slippageBps) external {\n if (slippageBps > BPS_PRECISION) revert INVALID_REDEEM_SLIPPAGE_BPS();\n\n superVaultState[msg.sender].redeemSlippageBps = slippageBps;\n\n emit RedeemSlippageSet(msg.sender, slippageBps);\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals) {\n vault = _vault;\n asset = address(_asset);\n vaultDecimals = _vaultDecimals;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getConfigInfo() external view returns (FeeConfig memory feeConfig_) {\n feeConfig_ = feeConfig;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getStoredPPS() public view returns (uint256) {\n return _getSuperVaultAggregator().getPPS(address(this));\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state) {\n return superVaultState[controller];\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSource(address source) external view returns (YieldSource memory) {\n return YieldSource({ oracle: yieldSources[source] });\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory) {\n uint256 length = yieldSourcesList.length();\n YieldSourceInfo[] memory sourcesInfo = new YieldSourceInfo[](length);\n\n for (uint256 i; i < length; ++i) {\n address sourceAddress = yieldSourcesList.at(i);\n address oracle = yieldSources[sourceAddress];\n\n sourcesInfo[i] = YieldSourceInfo({ sourceAddress: sourceAddress, oracle: oracle });\n }\n\n return sourcesInfo;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSources() external view returns (address[] memory) {\n return yieldSourcesList.values();\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSourcesCount() external view returns (uint256) {\n return yieldSourcesList.length();\n }\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n function vaultUnrealizedProfit() external view returns (uint256) {\n IERC4626 vault = IERC4626(_vault);\n uint256 totalSupplyLocal = vault.totalSupply();\n\n // No profit if no shares exist\n if (totalSupplyLocal == 0) return 0;\n\n uint256 currentPPS = _getSuperVaultAggregator().getPPS(address(this));\n\n // No profit if current PPS is at or below HWM\n if (currentPPS <= vaultHwmPps) return 0;\n\n // Calculate profit as: (PPS growth) * (shares) / PRECISION\n uint256 ppsGrowth = currentPPS - vaultHwmPps;\n return Math.mulDiv(ppsGrowth, totalSupplyLocal, PRECISION, Math.Rounding.Floor);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function containsYieldSource(address source) external view returns (bool) {\n return yieldSourcesList.contains(source);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares) {\n return superVaultState[controller].pendingRedeemRequest;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets) {\n return superVaultState[controller].maxWithdraw;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function pendingCancelRedeemRequest(address controller) external view returns (bool) {\n return superVaultState[controller].pendingCancelRedeemRequest;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares) {\n if (!superVaultState[controller].pendingCancelRedeemRequest) return 0;\n return superVaultState[controller].claimableCancelRedeemRequest;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice) {\n return superVaultState[controller].averageWithdrawPrice;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets)\n {\n SuperVaultState memory state = superVaultState[controller];\n shares = state.pendingRedeemRequest;\n\n if (shares == 0) return (0, 0, 0);\n\n uint256 pps = getStoredPPS();\n theoreticalAssets = shares.mulDiv(pps, PRECISION, Math.Rounding.Floor);\n\n uint16 slippageBps = state.redeemSlippageBps > 0 ? state.redeemSlippageBps : DEFAULT_REDEEM_SLIPPAGE_BPS;\n\n minAssets = SuperVaultAccountingLib.computeMinNetOut(shares, state.averageRequestPPS, slippageBps, PRECISION);\n\n return (shares, theoreticalAssets, minAssets);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets)\n {\n if (controllers.length == 0) revert ZERO_LENGTH();\n\n individualAssets = new uint256[](controllers.length);\n totalTheoAssets = 0;\n\n for (uint256 i = 0; i < controllers.length; i++) {\n // Get theoretical assets for this controller\n (, uint256 theoreticalAssets,) = this.previewExactRedeem(controllers[i]);\n individualAssets[i] = theoreticalAssets;\n totalTheoAssets += theoreticalAssets;\n }\n\n return (totalTheoAssets, individualAssets);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Process a single hook execution\n /// @param hook Hook address\n /// @param prevHook Previous hook address\n /// @param hookCalldata Hook calldata\n /// @param expectedAssetsOrSharesOut Expected assets or shares output\n /// @return processedHook Processed hook address\n function _processSingleHookExecution(\n address hook,\n address prevHook,\n bytes memory hookCalldata,\n uint256 expectedAssetsOrSharesOut\n )\n internal\n returns (address)\n {\n ExecutionVars memory vars;\n vars.hookContract = ISuperHook(hook);\n\n vars.targetedYieldSource = HookDataDecoder.extractYieldSource(hookCalldata);\n\n // Bool flagging if the hook uses the previous hook's outAmount\n // No slippage checks performed here as they have already been performed in the previous hook execution\n bool usePrevHookAmount = _decodeHookUsePrevHookAmount(hook, hookCalldata);\n\n ISuperHook(address(vars.hookContract)).setExecutionContext(address(this));\n vars.executions = vars.hookContract.build(prevHook, address(this), hookCalldata);\n for (uint256 j; j < vars.executions.length; ++j) {\n // Block hooks from calling the SuperVaultAggregator directly\n address aggregatorAddr = address(_getSuperVaultAggregator());\n if (vars.executions[j].target == aggregatorAddr) revert OPERATION_FAILED();\n (vars.success,) =\n vars.executions[j].target.call{ value: vars.executions[j].value }(vars.executions[j].callData);\n if (!vars.success) revert OPERATION_FAILED();\n }\n ISuperHook(address(vars.hookContract)).resetExecutionState(address(this));\n\n uint256 actualOutput = ISuperHookResult(hook).getOutAmount(address(this));\n\n // this is not to protect the user but rather a honest manager from doing a mistake\n if (actualOutput < expectedAssetsOrSharesOut) {\n revert MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n }\n\n emit HookExecuted(hook, prevHook, vars.targetedYieldSource, usePrevHookAmount, hookCalldata);\n\n return hook;\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL REDEMPTION PROCESSING\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Process exact fulfillment for batch processing\n /// @dev Handles all accounting updates for fulfilled redemption:\n /// 1. Validates slippage bounds (minAssets <= actual <= theoretical)\n /// 2. Updates weighted average withdraw price across multiple fulfillments\n /// 3. Clears pending state and makes assets claimable\n /// 4. Resets cancellation flags\n /// @dev SECURITY: Bounds validation ensures manager cannot underfill/overfill\n /// @dev ACCOUNTING: Average withdraw price uses weighted formula to track historical execution prices\n /// @param controller Controller address\n /// @param totalAssetsOut Total assets available for this controller (from executeHooks)\n /// @param currentPPS Current price per share\n /// @param pendingShares Pending shares for this controller (passed to avoid re-reading from storage)\n function _processExactFulfillmentBatch(\n address controller,\n uint256 totalAssetsOut,\n uint256 currentPPS,\n uint256 pendingShares\n )\n internal\n {\n SuperVaultState storage state = superVaultState[controller];\n\n // Slippage validation\n uint16 slippageBps = state.redeemSlippageBps > 0 ? state.redeemSlippageBps : DEFAULT_REDEEM_SLIPPAGE_BPS;\n\n uint256 theoreticalAssets = pendingShares.mulDiv(currentPPS, PRECISION, Math.Rounding.Floor);\n\n uint256 minAssetsOut =\n SuperVaultAccountingLib.computeMinNetOut(pendingShares, state.averageRequestPPS, slippageBps, PRECISION);\n\n // Bounds check: totalAssetsOut must be between minAssetsOut and theoreticalAssets\n if (totalAssetsOut < minAssetsOut || totalAssetsOut > theoreticalAssets) {\n revert BOUNDS_EXCEEDED(minAssetsOut, theoreticalAssets, totalAssetsOut);\n }\n\n // Update average withdraw price (use actual assets received)\n state.averageWithdrawPrice = SuperVaultAccountingLib.calculateAverageWithdrawPrice(\n state.maxWithdraw, state.averageWithdrawPrice, pendingShares, totalAssetsOut, PRECISION\n );\n\n // Reset state\n state.pendingRedeemRequest = 0;\n state.maxWithdraw += totalAssetsOut;\n state.averageRequestPPS = 0;\n state.pendingCancelRedeemRequest = false;\n state.claimableCancelRedeemRequest = 0;\n\n emit RedeemClaimable(controller, totalAssetsOut, pendingShares, state.averageWithdrawPrice);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL HELPER FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Internal function to get the SuperVaultAggregator\n /// @return The SuperVaultAggregator\n function _getSuperVaultAggregator() internal view returns (ISuperVaultAggregator) {\n address aggregatorAddress = SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.SUPER_VAULT_AGGREGATOR());\n\n return ISuperVaultAggregator(aggregatorAddress);\n }\n\n /// @notice Internal function to check if a manager is authorized\n /// @param manager_ The manager to check\n function _isManager(address manager_) internal view {\n if (!_getSuperVaultAggregator().isAnyManager(manager_, address(this))) {\n revert MANAGER_NOT_AUTHORIZED();\n }\n }\n\n /// @notice Internal function to check if a manager is the primary manager\n /// @param manager_ The manager to check\n function _isPrimaryManager(address manager_) internal view {\n if (!_getSuperVaultAggregator().isMainManager(manager_, address(this))) {\n revert MANAGER_NOT_AUTHORIZED();\n }\n }\n\n /// @notice Internal function to manage a yield source\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle\n /// @param actionType Type of action (see YieldSourceAction enum)\n function _manageYieldSource(address source, address oracle, YieldSourceAction actionType) internal {\n if (actionType == YieldSourceAction.Add) {\n _addYieldSource(source, oracle);\n } else if (actionType == YieldSourceAction.UpdateOracle) {\n _updateYieldSourceOracle(source, oracle);\n } else if (actionType == YieldSourceAction.Remove) {\n _removeYieldSource(source);\n }\n }\n\n /// @notice Internal function to add a yield source\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle\n function _addYieldSource(address source, address oracle) internal {\n if (source == address(0) || oracle == address(0)) revert ZERO_ADDRESS();\n if (yieldSources[source] != address(0)) revert YIELD_SOURCE_ALREADY_EXISTS();\n yieldSources[source] = oracle;\n if (!yieldSourcesList.add(source)) revert YIELD_SOURCE_ALREADY_EXISTS();\n\n emit YieldSourceAdded(source, oracle);\n }\n\n /// @notice Internal function to update a yield source's oracle\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle\n function _updateYieldSourceOracle(address source, address oracle) internal {\n if (oracle == address(0)) revert ZERO_ADDRESS();\n address oldOracle = yieldSources[source];\n if (oldOracle == address(0)) revert YIELD_SOURCE_NOT_FOUND();\n yieldSources[source] = oracle;\n\n emit YieldSourceOracleUpdated(source, oldOracle, oracle);\n }\n\n /// @notice Internal function to remove a yield source\n /// @param source Address of the yield source\n function _removeYieldSource(address source) internal {\n if (yieldSources[source] == address(0)) revert YIELD_SOURCE_NOT_FOUND();\n\n // Remove from mapping\n delete yieldSources[source];\n\n // Remove from EnumerableSet\n if (!yieldSourcesList.remove(source)) revert YIELD_SOURCE_NOT_FOUND();\n\n emit YieldSourceRemoved(source);\n }\n\n /// @notice Internal function to propose a PPS expiry threshold\n /// @param _threshold The new PPS expiry threshold\n function _proposePPSExpiration(uint256 _threshold) internal {\n _isPrimaryManager(msg.sender);\n\n if (_threshold < MIN_PPS_EXPIRATION_THRESHOLD || _threshold > MAX_PPS_EXPIRATION_THRESHOLD) {\n revert INVALID_PPS_EXPIRY_THRESHOLD();\n }\n\n uint256 currentProposedThreshold = proposedPPSExpiryThreshold;\n proposedPPSExpiryThreshold = _threshold;\n ppsExpiryThresholdEffectiveTime = block.timestamp + PROPOSAL_TIMELOCK;\n\n emit PPSExpirationProposed(currentProposedThreshold, _threshold, ppsExpiryThresholdEffectiveTime);\n }\n\n /// @notice Internal function to perform a PPS expiry threshold\n function _updatePPSExpiration() internal {\n _isPrimaryManager(msg.sender);\n\n // Must have a valid proposal\n if (block.timestamp < ppsExpiryThresholdEffectiveTime) revert INVALID_TIMESTAMP();\n\n if (proposedPPSExpiryThreshold == 0) revert INVALID_PPS_EXPIRY_THRESHOLD();\n\n uint256 _proposed = proposedPPSExpiryThreshold;\n ppsExpiration = _proposed;\n ppsExpiryThresholdEffectiveTime = 0;\n proposedPPSExpiryThreshold = 0;\n\n emit PPSExpiryThresholdUpdated(_proposed);\n }\n\n /// @notice Internal function to cancel a PPS expiry threshold proposal\n function _cancelPPSExpirationProposalUpdate() internal {\n _isPrimaryManager(msg.sender);\n\n if (ppsExpiryThresholdEffectiveTime == 0) revert NO_PROPOSAL();\n\n proposedPPSExpiryThreshold = 0;\n ppsExpiryThresholdEffectiveTime = 0;\n\n emit PPSExpiryThresholdProposalCanceled();\n }\n\n /// @notice Internal function to check if a hook is registered\n /// @param hook Address of the hook\n /// @return True if the hook is registered, false otherwise\n function _isRegisteredHook(address hook) private view returns (bool) {\n return SUPER_GOVERNOR.isHookRegistered(hook);\n }\n\n /// @notice Internal function to decode a hook's use previous hook amount\n /// @param hook Address of the hook\n /// @param hookCalldata Call data for the hook\n /// @return True if the hook should use the previous hook amount, false otherwise\n function _decodeHookUsePrevHookAmount(address hook, bytes memory hookCalldata) private pure returns (bool) {\n try ISuperHookContextAware(hook).decodeUsePrevHookAmount(hookCalldata) returns (bool usePrevHookAmount) {\n return usePrevHookAmount;\n } catch {\n return false;\n }\n }\n\n /// @notice Internal function to handle a redeem\n /// @param controller Address of the controller\n /// @param shares Amount of shares\n function _handleRequestRedeem(address controller, uint256 shares) private {\n if (shares == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n\n // Get current PPS from aggregator to use as baseline for slippage protection\n uint256 currentPPS = getStoredPPS();\n if (currentPPS == 0) revert INVALID_PPS();\n\n // Calculate weighted average of PPS if there's an existing request\n if (state.pendingRedeemRequest > 0) {\n // Incremental request: Calculate weighted average PPS\n // This protects users from PPS manipulation between multiple requests\n // Formula: avgPPS = (oldShares * oldPPS + newShares * newPPS) / totalShares\n uint256 existingSharesInRequest = state.pendingRedeemRequest;\n uint256 newTotalSharesInRequest = existingSharesInRequest + shares;\n\n // Weighted average ensures fair pricing across multiple request timestamps\n state.averageRequestPPS =\n ((existingSharesInRequest * state.averageRequestPPS) + (shares * currentPPS)) / newTotalSharesInRequest;\n\n state.pendingRedeemRequest = newTotalSharesInRequest;\n } else {\n // First request: Initialize with current PPS as baseline for slippage protection\n state.pendingRedeemRequest = shares;\n state.averageRequestPPS = currentPPS;\n }\n\n emit RedeemRequestPlaced(controller, controller, shares);\n }\n\n /// @notice Internal function to handle a redeem cancellation request\n /// @param controller Address of the controller\n function _handleCancelRedeemRequest(address controller) private {\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n if (state.pendingRedeemRequest == 0) revert REQUEST_NOT_FOUND();\n if (state.pendingCancelRedeemRequest) revert CANCELLATION_REDEEM_REQUEST_PENDING();\n\n state.pendingCancelRedeemRequest = true;\n emit RedeemCancelRequestPlaced(controller);\n }\n\n /// @notice Internal function to handle a claim redeem cancellation\n /// @param controller Address of the controller\n function _handleClaimCancelRedeem(address controller) private {\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n uint256 pendingShares = state.claimableCancelRedeemRequest;\n if (pendingShares == 0) revert REQUEST_NOT_FOUND();\n\n if (!state.pendingCancelRedeemRequest) revert CANCELLATION_REDEEM_REQUEST_PENDING();\n\n // Clear pending request metadata\n state.pendingCancelRedeemRequest = false;\n state.claimableCancelRedeemRequest = 0;\n emit RedeemRequestCanceled(controller, pendingShares);\n }\n\n /// @notice Internal function to handle a redeem claim\n /// @dev Only updates state. Vault is responsible for calling Escrow.returnAssets() after this returns.\n /// Callers (SuperVault.withdraw/redeem) already validate assetsToClaim <= state.maxWithdraw.\n /// @param controller Address of the controller\n /// @param receiver Address of the receiver (used for event only)\n /// @param assetsToClaim Amount of assets to claim\n function _handleClaimRedeem(address controller, address receiver, uint256 assetsToClaim) private {\n if (assetsToClaim == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n state.maxWithdraw -= assetsToClaim;\n emit RedeemRequestClaimed(receiver, controller, assetsToClaim, 0);\n }\n\n /// @notice Internal function to safely transfer tokens\n /// @param token Address of the token\n /// @param recipient Address to receive the tokens\n /// @param amount Amount of tokens to transfer\n function _safeTokenTransfer(address token, address recipient, uint256 amount) private {\n if (amount > 0) IERC20(token).safeTransfer(recipient, amount);\n }\n\n /// @notice Internal function to get the token balance of an account\n /// @param token Address of the token\n /// @param account Address of the account\n /// @return Token balance of the account\n function _getTokenBalance(address token, address account) private view returns (uint256) {\n return IERC20(token).balanceOf(account);\n }\n\n /// @notice Internal function to check if the caller is the vault\n /// @dev This is used to prevent unauthorized access to certain functions\n function _requireVault() internal view {\n if (msg.sender != _vault) revert ACCESS_DENIED();\n }\n\n /// @notice Checks if the strategy is currently paused\n /// @dev This calls SuperVaultAggregator.isStrategyPaused to determine pause status\n /// @return True if the strategy is paused, false otherwise\n function _isPaused(ISuperVaultAggregator aggregator) internal view returns (bool) {\n return aggregator.isStrategyPaused(address(this));\n }\n\n /// @notice Checks if the PPS is stale\n /// @dev This calls SuperVaultAggregator.isPPSStale to determine stale status\n /// @return True if the PPS is stale, false otherwise\n function _isPPSStale(ISuperVaultAggregator aggregator) internal view returns (bool) {\n return aggregator.isPPSStale(address(this));\n }\n\n /// @notice Checks if the PPS is not updated\n /// @dev This checks if the PPS has not been updated since the `ppsExpiration` time\n /// @param aggregator The SuperVaultAggregator contract\n /// @return True if the PPS is not updated, false otherwise\n function _isPPSNotUpdated(ISuperVaultAggregator aggregator) internal view returns (bool) {\n // The `ppsExpiration` serves a different purpose:\n // if the oracle network stops pushing updates for some reasons (e.g. quite some nodes go down and the\n // quorum is never reached)\n // then the onchain PPS gets never updated and eventually it should not be used anymore, which is what the\n // `ppsExpiration` logic controls\n uint256 lastPPSUpdateTimestamp = aggregator.getLastUpdateTimestamp(address(this));\n return block.timestamp - lastPPSUpdateTimestamp > ppsExpiration;\n }\n\n /// @notice Validates full pps state by checking pause, stale, and PPS update status\n /// @dev Used for operations that require current PPS for calculations:\n /// - handleOperations4626Deposit: Needs PPS to calculate shares from assets\n /// - handleOperations4626Mint: Needs PPS to validate asset requirements\n /// - fulfillRedeemRequests: Needs current PPS to calculate assets from shares\n /// @param aggregator The SuperVaultAggregator contract\n function _validateStrategyState(ISuperVaultAggregator aggregator) internal view {\n if (_isPaused(aggregator)) revert STRATEGY_PAUSED();\n if (_isPPSStale(aggregator)) revert STALE_PPS();\n if (_isPPSNotUpdated(aggregator)) revert PPS_EXPIRED();\n }\n\n /// @notice Validates a hook using the Merkle root system\n /// @param hook Address of the hook to validate\n /// @param hookCalldata Calldata to be passed to the hook\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n /// @return isValid True if the hook is valid, false otherwise\n function _validateHook(\n address hook,\n bytes memory hookCalldata,\n bytes32[] memory globalProof,\n bytes32[] memory strategyProof\n )\n internal\n view\n returns (bool)\n {\n return _getSuperVaultAggregator()\n .validateHook(\n address(this),\n ISuperVaultAggregator.ValidateHookArgs({\n hookAddress: hook,\n hookArgs: ISuperHookInspector(hook).inspect(hookCalldata),\n globalProof: globalProof,\n strategyProof: strategyProof\n })\n );\n }\n}\n"},"src/interfaces/SuperVault/ISuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { ISuperHook, Execution } from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n/// @title ISuperVaultStrategy\n/// @author Superform Labs\n/// @notice Interface for SuperVault strategy implementation that manages yield sources and executes strategies\ninterface ISuperVaultStrategy {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n error ZERO_LENGTH();\n error INVALID_HOOK();\n error ZERO_ADDRESS();\n error ACCESS_DENIED();\n error INVALID_AMOUNT();\n error OPERATION_FAILED();\n error INVALID_TIMESTAMP();\n error REQUEST_NOT_FOUND();\n error INVALID_ARRAY_LENGTH();\n error ACTION_TYPE_DISALLOWED();\n error YIELD_SOURCE_NOT_FOUND();\n error YIELD_SOURCE_ALREADY_EXISTS();\n error INVALID_PERFORMANCE_FEE_BPS();\n error MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n error MANAGER_NOT_AUTHORIZED();\n error INVALID_PPS();\n error INVALID_VAULT();\n error INVALID_ASSET();\n error OPERATIONS_BLOCKED_BY_VETO();\n error HOOK_VALIDATION_FAILED();\n error STRATEGY_PAUSED();\n error NO_PROPOSAL();\n error INVALID_REDEEM_SLIPPAGE_BPS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n error STALE_PPS();\n error PPS_EXPIRED();\n error INVALID_PPS_EXPIRY_THRESHOLD();\n error BOUNDS_EXCEEDED(uint256 minAllowed, uint256 maxAllowed, uint256 actual);\n error INSUFFICIENT_LIQUIDITY();\n error CONTROLLERS_NOT_SORTED_UNIQUE();\n error ZERO_SHARE_FULFILLMENT_DISALLOWED();\n error NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n error SKIM_TIMELOCK_ACTIVE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event SuperGovernorSet(address indexed superGovernor);\n event Initialized(address indexed vault);\n event YieldSourceAdded(address indexed source, address indexed oracle);\n event YieldSourceOracleUpdated(address indexed source, address indexed oldOracle, address indexed newOracle);\n event YieldSourceRemoved(address indexed source);\n\n event VaultFeeConfigUpdated(uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient);\n event VaultFeeConfigProposed(\n uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient, uint256 effectiveTime\n );\n event HooksExecuted(address[] hooks);\n event RedeemRequestPlaced(address indexed controller, address indexed owner, uint256 shares);\n event RedeemRequestClaimed(address indexed controller, address indexed receiver, uint256 assets, uint256 shares);\n event RedeemRequestsFulfilled(address[] controllers, uint256 processedShares, uint256 currentPPS);\n event RedeemRequestCanceled(address indexed controller, uint256 shares);\n event RedeemCancelRequestPlaced(address indexed controller);\n event RedeemCancelRequestFulfilled(address indexed controller, uint256 shares);\n event HookExecuted(\n address indexed hook,\n address indexed prevHook,\n address indexed targetedYieldSource,\n bool usePrevHookAmount,\n bytes hookCalldata\n );\n\n event PPSUpdated(uint256 newPPS, uint256 calculationBlock);\n event FeeRecipientChanged(address indexed newRecipient);\n event ManagementFeePaid(address indexed controller, address indexed recipient, uint256 feeAssets, uint256 feeBps);\n event DepositHandled(address indexed controller, uint256 assets, uint256 shares);\n event RedeemClaimable(\n address indexed controller, uint256 assetsFulfilled, uint256 sharesFulfilled, uint256 averageWithdrawPrice\n );\n event RedeemSlippageSet(address indexed controller, uint16 slippageBps);\n\n event PPSExpirationProposed(uint256 currentProposedThreshold, uint256 ppsExpiration, uint256 effectiveTime);\n event PPSExpiryThresholdUpdated(uint256 ppsExpiration);\n event PPSExpiryThresholdProposalCanceled();\n\n /// @notice Emitted when the high-water mark PPS is updated after fee collection\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n /// @param previousPps The PPS before fee collection\n /// @param profit The total profit above HWM (in assets)\n /// @param feeCollected The total fee collected (in assets)\n event HWMPPSUpdated(uint256 newHwmPps, uint256 previousPps, uint256 profit, uint256 feeCollected);\n\n /// @notice Emitted when the high-water mark PPS is reset\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n event HighWaterMarkReset(uint256 newHwmPps);\n\n /// @notice Emitted when performance fees are skimmed\n /// @param totalFee The total fee collected (in assets)\n /// @param superformFee The fee collected for Superform (in assets)\n event PerformanceFeeSkimmed(uint256 totalFee, uint256 superformFee);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n struct FeeConfig {\n uint256 performanceFeeBps; // On profit at fulfill time\n uint256 managementFeeBps; // Entry fee on deposit/mint (asset-side)\n address recipient; // Fee sink (entry + performance)\n }\n\n /// @notice Structure for hook execution arguments\n struct ExecuteArgs {\n /// @notice Array of hooks to execute\n address[] hooks;\n /// @notice Calldata for each hook (must match hooks array length)\n bytes[] hookCalldata;\n /// @notice Expected output amounts or output shares\n uint256[] expectedAssetsOrSharesOut;\n /// @notice Global Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] globalProofs;\n /// @notice Strategy-specific Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] strategyProofs;\n }\n\n struct YieldSource {\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice Comprehensive information about a yield source including its address and configuration\n struct YieldSourceInfo {\n address sourceAddress; // Address of the yield source\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice State specific to asynchronous redeem requests\n struct SuperVaultState {\n // Cancellation\n bool pendingCancelRedeemRequest;\n uint256 claimableCancelRedeemRequest;\n // Redeems\n uint256 pendingRedeemRequest; // Shares requested\n uint256 maxWithdraw; // Assets claimable after fulfillment\n uint256 averageRequestPPS; // Average PPS at the time of redeem request\n uint256 averageWithdrawPrice; // Average price for claimable assets\n uint16 redeemSlippageBps; // User-defined slippage tolerance in BPS for redeem fulfillment\n }\n\n struct ExecutionVars {\n bool success;\n address targetedYieldSource;\n uint256 outAmount;\n ISuperHook hookContract;\n Execution[] executions;\n }\n\n struct FulfillRedeemVars {\n uint256 totalRequestedShares;\n uint256 totalNetAssetsOut;\n uint256 currentPPS;\n uint256 strategyBalance;\n }\n\n /*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n enum Operation {\n RedeemRequest,\n CancelRedeemRequest,\n ClaimCancelRedeem,\n ClaimRedeem\n }\n\n /// @notice Action types for yield source management\n enum YieldSourceAction {\n Add, // 0: Add a new yield source\n UpdateOracle, // 1: Update an existing yield source's oracle\n Remove // 2: Remove a yield source\n }\n\n /// @notice Action types for PPS expiration threshold management\n enum PPSExpirationAction {\n Propose, // 0: Propose a new PPS expiration threshold\n Execute, // 1: Execute the proposed threshold update\n Cancel // 2: Cancel the pending threshold proposal\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the strategy with required parameters\n /// @param vaultAddress Address of the associated SuperVault\n /// @param feeConfigData Fee configuration\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external;\n\n /// @notice Execute a 4626 deposit by processing assets.\n /// @param controller The controller address\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @return sharesNet The amount of net shares to mint\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet);\n\n /// @notice Execute a 4626 mint by processing shares.\n /// @param controller The controller address\n /// @param sharesNet The amount of shares to mint\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @param assetsNet The amount of net assets that strategy will receive\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external;\n\n /// @notice Quotes the amount of assets that will be received for a given amount of shares.\n /// @param shares The amount of shares to mint\n /// @return assetsGross The amount of gross assets that will be received\n /// @return assetsNet The amount of net assets that will be received\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet);\n\n /// @notice Execute async redeem requests (redeem, cancel, claim).\n /// @param op The operation type (RedeemRequest, CancelRedeem, ClaimRedeem)\n /// @param controller The controller address\n /// @param receiver The receiver address\n /// @param amount The amount of assets or shares\n function handleOperations7540(Operation op, address controller, address receiver, uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Execute hooks for general strategy management (rebalancing, etc.).\n /// @param args Execution arguments containing hooks, calldata, proofs, expectations.\n function executeHooks(ExecuteArgs calldata args) external payable;\n\n /// @notice Fulfills pending cancel redeem requests by making shares claimable\n /// @dev Processes all controllers with pending cancellation flags\n /// @dev Can only be called by authorized managers\n /// @param controllers Array of controller addresses with pending cancel requests\n function fulfillCancelRedeemRequests(address[] memory controllers) external;\n\n /// @notice Fulfills pending redeem requests with exact total assets per controller (pre-fee).\n /// @dev PRE: Off-chain sort/unique controllers. Call executeHooks(sum(totalAssetsOut)) first.\n /// @dev Social: totalAssetsOut[i] = theoreticalGross[i] (full). Selective: totalAssetsOut[i] < theoreticalGross[i].\n /// @dev NOTE: totalAssetsOut includes fees - actual net amount received is calculated internally after fee\n /// deduction. @param controllers Ordered/unique controllers with pending requests.\n /// @param totalAssetsOut Total PRE-FEE assets available for each controller[i] (from executeHooks).\n function fulfillRedeemRequests(address[] calldata controllers, uint256[] calldata totalAssetsOut) external;\n\n /// @notice Skim performance fees based on per-share High Water Mark (PPS-based)\n /// @dev Can be called by any manager when vault PPS has grown above HWM PPS\n /// @dev Uses PPS growth to calculate profit: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev HWM is only updated during this function, not during deposits/redemptions\n function skimPerformanceFee() external;\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Manage a single yield source: add, update oracle, or remove\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle (used for adding/updating, ignored for removal)\n /// @param actionType Type of action (see YieldSourceAction enum)\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external;\n\n /// @notice Batch manage multiple yield sources in a single transaction\n /// @param sources Array of yield source addresses\n /// @param oracles Array of oracle addresses (used for adding/updating, ignored for removal)\n /// @param actionTypes Array of action types (see YieldSourceAction enum)\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external;\n\n /// @notice Change the fee recipient when the primary manager is changed\n /// @param newRecipient New fee recipient\n function changeFeeRecipient(address newRecipient) external;\n\n /// @notice Propose or execute a hook root update\n /// @notice Propose changes to vault-specific fee configuration\n /// @param performanceFeeBps New performance fee in basis points\n /// @param managementFeeBps New management fee in basis points\n /// @param recipient New fee recipient\n /// @dev IMPORTANT: Before executing the proposed update (via executeVaultFeeConfigUpdate),\n /// manager should call skimPerformanceFee() to collect performance fees on existing profits\n /// under the current fee structure to avoid losing profit or incorrect fee calculations.\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external;\n\n /// @notice Execute the proposed vault fee configuration update after timelock\n /// @dev IMPORTANT: Manager should call skimPerformanceFee() before executing this update\n /// to collect performance fees on existing profits under the current fee structure.\n /// Otherwise, profit earned under the old fee percentage will be lost or incorrectly calculated.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// to avoid incorrect fee calculations with the new fee structure.\n function executeVaultFeeConfigUpdate() external;\n\n /// @notice Reset the high-water mark PPS to the current PPS\n /// @dev This function is only callable by Aggregator\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// @param newHwmPps The new high-water mark PPS value\n function resetHighWaterMark(uint256 newHwmPps) external;\n\n /// @notice Manage PPS expiry threshold\n /// @param action Type of action (see PPSExpirationAction enum)\n /// @param ppsExpiration The new PPS expiry threshold\n function managePPSExpiration(PPSExpirationAction action, uint256 ppsExpiration) external;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set the slippage tolerance for all future redeem request fulfillments, until reset using this function\n /// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)\n function setRedeemSlippage(uint16 slippageBps) external;\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Get the vault info\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals);\n\n /// @notice Get the fee configurations\n function getConfigInfo() external view returns (FeeConfig memory feeConfig);\n\n /// @notice Returns the currently stored PPS value.\n function getStoredPPS() external view returns (uint256);\n\n /// @notice Get a yield source's configuration\n function getYieldSource(address source) external view returns (YieldSource memory);\n\n /// @notice Get all yield sources with their information\n /// @return Array of YieldSourceInfo structs\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory);\n\n /// @notice Get all yield source addresses\n /// @return Array of yield source addresses\n function getYieldSources() external view returns (address[] memory);\n\n /// @notice Get the count of yield sources\n /// @return Number of yield sources\n function getYieldSourcesCount() external view returns (uint256);\n\n /// @notice Check if a yield source exists\n /// @param source Address of the yield source\n /// @return True if the yield source exists\n function containsYieldSource(address source) external view returns (bool);\n\n /// @notice Get the average withdraw price for a controller\n /// @param controller The controller address\n /// @return averageWithdrawPrice The average withdraw price\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice);\n\n /// @notice Get the super vault state for a controller\n /// @param controller The controller address\n /// @return state The super vault state\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state);\n\n /// @notice Get the pending redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return pendingShares The amount of shares pending redemption\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares);\n\n /// @notice Get the pending cancellation for a redeem request for a controller\n /// @param controller The controller address\n /// @return isPending True if the redeem request is pending cancellation\n function pendingCancelRedeemRequest(address controller) external view returns (bool isPending);\n\n /// @notice Get the claimable cancel redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return claimableShares The amount of shares claimable\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares);\n\n /// @notice Get the claimable withdraw amount (assets) for a controller\n /// @param controller The controller address\n /// @return claimableAssets The amount of assets claimable\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets);\n\n /// @notice Preview exact redeem fulfillment for off-chain calculation\n /// @param controller The controller address to preview\n /// @return shares Pending redeem shares\n /// @return theoreticalAssets Theoretical assets at current PPS\n /// @return minAssets Minimum acceptable assets (slippage floor)\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets);\n\n /// @notice Batch preview exact redeem fulfillment for multiple controllers\n /// @dev Efficiently batches multiple previewExactRedeem calls to reduce RPC overhead\n /// @param controllers Array of controller addresses to preview\n /// @return totalTheoAssets Total theoretical assets across all controllers\n /// @return individualAssets Array of theoretical assets per controller\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets);\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev Returns 0 if totalSupply is 0 or currentPPS <= hwmPPS\n function vaultUnrealizedProfit() external view returns (uint256);\n}\n"},"src/SuperVault/SuperVaultEscrow.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ISuperVaultEscrow } from \"../interfaces/SuperVault/ISuperVaultEscrow.sol\";\n\n/// @title SuperVaultEscrow\n/// @author Superform Labs\n/// @notice Escrow contract for SuperVault shares during request/claim process\ncontract SuperVaultEscrow is ISuperVaultEscrow {\n using SafeERC20 for IERC20;\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n bool public initialized;\n address public vault;\n\n /*//////////////////////////////////////////////////////////////\n MODIFIERS\n //////////////////////////////////////////////////////////////*/\n modifier onlyVault() {\n _onlyVault();\n _;\n }\n\n function _onlyVault() internal view {\n if (msg.sender != vault) revert UNAUTHORIZED();\n }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultEscrow\n function initialize(address vaultAddress) external {\n if (initialized) revert ALREADY_INITIALIZED();\n if (vaultAddress == address(0)) revert ZERO_ADDRESS();\n\n initialized = true;\n vault = vaultAddress;\n\n emit Initialized(vaultAddress);\n }\n\n /*//////////////////////////////////////////////////////////////\n VAULT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultEscrow\n function escrowShares(address from, uint256 amount) external onlyVault {\n if (amount == 0) revert ZERO_AMOUNT();\n IERC20(vault).safeTransferFrom(from, address(this), amount);\n emit SharesEscrowed(from, amount);\n }\n\n /// @inheritdoc ISuperVaultEscrow\n function returnShares(address to, uint256 amount) external onlyVault {\n if (amount == 0) revert ZERO_AMOUNT();\n IERC20(vault).safeTransfer(to, amount);\n emit SharesReturned(to, amount);\n }\n\n /// @inheritdoc ISuperVaultEscrow\n function returnAssets(address to, uint256 amount) external onlyVault {\n if (amount == 0) revert ZERO_AMOUNT();\n if (to == address(0)) revert ZERO_ADDRESS();\n IERC20(IERC4626(vault).asset()).safeTransfer(to, amount);\n emit AssetsReturned(to, amount);\n }\n}\n"},"src/interfaces/ISuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n/// @notice Enum representing different types of fees that can be managed\nenum FeeType {\n REVENUE_SHARE,\n PERFORMANCE_FEE_SHARE\n}\n/// @title ISuperGovernor\n/// @author Superform Labs\n/// @notice Interface for the SuperGovernor contract\n/// @dev Central registry for all deployed contracts in the Superform periphery\n\ninterface ISuperGovernor is IAccessControl {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Structure containing Merkle root data for a hook\n struct HookMerkleRootData {\n bytes32 currentRoot; // Current active Merkle root for the hook\n bytes32 proposedRoot; // Proposed new Merkle root (zero if no proposal exists)\n uint256 effectiveTime; // Timestamp when the proposed root becomes effective\n }\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when trying to access a contract that is not registered\n error CONTRACT_NOT_FOUND();\n /// @notice Thrown when providing an invalid address (typically zero address)\n error INVALID_ADDRESS();\n /// @notice Thrown when a hook is not approved but expected to be\n error HOOK_NOT_APPROVED();\n /// @notice Thrown when an invalid fee value is proposed (must be <= BPS_MAX)\n error INVALID_FEE_VALUE();\n /// @notice Thrown when no proposed fee exists but one is expected\n error NO_PROPOSED_FEE(FeeType feeType);\n /// @notice Thrown when timelock period has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when a validator is already registered\n error VALIDATOR_ALREADY_REGISTERED();\n /// @notice Thrown when trying to change active PPS oracle directly\n error MUST_USE_TIMELOCK_FOR_CHANGE();\n /// @notice Thrown when a SuperBank hook Merkle root is not registered but expected to be\n /// @dev This error is defined here for use by other contracts in the system (SuperVaultStrategy,\n /// SuperVaultAggregator, ECDSAPPSOracle)\n error INVALID_TIMESTAMP();\n /// @notice Thrown when attempting to set an invalid quorum value (typically zero)\n error INVALID_QUORUM();\n /// @notice Thrown when validator and public key array lengths don't match\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when trying to set validator config with an empty validator array\n error EMPTY_VALIDATOR_ARRAY();\n /// @notice Thrown when no active PPS oracle is set but one is required\n error NO_ACTIVE_PPS_ORACLE();\n /// @notice Thrown when no proposed PPS oracle exists but one is expected\n error NO_PROPOSED_PPS_ORACLE();\n /// @notice Error thrown when manager takeovers are frozen\n error MANAGER_TAKEOVERS_FROZEN();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error NO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error ZERO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed minimum staleness exists but one is expected\n error NO_PROPOSED_MIN_STALENESS();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when there's no pending change but one is expected\n error NO_PENDING_CHANGE();\n /// @notice Thrown when the super oracle is not found\n error SUPER_ORACLE_NOT_FOUND();\n /// @notice Thrown when the up token is not found\n error UP_NOT_FOUND();\n /// @notice Thrown when the upkeep token is not found\n error UPKEEP_TOKEN_NOT_FOUND();\n /// @notice Thrown when the gas info is invalid\n error INVALID_GAS_INFO();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an address is set in the registry\n /// @param key The key used to reference the address\n /// @param oldValue The old address value\n /// @param value The address value\n event AddressSet(bytes32 indexed key, address indexed oldValue, address indexed value);\n\n /// @notice Emitted when a hook is approved\n /// @param hook The address of the approved hook\n event HookApproved(address indexed hook);\n\n /// @notice Emitted when validator configuration is set\n /// @param version The version of the configuration\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys (for signature verification)\n /// @param quorum The quorum required for validator consensus\n /// @param offchainConfig Offchain configuration data\n event ValidatorConfigSet(\n uint256 version, address[] validators, bytes[] validatorPublicKeys, uint256 quorum, bytes offchainConfig\n );\n\n /// @notice Emitted when a hook is removed\n /// @param hook The address of the removed hook\n event HookRemoved(address indexed hook);\n\n /// @notice Emitted when a new fee is proposed\n /// @param feeType The type of fee being proposed\n /// @param value The proposed fee value (in basis points)\n /// @param effectiveTime The timestamp when the fee will be effective\n event FeeProposed(FeeType indexed feeType, uint256 value, uint256 effectiveTime);\n\n /// @notice Emitted when a fee is updated\n /// @param feeType The type of fee being updated\n /// @param value The new fee value (in basis points)\n event FeeUpdated(FeeType indexed feeType, uint256 value);\n\n /// @notice Emitted when a new SuperBank hook Merkle root is proposed\n /// @param hook The hook address for which the Merkle root is being proposed\n /// @param newRoot The new Merkle root\n /// @param effectiveTime The timestamp when the new root will be effective\n event SuperBankHookMerkleRootProposed(address indexed hook, bytes32 newRoot, uint256 effectiveTime);\n\n /// @notice Emitted when the SuperBank hook Merkle root is updated.\n /// @param hook The address of the hook for which the Merkle root was updated.\n /// @param newRoot The new Merkle root.\n event SuperBankHookMerkleRootUpdated(address indexed hook, bytes32 newRoot);\n\n /// @notice Emitted when an active PPS oracle is initially set\n /// @param oracle The address of the set oracle\n event ActivePPSOracleSet(address indexed oracle);\n\n /// @notice Emitted when a new PPS oracle is proposed\n /// @param oracle The address of the proposed oracle\n /// @param effectiveTime The timestamp when the proposal will be effective\n event ActivePPSOracleProposed(address indexed oracle, uint256 effectiveTime);\n\n /// @notice Emitted when the active PPS oracle is changed\n /// @param oldOracle The address of the previous oracle\n /// @param newOracle The address of the new oracle\n event ActivePPSOracleChanged(address indexed oldOracle, address indexed newOracle);\n\n /// @notice Event emitted when manager takeovers are permanently frozen\n event ManagerTakeoversFrozen();\n\n /// @notice Emitted when a change to upkeep payments status is proposed\n /// @param enabled The proposed status (enabled/disabled)\n /// @param effectiveTime The timestamp when the status change will be effective\n event UpkeepPaymentsChangeProposed(bool enabled, uint256 effectiveTime);\n\n /// @notice Emitted when upkeep payments status is changed\n /// @param enabled The new status (enabled/disabled)\n event UpkeepPaymentsChanged(bool enabled);\n\n /// @notice Emitted when a new minimum staleness is proposed\n /// @param newMinStaleness The proposed minimum staleness value\n /// @param effectiveTime The timestamp when the new value will be effective\n event MinStalenessProposed(uint256 newMinStaleness, uint256 effectiveTime);\n\n /// @notice Emitted when the minimum staleness is changed\n /// @param newMinStaleness The new minimum staleness value\n event MinStalenessChanged(uint256 newMinStaleness);\n\n /// @notice Emitted when gas info is set\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n event GasInfoSet(address indexed oracle, uint256 gasIncreasePerEntryBatch);\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets an address in the registry\n /// @param key The key to associate with the address\n /// @param value The address value\n function setAddress(bytes32 key, address value) external;\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Change the primary manager for a strategy\n /// @dev Only SuperGovernor can call this function directly\n /// @param strategy The strategy address\n /// @param newManager The new primary manager address\n /// @param feeRecipient The new fee recipient address\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Resets the high-water mark PPS to the current PPS\n /// @dev Only SuperGovernor can call this function\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value for the given strategy\n /// @param strategy Address of the strategy to reset the high-water mark for\n function resetHighWaterMark(address strategy) external;\n\n /// @notice Permanently freezes all manager takeovers globally\n function freezeManagerTakeover() external;\n\n /// @notice Changes the hooks root update timelock duration\n /// @param newTimelock New timelock duration in seconds\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes a new global hooks Merkle root\n /// @dev Only GOVERNOR_ROLE can call this function\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Sets veto status for global hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Sets veto status for a strategy-specific hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param strategy Address of the strategy to affect\n /// @param vetoed Whether to veto (true) or unveto (false) the strategy hooks root\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Sets the maximum staleness period for all oracle feeds\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleMaxStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness period for a specific oracle feed\n /// @param feed The address of the feed to set staleness for\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness periods for multiple oracle feeds in batch\n /// @param feeds The addresses of the feeds to set staleness for\n /// @param newMaxStalenessList The new maximum staleness periods in seconds\n function setOracleFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Queues an oracle update for execution after timelock period\n /// @param bases Base asset addresses\n /// @param quotes Quote asset addresses\n /// @param providers Provider identifiers\n /// @param feeds Feed addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Executes a previously queued oracle update after timelock has expired\n function executeOracleUpdate() external;\n\n /// @notice Queues a provider removal for execution after timelock period\n /// @param providers The providers to remove\n function queueOracleProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Sets uptime feeds for multiple data oracles in batch (Layer 2 only)\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Registers a hook for use in SuperVaults\n /// @param hook The address of the hook to register\n function registerHook(address hook) external;\n\n /// @notice Unregisters a hook from the approved list\n /// @param hook The address of the hook to unregister\n function unregisterHook(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the validator configuration for the protocol\n /// @dev This function atomically updates all validator configuration including quorum.\n /// The entire validator set is replaced (not incrementally updated).\n /// Version must be managed externally for cross-chain synchronization.\n /// Quorum updates require providing the full validator list.\n /// @param version The version number for the configuration (for cross-chain sync)\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys for signature verification\n /// @param quorum The number of validators required for consensus\n /// @param offchainConfig Offchain configuration data (emitted but not stored)\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the active PPS oracle (only if there is no active oracle yet)\n /// @param oracle Address of the PPS oracle to set as active\n function setActivePPSOracle(address oracle) external;\n\n /// @notice Proposes a new active PPS oracle (when there is already an active one)\n /// @param oracle Address of the PPS oracle to propose as active\n function proposeActivePPSOracle(address oracle) external;\n\n /// @notice Executes a previously proposed PPS oracle change after timelock has expired\n function executeActivePPSOracleChange() external;\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new fee value\n /// @param feeType The type of fee to propose\n /// @param value The proposed fee value (in basis points)\n function proposeFee(FeeType feeType, uint256 value) external;\n\n /// @notice Executes a previously proposed fee update after timelock has expired\n /// @param feeType The type of ffee to execute the update for\n function executeFeeUpdate(FeeType feeType) external;\n\n /// @notice Executes an upkeep claim on `SuperVaultAggregator`\n /// @param amount The amount to claim\n function executeUpkeepClaim(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets gas info for an oracle\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external;\n\n /// @notice Proposes a change to upkeep payments enabled status\n /// @param enabled The proposed enabled status\n function proposeUpkeepPaymentsChange(bool enabled) external;\n\n /// @notice Executes a previously proposed upkeep payments status change\n function executeUpkeepPaymentsChange() external;\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new minimum staleness value to prevent maxStaleness from being set too low\n /// @param newMinStaleness The proposed new minimum staleness value in seconds\n function proposeMinStaleness(uint256 newMinStaleness) external;\n\n /// @notice Executes a previously proposed minimum staleness change after timelock has expired\n function executeMinStalenessChange() external;\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to update the Merkle root for.\n /// @param proposedRoot The proposed new Merkle root.\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external;\n\n /// @notice Executes a previously proposed Merkle root update for a specific hook if the effective time has passed.\n /// @param hook The address of the hook to execute the update for.\n function executeSuperBankHookMerkleRootUpdate(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice The identifier of the role that grants access to critical governance functions\n function SUPER_GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to daily operations like hooks and validators\n function GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to bank management functions\n function BANK_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to gas management functions\n function GAS_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to oracle management functions\n function ORACLE_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to guardian functions\n function GUARDIAN_ROLE() external view returns (bytes32);\n\n /// @notice Gets an address from the registry\n /// @param key The key of the address to get\n /// @return The address value\n function getAddress(bytes32 key) external view returns (address);\n\n /// @notice Checks if manager takeovers are frozen\n /// @return True if manager takeovers are frozen, false otherwise\n function isManagerTakeoverFrozen() external view returns (bool);\n\n /// @notice Checks if a hook is registered\n /// @param hook The address of the hook to check\n /// @return True if the hook is registered, false otherwise\n function isHookRegistered(address hook) external view returns (bool);\n\n /// @notice Gets all registered hooks\n /// @return An array of registered hook addresses\n function getRegisteredHooks() external view returns (address[] memory);\n\n /// @notice Checks if an address is an approved validator\n /// @param validator The address to check\n /// @return True if the address is an approved validator, false otherwise\n function isValidator(address validator) external view returns (bool);\n\n /// @notice Checks if an address has the guardian role\n /// @param guardian Address to check\n /// @return true if the address has the GUARDIAN_ROLE\n function isGuardian(address guardian) external view returns (bool);\n\n /// @notice Returns the complete validator configuration\n /// @return version The current configuration version number\n /// @return validators Array of all registered validator addresses\n /// @return validatorPublicKeys Array of validator public keys\n /// @return quorum The number of validators required for consensus\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum);\n\n /// @notice Returns all registered validators\n /// @return List of validator addresses\n function getValidators() external view returns (address[] memory);\n\n /// @notice Returns the number of registered validators (O(1))\n function getValidatorsCount() external view returns (uint256);\n\n /// @notice Returns a validator address by index (0 … count-1)\n /// @param index The index into the validators set\n /// @return validator The validator address at the given index\n function getValidatorAt(uint256 index) external view returns (address validator);\n\n /// @notice Gets the proposed active PPS oracle and its effective time\n /// @return proposedOracle The proposed oracle address\n /// @return effectiveTime The timestamp when the proposed oracle will become effective\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime);\n\n /// @notice Gets the current quorum requirement for the active PPS Oracle\n /// @return The current quorum requirement\n function getPPSOracleQuorum() external view returns (uint256);\n\n /// @notice Gets the active PPS oracle\n /// @return The active PPS oracle address\n function getActivePPSOracle() external view returns (address);\n\n /// @notice Checks if an address is the current active PPS oracle\n /// @param oracle The address to check\n /// @return True if the address is the active PPS oracle, false otherwise\n function isActivePPSOracle(address oracle) external view returns (bool);\n\n /// @notice Gets the current fee value for a specific fee type\n /// @param feeType The type of fee to get\n /// @return The current fee value (in basis points)\n function getFee(FeeType feeType) external view returns (uint256);\n\n /// @notice Gets the current upkeep cost for an entry\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256);\n\n /// @notice Gets the proposed upkeep cost per update and its effective time\n /// @notice Gets the current minimum staleness value\n /// @return The current minimum staleness value in seconds\n function getMinStaleness() external view returns (uint256);\n\n /// @notice Gets the proposed minimum staleness value and its effective time\n /// @return proposedMinStaleness The proposed new minimum staleness value\n /// @return effectiveTime The timestamp when the new value will become effective\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime);\n\n /// @notice Returns the current Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to get the Merkle root for.\n /// @return The Merkle root for the hook's allowed targets.\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32);\n\n /// @notice Gets the proposed Merkle root and its effective time for a specific hook.\n /// @param hook The address of the hook to get the proposed Merkle root for.\n /// @return proposedRoot The proposed Merkle root.\n /// @return effectiveTime The timestamp when the proposed root will become effective.\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime);\n\n /// @notice Checks if upkeep payments are currently enabled\n /// @return enabled True if upkeep payments are enabled\n function isUpkeepPaymentsEnabled() external view returns (bool);\n\n /// @notice Gets the proposed upkeep payments status and effective time\n /// @return enabled The proposed status\n /// @return effectiveTime The timestamp when the change becomes effective\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime);\n\n /// @notice Gets the SUP strategy ID\n /// @return The ID of the SUP strategy vault\n function SUP_STRATEGY() external view returns (bytes32);\n\n /// @notice Gets the UP ID\n /// @return The ID of the UP token\n function UP() external view returns (bytes32);\n\n /// @notice Gets the UPKEEP_TOKEN ID\n /// @return The ID of the UPKEEP_TOKEN (used for upkeep payments, can be UP on mainnet or WETH/USDC on L2s)\n function UPKEEP_TOKEN() external view returns (bytes32);\n\n /// @notice Gets the Treasury ID\n /// @return The ID for the Treasury in the registry\n function TREASURY() external view returns (bytes32);\n\n /// @notice Gets the SuperOracle ID\n /// @return The ID for the SuperOracle in the registry\n function SUPER_ORACLE() external view returns (bytes32);\n\n /// @notice Gets the ECDSA PPS Oracle ID\n /// @return The ID for the ECDSA PPS Oracle in the registry\n function ECDSAPPSORACLE() external view returns (bytes32);\n\n /// @notice Gets the SuperVaultAggregator ID\n /// @return The ID for the SuperVaultAggregator in the registry\n function SUPER_VAULT_AGGREGATOR() external view returns (bytes32);\n\n /// @notice Gets the SuperBank ID\n /// @return The ID for the SuperBank in the registry\n function SUPER_BANK() external view returns (bytes32);\n\n /// @notice Gets the gas info for a specific SuperVault PPS Oracle\n /// @param oracle_ The address of the oracle to get gas info for\n /// @return The gas info for the specified oracle\n function getGasInfo(address oracle_) external view returns (uint256);\n\n /// @notice Cancels a previously proposed oracle provider removal\n function cancelOracleProviderRemoval() external;\n\n /// @notice Executes a previously proposed oracle provider removal after timelock has expired\n function executeOracleProviderRemoval() external;\n}\n"},"src/interfaces/SuperVault/ISuperVaultAggregator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { ISuperVaultStrategy } from \"../SuperVault/ISuperVaultStrategy.sol\";\n\n/// @title ISuperVaultAggregator\n/// @author Superform Labs\n/// @notice Interface for the SuperVaultAggregator contract\n/// @dev Registry and PPS oracle for all SuperVaults\ninterface ISuperVaultAggregator {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for forwarding PPS updates to avoid stack too deep errors\n /// @param strategy Address of the strategy being updated\n /// @param isExempt Whether the update is exempt from paying upkeep\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp when the value was generated\n /// @param upkeepCost Amount of upkeep tokens to charge if not exempt\n struct PPSUpdateData {\n address strategy;\n bool isExempt;\n uint256 pps;\n uint256 timestamp;\n uint256 upkeepCost;\n }\n\n /// @notice Local variables for vault creation to avoid stack too deep\n /// @param currentNonce Current vault creation nonce\n /// @param salt Salt for deterministic proxy creation\n /// @param initialPPS Initial price-per-share value\n struct VaultCreationLocalVars {\n uint256 currentNonce;\n bytes32 salt;\n uint256 initialPPS;\n }\n\n /// @notice Strategy configuration and state data\n /// @param pps Current price-per-share value\n /// @param lastUpdateTimestamp Last time PPS was updated\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param isPaused Whether the strategy is paused\n /// @param mainManager Address of the primary manager controlling the strategy\n /// @param secondaryManagers Set of secondary managers that can manage the strategy\n struct StrategyData {\n uint256 pps; // Slot 0: 32 bytes\n uint256 lastUpdateTimestamp; // Slot 1: 32 bytes\n uint256 minUpdateInterval; // Slot 2: 32 bytes\n uint256 maxStaleness; // Slot 3: 32 bytes\n // Packed slot 4: saves 2 storage slots (~4000 gas per read)\n address mainManager; // 20 bytes\n bool ppsStale; // 1 byte\n bool isPaused; // 1 byte\n bool hooksRootVetoed; // 1 byte\n uint72 __gap1; // 9 bytes padding\n EnumerableSet.AddressSet secondaryManagers;\n // Manager change proposal data\n address proposedManager;\n address proposedFeeRecipient;\n uint256 managerChangeEffectiveTime;\n // Hook validation data\n bytes32 managerHooksRoot;\n // Hook root update proposal data\n bytes32 proposedHooksRoot;\n uint256 hooksRootEffectiveTime;\n // PPS Verification thresholds\n uint256 deviationThreshold; // Threshold for abs(new - current) / current\n // Banned global leaves mapping\n mapping(bytes32 => bool) bannedLeaves; // Mapping of leaf hash to banned status\n // Min update interval proposal data\n uint256 proposedMinUpdateInterval;\n uint256 minUpdateIntervalEffectiveTime;\n uint256 lastUnpauseTimestamp; // Timestamp of last unpause (for skim timelock)\n }\n\n /// @notice Parameters for creating a new SuperVault trio\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param mainManager Address of the vault mainManager\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param feeConfig Fee configuration for the vault\n struct VaultCreationParams {\n address asset;\n string name;\n string symbol;\n address mainManager;\n address[] secondaryManagers;\n uint256 minUpdateInterval;\n uint256 maxStaleness;\n ISuperVaultStrategy.FeeConfig feeConfig;\n }\n\n /// @notice Struct to hold cached hook validation state variables to avoid stack too deep\n /// @param globalHooksRootVetoed Cached global hooks root veto status\n /// @param globalHooksRoot Cached global hooks root\n /// @param strategyHooksRootVetoed Cached strategy hooks root veto status\n /// @param strategyRoot Cached strategy hooks root\n struct HookValidationCache {\n bool globalHooksRootVetoed;\n bytes32 globalHooksRoot;\n bool strategyHooksRootVetoed;\n bytes32 strategyRoot;\n }\n\n /// @notice Arguments for validating a hook to avoid stack too deep\n /// @param hookAddress Address of the hook contract\n /// @param hookArgs Encoded arguments for the hook operation\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n struct ValidateHookArgs {\n address hookAddress;\n bytes hookArgs;\n bytes32[] globalProof;\n bytes32[] strategyProof;\n }\n\n /// @notice Two-step upkeep withdrawal request\n /// @param amount Amount to withdraw (full balance at time of request)\n /// @param effectiveTime When withdrawal can be executed (timestamp + 24h)\n struct UpkeepWithdrawalRequest {\n uint256 amount;\n uint256 effectiveTime;\n }\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when a new vault trio is created\n /// @param vault Address of the created SuperVault\n /// @param strategy Address of the created SuperVaultStrategy\n /// @param escrow Address of the created SuperVaultEscrow\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param nonce The nonce used for vault creation\n event VaultDeployed(\n address indexed vault,\n address indexed strategy,\n address escrow,\n address asset,\n string name,\n string symbol,\n uint256 indexed nonce\n );\n\n /// @notice Emitted when a PPS value is updated\n /// @param strategy Address of the strategy\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp of the update\n event PPSUpdated(address indexed strategy, uint256 pps, uint256 timestamp);\n\n /// @notice Emitted when a strategy is paused due to missed updates\n /// @param strategy Address of the paused strategy\n event StrategyPaused(address indexed strategy);\n\n /// @notice Emitted when a strategy is unpaused\n /// @param strategy Address of the unpaused strategy\n event StrategyUnpaused(address indexed strategy);\n\n /// @notice Emitted when a strategy validation check fails but execution continues\n /// @param strategy Address of the strategy that failed the check\n /// @param reason String description of which check failed\n event StrategyCheckFailed(address indexed strategy, string reason);\n\n /// @notice Emitted when upkeep tokens are deposited\n /// @param strategy Address of the strategy\n /// @param depositor Address of the depositor\n /// @param amount Amount of upkeep tokens deposited\n event UpkeepDeposited(address indexed strategy, address indexed depositor, uint256 amount);\n\n /// @notice Emitted when upkeep tokens are withdrawn\n /// @param strategy Address of the strategy\n /// @param withdrawer Address of the withdrawer (main manager of the strategy)\n /// @param amount Amount of upkeep tokens withdrawn\n event UpkeepWithdrawn(address indexed strategy, address indexed withdrawer, uint256 amount);\n\n /// @notice Emitted when an upkeep withdrawal is proposed (start of 24h timelock)\n /// @param strategy Address of the strategy\n /// @param mainManager Address of the main manager who proposed the withdrawal\n /// @param amount Amount of upkeep tokens to withdraw\n /// @param effectiveTime Timestamp when withdrawal can be executed\n event UpkeepWithdrawalProposed(\n address indexed strategy, address indexed mainManager, uint256 amount, uint256 effectiveTime\n );\n\n /// @notice Emitted when a pending upkeep withdrawal is cancelled (e.g., during governance takeover)\n /// @param strategy Address of the strategy\n event UpkeepWithdrawalCancelled(address indexed strategy);\n\n /// @notice Emitted when upkeep tokens are spent for validation\n /// @param strategy Address of the strategy\n /// @param amount Amount of upkeep tokens spent\n /// @param balance Current balance of the strategy\n /// @param claimableUpkeep Amount of upkeep tokens claimable\n event UpkeepSpent(address indexed strategy, uint256 amount, uint256 balance, uint256 claimableUpkeep);\n\n /// @notice Emitted when a secondary manager is added to a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager added\n event SecondaryManagerAdded(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a secondary manager is removed from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager removed\n event SecondaryManagerRemoved(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a primary manager is changed\n /// @param strategy Address of the strategy\n /// @param oldManager Address of the old primary manager\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n event PrimaryManagerChanged(\n address indexed strategy, address indexed oldManager, address indexed newManager, address feeRecipient\n );\n\n /// @notice Emitted when a change to primary manager is proposed by a secondary manager\n /// @param strategy Address of the strategy\n /// @param proposer Address of the secondary manager who made the proposal\n /// @param newManager Address of the proposed new primary manager\n /// @param effectiveTime Timestamp when the proposal can be executed\n event PrimaryManagerChangeProposed(\n address indexed strategy,\n address indexed proposer,\n address indexed newManager,\n address feeRecipient,\n uint256 effectiveTime\n );\n\n /// @notice Emitted when a primary manager change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledManager Address of the manager that was proposed\n event PrimaryManagerChangeCancelled(address indexed strategy, address indexed cancelledManager);\n\n /// @notice Emitted when the High Water Mark for a strategy is reset to PPS\n /// @param strategy Address of the strategy\n /// @param newHWM The new High Water Mark (PPS)\n event HighWaterMarkReset(address indexed strategy, uint256 indexed newHWM);\n\n /// @notice Emitted when a PPS update is stale (Validators could get slashed for innactivity)\n /// @param strategy Address of the strategy\n /// @param updateAuthority Address of the update authority\n /// @param timestamp Timestamp of the stale update\n event StaleUpdate(address indexed strategy, address indexed updateAuthority, uint256 timestamp);\n\n /// @notice Emitted when the global hooks Merkle root is being updated\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event GlobalHooksRootUpdateProposed(bytes32 indexed root, uint256 effectiveTime);\n\n /// @notice Emitted when the global hooks Merkle root is updated\n /// @param oldRoot Previous root value\n /// @param newRoot New root value\n event GlobalHooksRootUpdated(bytes32 indexed oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is updated\n /// @param strategy Address of the strategy\n /// @param oldRoot Previous root value (may be zero)\n /// @param newRoot New root value\n event StrategyHooksRootUpdated(address indexed strategy, bytes32 oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the account proposing the new root\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event StrategyHooksRootUpdateProposed(\n address indexed strategy, address indexed proposer, bytes32 root, uint256 effectiveTime\n );\n\n /// @notice Emitted when a proposed global hooks root update is vetoed by SuperGovernor\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event GlobalHooksRootVetoStatusChanged(bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's hooks Merkle root veto status changes\n /// @param strategy Address of the strategy\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event StrategyHooksRootVetoStatusChanged(address indexed strategy, bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's deviation threshold is updated\n /// @param strategy Address of the strategy\n /// @param deviationThreshold New deviation threshold (abs diff/current)\n event DeviationThresholdUpdated(address indexed strategy, uint256 deviationThreshold);\n\n /// @notice Emitted when the hooks root update timelock is changed\n /// @param newTimelock New timelock duration in seconds\n event HooksRootUpdateTimelockChanged(uint256 newTimelock);\n\n /// @notice Emitted when global leaves status is changed for a strategy\n /// @param strategy Address of the strategy\n /// @param leaves Array of leaf hashes that had their status changed\n /// @param statuses Array of new banned statuses (true = banned, false = allowed)\n event GlobalLeavesStatusChanged(address indexed strategy, bytes32[] leaves, bool[] statuses);\n\n /// @notice Emitted when upkeep is claimed\n /// @param superBank Address of the superBank\n /// @param amount Amount of upkeep claimed\n event UpkeepClaimed(address indexed superBank, uint256 amount);\n\n /// @notice Emitted when PPS update is too frequent (before minUpdateInterval)\n event UpdateTooFrequent();\n\n /// @notice Emitted when PPS update timestamp is not monotonically increasing\n event TimestampNotMonotonic();\n\n /// @notice Emitted when PPS update is rejected due to stale signature after unpause\n event StaleSignatureAfterUnpause(\n address indexed strategy, uint256 signatureTimestamp, uint256 lastUnpauseTimestamp\n );\n\n /// @notice Emitted when a strategy does not have enough upkeep balance\n event InsufficientUpkeep(address indexed strategy, address indexed strategyAddr, uint256 balance, uint256 cost);\n\n /// @notice Emitted when the provided timestamp is too large\n event ProvidedTimestampExceedsBlockTimestamp(\n address indexed strategy, uint256 argsTimestamp, uint256 blockTimestamp\n );\n\n /// @notice Emitted when a strategy is unknown\n event UnknownStrategy(address indexed strategy);\n\n /// @notice Emitted when the old primary manager is removed from the strategy\n /// @dev This can happen because of reaching the max number of secondary managers\n event OldPrimaryManagerRemoved(address indexed strategy, address indexed oldManager);\n\n /// @notice Emitted when a strategy's PPS is stale\n event StrategyPPSStale(address indexed strategy);\n\n /// @notice Emitted when a strategy's PPS is reset\n event StrategyPPSStaleReset(address indexed strategy);\n\n /// @notice Emitted when PPS is updated after performance fee skimming\n /// @param strategy Address of the strategy\n /// @param oldPPS Previous price-per-share value\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee skimmed that caused the PPS update\n /// @param timestamp Timestamp of the update\n event PPSUpdatedAfterSkim(\n address indexed strategy, uint256 oldPPS, uint256 newPPS, uint256 feeAmount, uint256 timestamp\n );\n\n /// @notice Emitted when a change to minUpdateInterval is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the manager who made the proposal\n /// @param newMinUpdateInterval The proposed new minimum update interval\n /// @param effectiveTime Timestamp when the proposal can be executed\n event MinUpdateIntervalChangeProposed(\n address indexed strategy, address indexed proposer, uint256 newMinUpdateInterval, uint256 effectiveTime\n );\n\n /// @notice Emitted when a minUpdateInterval change is executed\n /// @param strategy Address of the strategy\n /// @param oldMinUpdateInterval Previous minimum update interval\n /// @param newMinUpdateInterval New minimum update interval\n event MinUpdateIntervalChanged(\n address indexed strategy, uint256 oldMinUpdateInterval, uint256 newMinUpdateInterval\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is rejected due to validation failure\n /// @param strategy Address of the strategy\n /// @param proposedInterval The proposed interval that was rejected\n /// @param currentMaxStaleness The current maxStaleness value that caused rejection\n event MinUpdateIntervalChangeRejected(\n address indexed strategy, uint256 proposedInterval, uint256 currentMaxStaleness\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledInterval The proposed interval that was cancelled\n event MinUpdateIntervalChangeCancelled(address indexed strategy, uint256 cancelledInterval);\n\n /// @notice Emitted when a PPS update is rejected because strategy is paused\n /// @param strategy Address of the paused strategy\n event PPSUpdateRejectedStrategyPaused(address indexed strategy);\n\n /*///////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when address provided is zero\n error ZERO_ADDRESS();\n /// @notice Thrown when amount provided is zero\n error ZERO_AMOUNT();\n /// @notice Thrown when vault creation parameters are invalid (empty name or symbol)\n error INVALID_VAULT_PARAMS();\n /// @notice Thrown when array length is zero\n error ZERO_ARRAY_LENGTH();\n /// @notice Thrown when array length is zero\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when asset is invalid\n error INVALID_ASSET();\n /// @notice Thrown when insufficient upkeep balance for operation\n error INSUFFICIENT_UPKEEP();\n /// @notice Thrown when caller is not authorized\n error CALLER_NOT_AUTHORIZED();\n /// @notice Thrown when caller is not an approved PPS oracle\n error UNAUTHORIZED_PPS_ORACLE();\n /// @notice Thrown when caller is not authorized for update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n /// @notice Thrown when strategy address is not a known SuperVault strategy\n error UNKNOWN_STRATEGY();\n /// @notice Thrown when trying to unpause a strategy that is not paused\n error STRATEGY_NOT_PAUSED();\n /// @notice Thrown when trying to pause a strategy that is already paused\n error STRATEGY_ALREADY_PAUSED();\n /// @notice Thrown when array index is out of bounds\n error INDEX_OUT_OF_BOUNDS();\n /// @notice Thrown when attempting to add a manager that already exists\n error MANAGER_ALREADY_EXISTS();\n /// @notice Thrown when attempting to add a manager that is the primary manager\n error SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n /// @notice Thrown when there is no pending global hooks root change\n error NO_PENDING_GLOBAL_ROOT_CHANGE();\n /// @notice Thrown when attempting to execute a hooks root change before timelock has elapsed\n error ROOT_UPDATE_NOT_READY();\n /// @notice Thrown when a provided hook fails Merkle proof validation\n error HOOK_VALIDATION_FAILED();\n /// @notice Thrown when manager is not found\n error MANAGER_NOT_FOUND();\n /// @notice Thrown when there is no pending manager change proposal\n error NO_PENDING_MANAGER_CHANGE();\n /// @notice Thrown when caller is not authorized to update settings\n error UNAUTHORIZED_CALLER();\n /// @notice Thrown when the timelock for a proposed change has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when an array length is invalid\n error INVALID_ARRAY_LENGTH();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when arrays have mismatched lengths\n error MISMATCHED_ARRAY_LENGTHS();\n /// @notice Thrown when timestamp is invalid\n error INVALID_TIMESTAMP(uint256 index);\n /// @notice Thrown when too many secondary managers are added\n error TOO_MANY_SECONDARY_MANAGERS();\n /// @notice Thrown when upkeep withdrawal timelock has not passed yet\n error UPKEEP_WITHDRAWAL_NOT_READY();\n /// @notice Thrown when no pending upkeep withdrawal request exists\n error UPKEEP_WITHDRAWAL_NOT_FOUND();\n /// @notice PPS must decrease after skimming fees\n error PPS_MUST_DECREASE_AFTER_SKIM();\n /// @notice PPS deduction is larger than the maximum allowed fee rate\n error PPS_DEDUCTION_TOO_LARGE();\n /// @notice Thrown when no minUpdateInterval change proposal is pending\n error NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n /// @notice Thrown when minUpdateInterval >= maxStaleness\n error MIN_UPDATE_INTERVAL_TOO_HIGH();\n /// @notice Thrown when trying to update PPS while strategy is paused\n error STRATEGY_PAUSED();\n /// @notice Thrown when trying to update PPS while PPS is stale\n error PPS_STALE();\n\n /*//////////////////////////////////////////////////////////////\n VAULT CREATION\n //////////////////////////////////////////////////////////////*/\n /// @notice Creates a new SuperVault trio (SuperVault, SuperVaultStrategy, SuperVaultEscrow)\n /// @param params Parameters for the new vault creation\n /// @return superVault Address of the created SuperVault\n /// @return strategy Address of the created SuperVaultStrategy\n /// @return escrow Address of the created SuperVaultEscrow\n function createVault(VaultCreationParams calldata params)\n external\n returns (address superVault, address strategy, address escrow);\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for batch forwarding PPS updates\n /// @param strategies Array of strategy addresses\n /// @param ppss Array of price-per-share values\n /// @param timestamps Array of timestamps when values were generated\n /// @param updateAuthority Address of the update authority\n struct ForwardPPSArgs {\n address[] strategies;\n uint256[] ppss;\n uint256[] timestamps;\n address updateAuthority;\n }\n\n /// @notice Batch forwards validated PPS updates to multiple strategies\n /// @param args Struct containing all batch PPS update parameters\n function forwardPPS(ForwardPPSArgs calldata args) external;\n\n /// @notice Updates PPS directly after performance fee skimming\n /// @dev Only callable by the strategy contract itself (msg.sender must be a registered strategy)\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee that was skimmed (for event logging)\n function updatePPSAfterSkim(uint256 newPPS, uint256 feeAmount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Deposits upkeep tokens for strategy upkeep\n /// @dev The upkeep token is configurable per chain (UP on mainnet, WETH on L2s, etc.)\n /// @param strategy Address of the strategy to deposit for\n /// @param amount Amount of upkeep tokens to deposit\n function depositUpkeep(address strategy, uint256 amount) external;\n\n /// @notice Proposes withdrawal of upkeep tokens from strategy upkeep balance (starts 24h timelock)\n /// @dev Only the main manager can propose. Withdraws full balance at time of proposal.\n /// @param strategy Address of the strategy to withdraw from\n function proposeWithdrawUpkeep(address strategy) external;\n\n /// @notice Executes a pending upkeep withdrawal after 24h timelock\n /// @dev Anyone can execute, but funds go to the main manager of the strategy\n /// @param strategy Address of the strategy to withdraw from\n function executeWithdrawUpkeep(address strategy) external;\n\n /// @notice Claims upkeep tokens from the contract\n /// @param amount Amount of upkeep tokens to claim\n function claimUpkeep(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n PAUSE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Manually pauses a strategy\n /// @param strategy Address of the strategy to pause\n function pauseStrategy(address strategy) external;\n\n /// @notice Manually unpauses a strategy\n /// @param strategy Address of the strategy to unpause\n function unpauseStrategy(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER MANAGEMENT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Adds a secondary manager to a strategy\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to add\n function addSecondaryManager(address strategy, address manager) external;\n\n /// @notice Removes a secondary manager from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to remove\n function removeSecondaryManager(address strategy, address manager) external;\n\n /// @notice Changes the primary manager of a strategy immediately (only callable by SuperGovernor)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Proposes a change to the primary manager (callable by secondary managers)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the proposed new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function proposeChangePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Cancels a pending primary manager change proposal\n /// @dev Only the current primary manager can cancel the proposal\n /// @param strategy Address of the strategy\n function cancelChangePrimaryManager(address strategy) external;\n\n /// @notice Executes a previously proposed change to the primary manager after timelock\n /// @param strategy Address of the strategy\n function executeChangePrimaryManager(address strategy) external;\n\n /// @notice Resets the strategy's performance-fee high-water mark to PPS\n /// @dev Only callable by SuperGovernor\n /// @param strategy Address of the strategy\n function resetHighWaterMark(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK VALIDATION FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets a new hooks root update timelock duration\n /// @param newTimelock The new timelock duration in seconds\n function setHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes an update to the global hooks Merkle root\n /// @dev Only callable by SUPER_GOVERNOR\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed global hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeGlobalHooksRootUpdate() external;\n\n /// @notice Proposes an update to a strategy-specific hooks Merkle root\n /// @dev Only callable by the main manager for the strategy\n /// @param strategy Address of the strategy\n /// @param newRoot New Merkle root for strategy-specific hooks\n function proposeStrategyHooksRoot(address strategy, bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed strategy hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n /// @param strategy Address of the strategy whose root update to execute\n function executeStrategyHooksRootUpdate(address strategy) external;\n\n /// @notice Set veto status for the global hooks root\n /// @dev Only callable by SuperGovernor\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Set veto status for a strategy-specific hooks root\n /// @notice Sets the veto status of a strategy's hooks Merkle root\n /// @param strategy Address of the strategy\n /// @param vetoed Whether to veto (true) or unveto (false)\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Updates the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @param deviationThreshold_ New deviation threshold (abs diff/current ratio, scaled by 1e18)\n function updateDeviationThreshold(address strategy, uint256 deviationThreshold_) external;\n\n /// @notice Changes the banned status of global leaves for a specific strategy\n /// @dev Only callable by the primary manager of the strategy\n /// @param leaves Array of leaf hashes to change status for\n /// @param statuses Array of banned statuses (true = banned, false = allowed)\n /// @param strategy Address of the strategy to change banned leaves for\n function changeGlobalLeavesStatus(bytes32[] memory leaves, bool[] memory statuses, address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MIN UPDATE INTERVAL MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Proposes a change to the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @param newMinUpdateInterval The proposed new minimum update interval (in seconds)\n /// @dev Only the main manager can propose. Must be less than maxStaleness\n function proposeMinUpdateIntervalChange(address strategy, uint256 newMinUpdateInterval) external;\n\n /// @notice Executes a previously proposed minUpdateInterval change after timelock\n /// @param strategy Address of the strategy whose minUpdateInterval to update\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Cancels a pending minUpdateInterval change proposal\n /// @param strategy Address of the strategy\n /// @dev Only the main manager can cancel\n function cancelMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Gets the proposed minUpdateInterval and effective time\n /// @param strategy Address of the strategy\n /// @return proposedInterval The proposed minimum update interval\n /// @return effectiveTime The timestamp when the proposed interval becomes effective\n function getProposedMinUpdateInterval(address strategy)\n external\n view\n returns (uint256 proposedInterval, uint256 effectiveTime);\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the current vault creation nonce\n /// @dev This nonce is incremented every time a new vault is created\n /// @return Current vault creation nonce\n function getCurrentNonce() external view returns (uint256);\n\n /// @notice Check if the global hooks root is currently vetoed\n /// @return vetoed True if the global hooks root is vetoed\n function isGlobalHooksRootVetoed() external view returns (bool vetoed);\n\n /// @notice Check if a strategy hooks root is currently vetoed\n /// @param strategy Address of the strategy to check\n /// @return vetoed True if the strategy hooks root is vetoed\n function isStrategyHooksRootVetoed(address strategy) external view returns (bool vetoed);\n\n /// @notice Gets the current hooks root update timelock duration\n /// @return The current timelock duration in seconds\n function getHooksRootUpdateTimelock() external view returns (uint256);\n\n /// @notice Gets the current PPS (price-per-share) for a strategy\n /// @param strategy Address of the strategy\n /// @return pps Current price-per-share value\n function getPPS(address strategy) external view returns (uint256 pps);\n\n /// @notice Gets the last update timestamp for a strategy's PPS\n /// @param strategy Address of the strategy\n /// @return timestamp Last update timestamp\n function getLastUpdateTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @return interval Minimum time between updates\n function getMinUpdateInterval(address strategy) external view returns (uint256 interval);\n\n /// @notice Gets the maximum staleness period for a strategy\n /// @param strategy Address of the strategy\n /// @return staleness Maximum time allowed between updates\n function getMaxStaleness(address strategy) external view returns (uint256 staleness);\n\n /// @notice Gets the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @return deviationThreshold The current deviation threshold (abs diff/current ratio, scaled by 1e18)\n function getDeviationThreshold(address strategy) external view returns (uint256 deviationThreshold);\n\n /// @notice Checks if a strategy is currently paused\n /// @param strategy Address of the strategy\n /// @return isPaused True if paused, false otherwise\n function isStrategyPaused(address strategy) external view returns (bool isPaused);\n\n /// @notice Checks if a strategy's PPS is stale\n /// @dev PPS is automatically set to stale when the strategy is paused due to\n /// lack of upkeep payment in `SuperVaultAggregator`\n /// @param strategy Address of the strategy\n /// @return isStale True if stale, false otherwise\n function isPPSStale(address strategy) external view returns (bool isStale);\n\n /// @notice Gets the last unpause timestamp for a strategy\n /// @param strategy Address of the strategy\n /// @return timestamp Last unpause timestamp (0 if never unpaused)\n function getLastUnpauseTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the current upkeep balance for a strategy\n /// @param strategy Address of the strategy\n /// @return balance Current upkeep balance in upkeep tokens\n function getUpkeepBalance(address strategy) external view returns (uint256 balance);\n\n /// @notice Gets the main manager for a strategy\n /// @param strategy Address of the strategy\n /// @return manager Address of the main manager\n function getMainManager(address strategy) external view returns (address manager);\n\n /// @notice Gets pending primary manager change details\n /// @param strategy Address of the strategy\n /// @return proposedManager Address of the proposed new manager (address(0) if no pending change)\n /// @return effectiveTime Timestamp when the change can be executed (0 if no pending change)\n function getPendingManagerChange(address strategy)\n external\n view\n returns (address proposedManager, uint256 effectiveTime);\n\n /// @notice Checks if an address is the main manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isMainManager True if the address is the main manager, false otherwise\n function isMainManager(address manager, address strategy) external view returns (bool isMainManager);\n\n /// @notice Gets all secondary managers for a strategy\n /// @param strategy Address of the strategy\n /// @return secondaryManagers Array of secondary manager addresses\n function getSecondaryManagers(address strategy) external view returns (address[] memory secondaryManagers);\n\n /// @notice Checks if an address is a secondary manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isSecondaryManager True if the address is a secondary manager, false otherwise\n function isSecondaryManager(address manager, address strategy) external view returns (bool isSecondaryManager);\n\n /// @dev Internal helper function to check if an address is any kind of manager (primary or secondary)\n /// @param manager Address to check\n /// @param strategy The strategy to check against\n /// @return True if the address is either the primary manager or a secondary manager\n function isAnyManager(address manager, address strategy) external view returns (bool);\n\n /// @notice Gets all created SuperVaults\n /// @return Array of SuperVault addresses\n function getAllSuperVaults() external view returns (address[] memory);\n\n /// @notice Gets a SuperVault by index\n /// @param index The index of the SuperVault\n /// @return The SuperVault address at the given index\n function superVaults(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultStrategies\n /// @return Array of SuperVaultStrategy addresses\n function getAllSuperVaultStrategies() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultStrategy by index\n /// @param index The index of the SuperVaultStrategy\n /// @return The SuperVaultStrategy address at the given index\n function superVaultStrategies(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultEscrows\n /// @return Array of SuperVaultEscrow addresses\n function getAllSuperVaultEscrows() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultEscrow by index\n /// @param index The index of the SuperVaultEscrow\n /// @return The SuperVaultEscrow address at the given index\n function superVaultEscrows(uint256 index) external view returns (address);\n\n /// @notice Validates a hook against both global and strategy-specific Merkle roots\n /// @param strategy Address of the strategy\n /// @param args Arguments for hook validation\n /// @return isValid True if the hook is valid against either root\n function validateHook(address strategy, ValidateHookArgs calldata args) external view returns (bool isValid);\n\n /// @notice Batch validates multiple hooks against Merkle roots\n /// @param strategy Address of the strategy\n /// @param argsArray Array of hook validation arguments\n /// @return validHooks Array of booleans indicating which hooks are valid\n function validateHooks(\n address strategy,\n ValidateHookArgs[] calldata argsArray\n )\n external\n view\n returns (bool[] memory validHooks);\n\n /// @notice Gets the current global hooks Merkle root\n /// @return root The current global hooks Merkle root\n function getGlobalHooksRoot() external view returns (bytes32 root);\n\n /// @notice Gets the proposed global hooks root and effective time\n /// @return root The proposed global hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedGlobalHooksRoot() external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Checks if the global hooks root is active (timelock period has passed)\n /// @return isActive True if the global hooks root is active\n function isGlobalHooksRootActive() external view returns (bool);\n\n /// @notice Gets the hooks Merkle root for a specific strategy\n /// @param strategy Address of the strategy\n /// @return root The strategy-specific hooks Merkle root\n function getStrategyHooksRoot(address strategy) external view returns (bytes32 root);\n\n /// @notice Gets the proposed strategy hooks root and effective time\n /// @param strategy Address of the strategy\n /// @return root The proposed strategy hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedStrategyHooksRoot(address strategy) external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Gets the total number of SuperVaults\n /// @return count The total number of SuperVaults\n function getSuperVaultsCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultStrategies\n /// @return count The total number of SuperVaultStrategies\n function getSuperVaultStrategiesCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultEscrows\n /// @return count The total number of SuperVaultEscrows\n function getSuperVaultEscrowsCount() external view returns (uint256);\n}\n"},"src/libraries/AssetMetadataLib.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/interfaces/IERC20Metadata.sol\";\n\n/// @title AssetMetadataLib\n/// @author Superform Labs\n/// @notice Library for handling ERC20 metadata operations\nlibrary AssetMetadataLib {\n error INVALID_ASSET();\n\n /**\n * @notice Attempts to fetch an asset's decimals\n * @dev A return value of false indicates that the attempt failed in some way\n * @param asset_ The address of the token to query\n * @return ok Boolean indicating if the operation was successful\n * @return assetDecimals The token's decimals if successful, 0 otherwise\n */\n function tryGetAssetDecimals(address asset_) internal view returns (bool ok, uint8 assetDecimals) {\n if (asset_.code.length == 0) revert INVALID_ASSET();\n\n (bool success, bytes memory encodedDecimals) =\n address(asset_).staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));\n if (success && encodedDecimals.length >= 32) {\n uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n if (returnedDecimals <= type(uint8).max) {\n // casting to 'uint8' is safe because the returned decimals is a valid uint8\n // forge-lint: disable-next-line(unsafe-typecast)\n return (true, uint8(returnedDecimals));\n }\n }\n return (false, 0);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Create2.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)\n\npragma solidity ^0.8.20;\n\nimport {Errors} from \"./Errors.sol\";\n\n/**\n * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.\n * `CREATE2` can be used to compute in advance the address where a smart\n * contract will be deployed, which allows for interesting new mechanisms known\n * as 'counterfactual interactions'.\n *\n * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more\n * information.\n */\nlibrary Create2 {\n /**\n * @dev There's no code to deploy.\n */\n error Create2EmptyBytecode();\n\n /**\n * @dev Deploys a contract using `CREATE2`. The address where the contract\n * will be deployed can be known in advance via {computeAddress}.\n *\n * The bytecode for a contract can be obtained from Solidity with\n * `type(contractName).creationCode`.\n *\n * Requirements:\n *\n * - `bytecode` must not be empty.\n * - `salt` must have not been used for `bytecode` already.\n * - the factory must have a balance of at least `amount`.\n * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.\n */\n function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {\n if (address(this).balance < amount) {\n revert Errors.InsufficientBalance(address(this).balance, amount);\n }\n if (bytecode.length == 0) {\n revert Create2EmptyBytecode();\n }\n assembly (\"memory-safe\") {\n addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)\n // if no address was created, and returndata is not empty, bubble revert\n if and(iszero(addr), not(iszero(returndatasize()))) {\n let p := mload(0x40)\n returndatacopy(p, 0, returndatasize())\n revert(p, returndatasize())\n }\n }\n if (addr == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the\n * `bytecodeHash` or `salt` will result in a new destination address.\n */\n function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {\n return computeAddress(salt, bytecodeHash, address(this));\n }\n\n /**\n * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at\n * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.\n */\n function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40) // Get free memory pointer\n\n // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |\n // |-------------------|---------------------------------------------------------------------------|\n // | bytecodeHash | CCCCCCCCCCCCC...CC |\n // | salt | BBBBBBBBBBBBB...BB |\n // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |\n // | 0xFF | FF |\n // |-------------------|---------------------------------------------------------------------------|\n // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |\n // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |\n\n mstore(add(ptr, 0x40), bytecodeHash)\n mstore(add(ptr, 0x20), salt)\n mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes\n let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff\n mstore8(start, 0xff)\n addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Errors.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of common custom errors used in multiple contracts\n *\n * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.\n * It is recommended to avoid relying on the error API for critical functionality.\n *\n * _Available since v5.1._\n */\nlibrary Errors {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error InsufficientBalance(uint256 balance, uint256 needed);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedCall();\n\n /**\n * @dev The deployment failed.\n */\n error FailedDeployment();\n\n /**\n * @dev A necessary precompile is missing.\n */\n error MissingPrecompile(address);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Arrays.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n using SlotDerivation for bytes32;\n using StorageSlot for bytes32;\n\n /**\n * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n uint256[] memory array,\n function(uint256, uint256) pure returns (bool) comp\n ) internal pure returns (uint256[] memory) {\n _quickSort(_begin(array), _end(array), comp);\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n */\n function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n sort(array, Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of address (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n address[] memory array,\n function(address, address) pure returns (bool) comp\n ) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of address in increasing order.\n */\n function sort(address[] memory array) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n bytes32[] memory array,\n function(bytes32, bytes32) pure returns (bool) comp\n ) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n */\n function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n * at end (exclusive). Sorting follows the `comp` comparator.\n *\n * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n *\n * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n * be used only if the limits are within a memory array.\n */\n function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n unchecked {\n if (end - begin < 0x40) return;\n\n // Use first element as pivot\n uint256 pivot = _mload(begin);\n // Position where the pivot should be at the end of the loop\n uint256 pos = begin;\n\n for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n if (comp(_mload(it), pivot)) {\n // If the value stored at the iterator's position comes before the pivot, we increment the\n // position of the pivot and move the value there.\n pos += 0x20;\n _swap(pos, it);\n }\n }\n\n _swap(begin, pos); // Swap pivot into place\n _quickSort(begin, pos, comp); // Sort the left side of the pivot\n _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first element of `array`.\n */\n function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := add(array, 0x20)\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n * that comes just after the last element of the array.\n */\n function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n unchecked {\n return _begin(array) + array.length * 0x20;\n }\n }\n\n /**\n * @dev Load memory word (as a uint256) at location `ptr`.\n */\n function _mload(uint256 ptr) private pure returns (uint256 value) {\n assembly {\n value := mload(ptr)\n }\n }\n\n /**\n * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n */\n function _swap(uint256 ptr1, uint256 ptr2) private pure {\n assembly {\n let value1 := mload(ptr1)\n let value2 := mload(ptr2)\n mstore(ptr1, value2)\n mstore(ptr2, value1)\n }\n }\n\n /// @dev Helper: low level cast address memory array to uint256 memory array\n function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast address comp function to uint256 comp function\n function _castToUint256Comp(\n function(address, address) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n function _castToUint256Comp(\n function(bytes32, bytes32) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /**\n * @dev Searches a sorted `array` and returns the first index that contains\n * a value greater or equal to `element`. If no such index exists (i.e. all\n * values in the array are strictly less than `element`), the array length is\n * returned. Time complexity O(log n).\n *\n * NOTE: The `array` is expected to be sorted in ascending order, and to\n * contain no repeated elements.\n *\n * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n * support for repeated elements in the array. The {lowerBound} function should\n * be used instead.\n */\n function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n return low - 1;\n } else {\n return low;\n }\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value greater or equal than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n */\n function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value strictly greater than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n */\n function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {lowerBound}, but with an array in memory.\n */\n function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {upperBound}, but with an array in memory.\n */\n function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getAddressSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytes32Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getUint256Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytesSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getStringSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(address[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(string[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/Hashes.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library of standard hash functions.\n *\n * _Available since v5.1._\n */\nlibrary Hashes {\n /**\n * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.\n *\n * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].\n */\n function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {\n return a < b ? efficientKeccak256(a, b) : efficientKeccak256(b, a);\n }\n\n /**\n * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.\n */\n function efficientKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32 value) {\n assembly (\"memory-safe\") {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS\n }\n\n /**\n * @dev The signature derives the `address(0)`.\n */\n error ECDSAInvalidSignature();\n\n /**\n * @dev The signature has an invalid length.\n */\n error ECDSAInvalidSignatureLength(uint256 length);\n\n /**\n * @dev The signature has an S value that is in the upper half order.\n */\n error ECDSAInvalidSignatureS(bytes32 s);\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n * and a bytes32 providing additional information about the error.\n *\n * If no error is returned, then the address can be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n */\n function tryRecover(\n bytes32 hash,\n bytes memory signature\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly (\"memory-safe\") {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n unchecked {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n // We do not check for an overflow here since the shift operation results in 0 or 1.\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n */\n function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS, s);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature, bytes32(0));\n }\n\n return (signer, RecoverError.NoError, bytes32(0));\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n */\n function _throwError(RecoverError error, bytes32 errorArg) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert ECDSAInvalidSignature();\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert ECDSAInvalidSignatureLength(uint256(errorArg));\n } else if (error == RecoverError.InvalidSignatureS) {\n revert ECDSAInvalidSignatureS(errorArg);\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reinitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n *\n * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n */\n function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n return INITIALIZABLE_STORAGE;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n bytes32 slot = _initializableStorageSlot();\n assembly {\n $.slot := slot\n }\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant NOT_ENTERED = 1;\n uint256 private constant ENTERED = 2;\n\n /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n struct ReentrancyGuardStorage {\n uint256 _status;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n assembly {\n $.slot := ReentrancyGuardStorageLocation\n }\n }\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if ($._status == ENTERED) {\n revert ReentrancyGuardReentrantCall();\n }\n\n // Any calls to nonReentrant after this point will fail\n $._status = ENTERED;\n }\n\n function _nonReentrantAfter() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n return $._status == ENTERED;\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {IERC20Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC-20\n * applications.\n */\nabstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {\n /// @custom:storage-location erc7201:openzeppelin.storage.ERC20\n struct ERC20Storage {\n mapping(address account => uint256) _balances;\n\n mapping(address account => mapping(address spender => uint256)) _allowances;\n\n uint256 _totalSupply;\n\n string _name;\n string _symbol;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC20\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;\n\n function _getERC20Storage() private pure returns (ERC20Storage storage $) {\n assembly {\n $.slot := ERC20StorageLocation\n }\n }\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * Both values are immutable: they can only be set once during construction.\n */\n function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __ERC20_init_unchained(name_, symbol_);\n }\n\n function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n ERC20Storage storage $ = _getERC20Storage();\n $._name = name_;\n $._symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual returns (string memory) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual returns (string memory) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual returns (uint8) {\n return 18;\n }\n\n /// @inheritdoc IERC20\n function totalSupply() public view virtual returns (uint256) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._totalSupply;\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address account) public view virtual returns (uint256) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `value`.\n */\n function transfer(address to, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, value);\n return true;\n }\n\n /// @inheritdoc IERC20\n function allowance(address owner, address spender) public view virtual returns (uint256) {\n ERC20Storage storage $ = _getERC20Storage();\n return $._allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Skips emitting an {Approval} event indicating an allowance update. This is not\n * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `value`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `value`.\n */\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, value);\n _transfer(from, to, value);\n return true;\n }\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _transfer(address from, address to, uint256 value) internal {\n if (from == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n if (to == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(from, to, value);\n }\n\n /**\n * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n * this function.\n *\n * Emits a {Transfer} event.\n */\n function _update(address from, address to, uint256 value) internal virtual {\n ERC20Storage storage $ = _getERC20Storage();\n if (from == address(0)) {\n // Overflow check required: The rest of the code assumes that totalSupply never overflows\n $._totalSupply += value;\n } else {\n uint256 fromBalance = $._balances[from];\n if (fromBalance < value) {\n revert ERC20InsufficientBalance(from, fromBalance, value);\n }\n unchecked {\n // Overflow not possible: value <= fromBalance <= totalSupply.\n $._balances[from] = fromBalance - value;\n }\n }\n\n if (to == address(0)) {\n unchecked {\n // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n $._totalSupply -= value;\n }\n } else {\n unchecked {\n // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n $._balances[to] += value;\n }\n }\n\n emit Transfer(from, to, value);\n }\n\n /**\n * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n * Relies on the `_update` mechanism\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _mint(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(address(0), account, value);\n }\n\n /**\n * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n * Relies on the `_update` mechanism.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead\n */\n function _burn(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n _update(account, address(0), value);\n }\n\n /**\n * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n *\n * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n */\n function _approve(address owner, address spender, uint256 value) internal {\n _approve(owner, spender, value, true);\n }\n\n /**\n * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n *\n * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n * `Approval` event during `transferFrom` operations.\n *\n * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n * true using the following override:\n *\n * ```solidity\n * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n * super._approve(owner, spender, value, true);\n * }\n * ```\n *\n * Requirements are the same as {_approve}.\n */\n function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n ERC20Storage storage $ = _getERC20Storage();\n if (owner == address(0)) {\n revert ERC20InvalidApprover(address(0));\n }\n if (spender == address(0)) {\n revert ERC20InvalidSpender(address(0));\n }\n $._allowances[owner][spender] = value;\n if (emitEvent) {\n emit Approval(owner, spender, value);\n }\n }\n\n /**\n * @dev Updates `owner`'s allowance for `spender` based on spent `value`.\n *\n * Does not update the allowance value in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Does not emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance < type(uint256).max) {\n if (currentAllowance < value) {\n revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n }\n unchecked {\n _approve(owner, spender, currentAllowance - value, false);\n }\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.20;\n\nimport {MessageHashUtils} from \"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol\";\nimport {IERC5267} from \"@openzeppelin/contracts/interfaces/IERC5267.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: The upgradeable version of this contract does not use an immutable cache and recomputes the domain separator\n * each time {_domainSeparatorV4} is called. That is cheaper than accessing a cached version in cold storage.\n */\nabstract contract EIP712Upgradeable is Initializable, IERC5267 {\n bytes32 private constant TYPE_HASH =\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n /// @custom:storage-location erc7201:openzeppelin.storage.EIP712\n struct EIP712Storage {\n /// @custom:oz-renamed-from _HASHED_NAME\n bytes32 _hashedName;\n /// @custom:oz-renamed-from _HASHED_VERSION\n bytes32 _hashedVersion;\n\n string _name;\n string _version;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.EIP712\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;\n\n function _getEIP712Storage() private pure returns (EIP712Storage storage $) {\n assembly {\n $.slot := EIP712StorageLocation\n }\n }\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n EIP712Storage storage $ = _getEIP712Storage();\n $._name = name;\n $._version = version;\n\n // Reset prior values in storage if upgrading\n $._hashedName = 0;\n $._hashedVersion = 0;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n return _buildDomainSeparator();\n }\n\n function _buildDomainSeparator() private view returns (bytes32) {\n return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\n /// @inheritdoc IERC5267\n function eip712Domain()\n public\n view\n virtual\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n )\n {\n EIP712Storage storage $ = _getEIP712Storage();\n // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized\n // and the EIP712 domain is not reliable, as it will be missing name and version.\n require($._hashedName == 0 && $._hashedVersion == 0, \"EIP712: Uninitialized\");\n\n return (\n hex\"0f\", // 01111\n _EIP712Name(),\n _EIP712Version(),\n block.chainid,\n address(this),\n bytes32(0),\n new uint256[](0)\n );\n }\n\n /**\n * @dev The name parameter for the EIP712 domain.\n *\n * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n * are a concern.\n */\n function _EIP712Name() internal view virtual returns (string memory) {\n EIP712Storage storage $ = _getEIP712Storage();\n return $._name;\n }\n\n /**\n * @dev The version parameter for the EIP712 domain.\n *\n * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n * are a concern.\n */\n function _EIP712Version() internal view virtual returns (string memory) {\n EIP712Storage storage $ = _getEIP712Storage();\n return $._version;\n }\n\n /**\n * @dev The hash of the name parameter for the EIP712 domain.\n *\n * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.\n */\n function _EIP712NameHash() internal view returns (bytes32) {\n EIP712Storage storage $ = _getEIP712Storage();\n string memory name = _EIP712Name();\n if (bytes(name).length > 0) {\n return keccak256(bytes(name));\n } else {\n // If the name is empty, the contract may have been upgraded without initializing the new storage.\n // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.\n bytes32 hashedName = $._hashedName;\n if (hashedName != 0) {\n return hashedName;\n } else {\n return keccak256(\"\");\n }\n }\n }\n\n /**\n * @dev The hash of the version parameter for the EIP712 domain.\n *\n * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.\n */\n function _EIP712VersionHash() internal view returns (bytes32) {\n EIP712Storage storage $ = _getEIP712Storage();\n string memory version = _EIP712Version();\n if (bytes(version).length > 0) {\n return keccak256(bytes(version));\n } else {\n // If the version is empty, the contract may have been upgraded without initializing the new storage.\n // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.\n bytes32 hashedVersion = $._hashedVersion;\n if (hashedVersion != 0) {\n return hashedVersion;\n } else {\n return keccak256(\"\");\n }\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n"},"src/interfaces/SuperVault/ISuperVault.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { IERC7540Redeem, IERC7540CancelRedeem } from \"../../vendor/standards/ERC7540/IERC7540Vault.sol\";\nimport { IERC7741 } from \"../../vendor/standards/ERC7741/IERC7741.sol\";\n\n/// @title ISuperVault\n/// @notice Interface for SuperVault core contract that manages share minting\n/// @author Superform Labs\ninterface ISuperVault is IERC4626, IERC7540Redeem, IERC7741, IERC7540CancelRedeem {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INVALID_ASSET();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n error INVALID_AMOUNT();\n error UNAUTHORIZED();\n error DEADLINE_PASSED();\n error INVALID_SIGNATURE();\n error NOT_IMPLEMENTED();\n error INVALID_NONCE();\n error INVALID_WITHDRAW_PRICE();\n error INVALID_CONTROLLER();\n error CONTROLLER_MUST_EQUAL_OWNER();\n error RECEIVER_MUST_EQUAL_CONTROLLER();\n error NOT_ENOUGH_ASSETS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event NonceInvalidated(address indexed sender, bytes32 indexed nonce);\n\n event SuperGovernorSet(address indexed superGovernor);\n\n event Initialized(address indexed asset, address indexed strategy, address indexed escrow);\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Burn shares, only callable by strategy\n /// @param amount The amount of shares to burn\n function burnShares(uint256 amount) external;\n\n /// @notice Get the amount of assets escrowed\n function getEscrowedAssets() external view returns (uint256);\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get the escrow address\n function escrow() external view returns (address);\n}\n"},"src/vendor/standards/ERC7540/IERC7540Vault.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport { IERC7741 } from \"../ERC7741/IERC7741.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller) external view returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller) external view returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7540CancelDeposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 assets);\n}\n\n//IERC7887Redeem\ninterface IERC7540CancelRedeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 shares);\n}\n\n/**\n * @title IERC7540\n * @dev Fully async ERC7540 implementation according to the standard\n * @dev Adapted from Centrifuge's IERC7540 implementation\n */\ninterface IERC7540 is IERC7540Deposit, IERC7540Redeem { }\n\n/**\n * @title IERC7540Vault\n * @dev This is the specific set of interfaces used by the SuperVaults\n */\ninterface IERC7540Vault is IERC7540, IERC7741 {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n}\n"},"src/vendor/standards/ERC7741/IERC7741.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n )\n external\n returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},"src/vendor/standards/ERC7575/IERC7575.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC7575 is IERC165 {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n event Withdraw(\n address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the address of the share token\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function share() external view returns (address shareTokenAddress);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"src/interfaces/SuperVault/ISuperVaultEscrow.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperVaultEscrow\n/// @notice Interface for SuperVault escrow contract that holds shares during request/claim process\n/// @author Superform Labs\ninterface ISuperVaultEscrow {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error ALREADY_INITIALIZED();\n error UNAUTHORIZED();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when escrow is initialized\n /// @param vault The vault contract address\n event Initialized(address indexed vault);\n\n /// @notice Emitted when shares are transferred to escrow\n /// @param from The address shares were transferred from\n /// @param amount The amount of shares escrowed\n event SharesEscrowed(address indexed from, uint256 amount);\n\n /// @notice Emitted when shares are returned from escrow\n /// @param to The address shares were returned to\n /// @param amount The amount of shares returned\n event SharesReturned(address indexed to, uint256 amount);\n\n /// @notice Emitted when assets are returned from escrow\n /// @param to The address assets were returned to\n /// @param amount The amount of assets returned\n event AssetsReturned(address indexed to, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initialize the escrow with required parameters\n /// @param vaultAddress The vault contract address\n function initialize(address vaultAddress) external;\n\n /*//////////////////////////////////////////////////////////////\n VAULT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Transfer shares from user to escrow during redeem request\n /// @param from The address to transfer shares from\n /// @param amount The amount of shares to transfer\n function escrowShares(address from, uint256 amount) external;\n\n /// @notice Return shares from escrow to user during redeem cancellation\n /// @param to The address to return shares to\n /// @param amount The amount of shares to return\n function returnShares(address to, uint256 amount) external;\n\n /// @notice Return assets from escrow to vault during deposit cancellation\n /// @param to The address to return assets to\n /// @param amount The amount of assets to return\n function returnAssets(address to, uint256 amount) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"lib/v2-core/lib/solady/src/utils/LibSort.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Optimized sorts and operations for sorted arrays.\n/// @author Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibSort.sol)\nlibrary LibSort {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INSERTION SORT */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // - Faster on small arrays (32 or lesser elements).\n // - Faster on almost sorted arrays.\n // - Smaller bytecode (about 300 bytes smaller than sort, which uses intro-quicksort).\n // - May be suitable for view functions intended for off-chain querying.\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(a) // Length of `a`.\n mstore(a, 0) // For insertion sort's inner loop to terminate.\n let h := add(a, shl(5, n)) // High slot.\n let w := not(0x1f)\n for { let i := add(a, 0x20) } 1 {} {\n i := add(i, 0x20)\n if gt(i, h) { break }\n let k := mload(i) // Key.\n let j := add(i, w) // The slot before the current slot.\n let v := mload(j) // The value of `j`.\n if iszero(gt(v, k)) { continue }\n for {} 1 {} {\n mstore(add(j, 0x20), v)\n j := add(j, w) // `sub(j, 0x20)`.\n v := mload(j)\n if iszero(gt(v, k)) { break }\n }\n mstore(add(j, 0x20), k)\n }\n mstore(a, n) // Restore the length of `a`.\n }\n }\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(int256[] memory a) internal pure {\n _flipSign(a);\n insertionSort(_toUints(a));\n _flipSign(a);\n }\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(address[] memory a) internal pure {\n insertionSort(_toUints(a));\n }\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(bytes32[] memory a) internal pure {\n insertionSort(_toUints(a));\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTRO-QUICKSORT */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // - Faster on larger arrays (more than 32 elements).\n // - Robust performance.\n // - Larger bytecode.\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n function swap(a_, b_) -> _a, _b {\n _b := a_\n _a := b_\n }\n function mswap(i_, j_) {\n let t_ := mload(i_)\n mstore(i_, mload(j_))\n mstore(j_, t_)\n }\n function sortInner(w_, l_, h_) {\n // Do insertion sort if `h_ - l_ <= 0x20 * 12`.\n // Threshold is fine-tuned via trial and error.\n if iszero(gt(sub(h_, l_), 0x180)) {\n // Hardcode sort the first 2 elements.\n let i_ := add(l_, 0x20)\n if iszero(lt(mload(l_), mload(i_))) { mswap(i_, l_) }\n for {} 1 {} {\n i_ := add(i_, 0x20)\n if gt(i_, h_) { break }\n let k_ := mload(i_) // Key.\n let j_ := add(i_, w_) // The slot before the current slot.\n let v_ := mload(j_) // The value of `j_`.\n if iszero(gt(v_, k_)) { continue }\n for {} 1 {} {\n mstore(add(j_, 0x20), v_)\n j_ := add(j_, w_)\n v_ := mload(j_)\n if iszero(gt(v_, k_)) { break }\n }\n mstore(add(j_, 0x20), k_)\n }\n leave\n }\n // Pivot slot is the average of `l_` and `h_`.\n let p_ := add(shl(5, shr(6, add(l_, h_))), and(31, l_))\n // Median of 3 with sorting.\n {\n let e0_ := mload(l_)\n let e1_ := mload(p_)\n if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) }\n let e2_ := mload(h_)\n if iszero(lt(e1_, e2_)) {\n e1_, e2_ := swap(e1_, e2_)\n if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) }\n }\n mstore(h_, e2_)\n mstore(p_, e1_)\n mstore(l_, e0_)\n }\n // Hoare's partition.\n {\n // The value of the pivot slot.\n let x_ := mload(p_)\n p_ := h_\n for { let i_ := l_ } 1 {} {\n for {} 1 {} {\n i_ := add(0x20, i_)\n if iszero(gt(x_, mload(i_))) { break }\n }\n let j_ := p_\n for {} 1 {} {\n j_ := add(w_, j_)\n if iszero(lt(x_, mload(j_))) { break }\n }\n p_ := j_\n if iszero(lt(i_, p_)) { break }\n mswap(i_, p_)\n }\n }\n if iszero(eq(add(p_, 0x20), h_)) { sortInner(w_, add(p_, 0x20), h_) }\n if iszero(eq(p_, l_)) { sortInner(w_, l_, p_) }\n }\n\n for { let n := mload(a) } iszero(lt(n, 2)) {} {\n let w := not(0x1f) // `-0x20`.\n let l := add(a, 0x20) // Low slot.\n let h := add(a, shl(5, n)) // High slot.\n let j := h\n // While `mload(j - 0x20) <= mload(j): j -= 0x20`.\n for {} iszero(gt(mload(add(w, j)), mload(j))) {} { j := add(w, j) }\n // If the array is already sorted, break.\n if iszero(gt(j, l)) { break }\n // While `mload(j - 0x20) >= mload(j): j -= 0x20`.\n for { j := h } iszero(lt(mload(add(w, j)), mload(j))) {} { j := add(w, j) }\n // If the array is reversed sorted.\n if iszero(gt(j, l)) {\n for {} 1 {} {\n let t := mload(l)\n mstore(l, mload(h))\n mstore(h, t)\n h := add(w, h)\n l := add(l, 0x20)\n if iszero(lt(l, h)) { break }\n }\n break\n }\n mstore(a, 0) // For insertion sort's inner loop to terminate.\n sortInner(w, l, h)\n mstore(a, n) // Restore the length of `a`.\n break\n }\n }\n }\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(int256[] memory a) internal pure {\n _flipSign(a);\n sort(_toUints(a));\n _flipSign(a);\n }\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(address[] memory a) internal pure {\n sort(_toUints(a));\n }\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(bytes32[] memory a) internal pure {\n sort(_toUints(a));\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* OTHER USEFUL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance, the `uniquifySorted` methods will not revert if the\n // array is not sorted -- it will simply remove consecutive duplicate elements.\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n // If the length of `a` is greater than 1.\n if iszero(lt(mload(a), 2)) {\n let x := add(a, 0x20)\n let y := add(a, 0x40)\n let end := add(a, shl(5, add(mload(a), 1)))\n for {} 1 {} {\n if iszero(eq(mload(x), mload(y))) {\n x := add(x, 0x20)\n mstore(x, mload(y))\n }\n y := add(y, 0x20)\n if eq(y, end) { break }\n }\n mstore(a, shr(5, sub(x, a)))\n }\n }\n }\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(int256[] memory a) internal pure {\n uniquifySorted(_toUints(a));\n }\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(address[] memory a) internal pure {\n uniquifySorted(_toUints(a));\n }\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(bytes32[] memory a) internal pure {\n uniquifySorted(_toUints(a));\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(uint256[] memory a, uint256 needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(a, needle, 0);\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(int256[] memory a, int256 needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255);\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(address[] memory a, address needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(_toUints(a), uint160(needle), 0);\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(bytes32[] memory a, bytes32 needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(_toUints(a), uint256(needle), 0);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(uint256[] memory a, uint256 needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(int256[] memory a, int256 needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(address[] memory a, address needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(bytes32[] memory a, bytes32 needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Reverses the array in-place.\n function reverse(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(mload(a), 2)) {\n let s := 0x20\n let w := not(0x1f)\n let h := add(a, shl(5, mload(a)))\n for { a := add(a, s) } 1 {} {\n let t := mload(a)\n mstore(a, mload(h))\n mstore(h, t)\n h := add(h, w)\n a := add(a, s)\n if iszero(lt(a, h)) { break }\n }\n }\n }\n }\n\n /// @dev Reverses the array in-place.\n function reverse(int256[] memory a) internal pure {\n reverse(_toUints(a));\n }\n\n /// @dev Reverses the array in-place.\n function reverse(address[] memory a) internal pure {\n reverse(_toUints(a));\n }\n\n /// @dev Reverses the array in-place.\n function reverse(bytes32[] memory a) internal pure {\n reverse(_toUints(a));\n }\n\n /// @dev Returns a copy of the array.\n function copy(uint256[] memory a) internal pure returns (uint256[] memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let end := add(add(result, 0x20), shl(5, mload(a)))\n let o := result\n for { let d := sub(a, result) } 1 {} {\n mstore(o, mload(add(o, d)))\n o := add(0x20, o)\n if eq(o, end) { break }\n }\n mstore(0x40, o)\n }\n }\n\n /// @dev Returns a copy of the array.\n function copy(int256[] memory a) internal pure returns (int256[] memory result) {\n result = _toInts(copy(_toUints(a)));\n }\n\n /// @dev Returns a copy of the array.\n function copy(address[] memory a) internal pure returns (address[] memory result) {\n result = _toAddresses(copy(_toUints(a)));\n }\n\n /// @dev Returns a copy of the array.\n function copy(bytes32[] memory a) internal pure returns (bytes32[] memory result) {\n result = _toBytes32s(copy(_toUints(a)));\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(uint256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := iszero(gt(p, mload(a)))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(int256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := iszero(sgt(p, mload(a)))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(address[] memory a) internal pure returns (bool result) {\n result = isSorted(_toUints(a));\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(bytes32[] memory a) internal pure returns (bool result) {\n result = isSorted(_toUints(a));\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := lt(p, mload(a))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := slt(p, mload(a))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) {\n result = isSortedAndUniquified(_toUints(a));\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(bytes32[] memory a) internal pure returns (bool result) {\n result = isSortedAndUniquified(_toUints(a));\n }\n\n /// @dev Returns the sorted set difference of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(uint256[] memory a, uint256[] memory b)\n internal\n pure\n returns (uint256[] memory c)\n {\n c = _difference(a, b, 0);\n }\n\n /// @dev Returns the sorted set difference between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(int256[] memory a, int256[] memory b)\n internal\n pure\n returns (int256[] memory c)\n {\n c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255));\n }\n\n /// @dev Returns the sorted set difference between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(address[] memory a, address[] memory b)\n internal\n pure\n returns (address[] memory c)\n {\n c = _toAddresses(_difference(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set difference between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(bytes32[] memory a, bytes32[] memory b)\n internal\n pure\n returns (bytes32[] memory c)\n {\n c = _toBytes32s(_difference(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(uint256[] memory a, uint256[] memory b)\n internal\n pure\n returns (uint256[] memory c)\n {\n c = _intersection(a, b, 0);\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(int256[] memory a, int256[] memory b)\n internal\n pure\n returns (int256[] memory c)\n {\n c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255));\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(address[] memory a, address[] memory b)\n internal\n pure\n returns (address[] memory c)\n {\n c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(bytes32[] memory a, bytes32[] memory b)\n internal\n pure\n returns (bytes32[] memory c)\n {\n c = _toBytes32s(_intersection(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set union of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(uint256[] memory a, uint256[] memory b)\n internal\n pure\n returns (uint256[] memory c)\n {\n c = _union(a, b, 0);\n }\n\n /// @dev Returns the sorted set union of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(int256[] memory a, int256[] memory b)\n internal\n pure\n returns (int256[] memory c)\n {\n c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255));\n }\n\n /// @dev Returns the sorted set union between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(address[] memory a, address[] memory b)\n internal\n pure\n returns (address[] memory c)\n {\n c = _toAddresses(_union(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set union between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(bytes32[] memory a, bytes32[] memory b)\n internal\n pure\n returns (bytes32[] memory c)\n {\n c = _toBytes32s(_union(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Cleans the upper 96 bits of the addresses.\n /// In case `a` is produced via assembly and might have dirty upper bits.\n function clean(address[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n let addressMask := shr(96, not(0))\n for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} {\n a := add(a, 0x20)\n mstore(a, and(mload(a), addressMask))\n }\n }\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(uint256[] memory keys, uint256[] memory values) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n function mswap(i_, j_) {\n let t_ := mload(i_)\n mstore(i_, mload(j_))\n mstore(j_, t_)\n }\n function sortInner(l_, h_, d_) {\n let p_ := mload(l_)\n let j_ := l_\n for { let i_ := add(l_, 0x20) } 1 {} {\n if lt(mload(i_), p_) {\n j_ := add(j_, 0x20)\n mswap(i_, j_)\n mswap(add(i_, d_), add(j_, d_))\n }\n i_ := add(0x20, i_)\n if iszero(lt(i_, h_)) { break }\n }\n mswap(l_, j_)\n mswap(add(l_, d_), add(j_, d_))\n if iszero(gt(add(0x40, l_), j_)) { sortInner(l_, j_, d_) }\n if iszero(gt(add(0x60, j_), h_)) { sortInner(add(j_, 0x20), h_, d_) }\n }\n let n := mload(values)\n if iszero(eq(mload(keys), n)) {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, 0x32) // Array out of bounds panic if the arrays lengths differ.\n revert(0x1c, 0x24)\n }\n if iszero(lt(n, 2)) {\n let d := sub(values, keys)\n let x := add(keys, 0x20)\n let end := add(x, shl(5, n))\n sortInner(x, end, d)\n let s := mload(add(x, d))\n for { let y := add(keys, 0x40) } 1 {} {\n if iszero(eq(mload(x), mload(y))) {\n mstore(add(x, d), s) // Write sum.\n s := 0\n x := add(x, 0x20)\n mstore(x, mload(y))\n }\n s := add(s, mload(add(y, d)))\n if lt(s, mload(add(y, d))) {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, 0x11) // Overflow panic if the addition overflows.\n revert(0x1c, 0x24)\n }\n y := add(y, 0x20)\n if eq(y, end) { break }\n }\n mstore(add(x, d), s) // Write sum.\n mstore(keys, shr(5, sub(x, keys))) // Truncate.\n mstore(values, mload(keys)) // Truncate.\n }\n }\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(address[] memory keys, uint256[] memory values) internal pure {\n groupSum(_toUints(keys), values);\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(bytes32[] memory keys, uint256[] memory values) internal pure {\n groupSum(_toUints(keys), values);\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(int256[] memory keys, uint256[] memory values) internal pure {\n groupSum(_toUints(keys), values);\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(uint256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n function p(i_, x_) -> _y {\n _y := or(shr(i_, x_), x_)\n }\n let n := mload(a)\n if iszero(lt(n, 2)) {\n let m := mload(0x40) // Use free memory temporarily for hashmap.\n let w := not(0x1f) // `-0x20`.\n let c := and(w, p(16, p(8, p(4, p(2, p(1, mul(0x30, n)))))))\n calldatacopy(m, calldatasize(), add(0x20, c)) // Zeroize hashmap.\n for { let i := add(a, shl(5, n)) } 1 {} {\n // See LibPRNG for explanation of this formula.\n let r := mulmod(mload(i), 0x100000000000000000000000000000051, not(0xbc))\n // Linear probing.\n for {} 1 { r := add(0x20, r) } {\n let o := add(m, and(r, c)) // Non-zero pointer into hashmap.\n if iszero(mload(o)) {\n mstore(o, i) // Store non-zero pointer into hashmap.\n break\n }\n if eq(mload(mload(o)), mload(i)) {\n result := 1\n i := a // To break the outer loop.\n break\n }\n }\n i := add(i, w) // Iterate `a` backwards.\n if iszero(lt(a, i)) { break }\n }\n if shr(31, n) { invalid() } // Just in case.\n }\n }\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(address[] memory a) internal pure returns (bool) {\n return hasDuplicate(_toUints(a));\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(bytes32[] memory a) internal pure returns (bool) {\n return hasDuplicate(_toUints(a));\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(int256[] memory a) internal pure returns (bool) {\n return hasDuplicate(_toUints(a));\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Reinterpret cast to an uint256 array.\n function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an uint256 array.\n function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n // As any address written to memory will have the upper 96 bits\n // of the word zeroized (as per Solidity spec), we can directly\n // compare these addresses as if they are whole uint256 words.\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an uint256 array.\n function _toUints(bytes32[] memory a) private pure returns (uint256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an int array.\n function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an address array.\n function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an bytes32 array.\n function _toBytes32s(uint256[] memory a) private pure returns (bytes32[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Converts an array of signed integers to unsigned\n /// integers suitable for sorting or vice versa.\n function _flipSign(int256[] memory a) private pure {\n /// @solidity memory-safe-assembly\n assembly {\n let q := shl(255, 1)\n for { let i := add(a, shl(5, mload(a))) } iszero(eq(a, i)) {} {\n mstore(i, add(mload(i), q))\n i := sub(i, 0x20)\n }\n }\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed)\n private\n pure\n returns (bool found, uint256 index)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0)\n let l := 1\n let h := mload(a)\n let t := 0\n for { needle := add(signed, needle) } 1 {} {\n index := shr(1, add(l, h))\n t := add(signed, mload(add(a, shl(5, index))))\n if or(gt(l, h), eq(t, needle)) { break }\n // Decide whether to search the left or right half.\n if iszero(gt(needle, t)) {\n h := add(index, w)\n continue\n }\n l := add(index, 1)\n }\n // `index` will be zero in the case of an empty array,\n // or when the value is less than the smallest value in the array.\n found := eq(t, needle)\n t := iszero(iszero(index))\n index := mul(add(index, w), t)\n found := and(found, t)\n }\n }\n\n /// @dev Returns the sorted set difference of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function _difference(uint256[] memory a, uint256[] memory b, uint256 signed)\n private\n pure\n returns (uint256[] memory c)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let s := 0x20\n let aEnd := add(a, shl(5, mload(a)))\n let bEnd := add(b, shl(5, mload(b)))\n c := mload(0x40) // Set `c` to the free memory pointer.\n a := add(a, s)\n b := add(b, s)\n let k := c\n for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {\n let u := mload(a)\n let v := mload(b)\n if iszero(xor(u, v)) {\n a := add(a, s)\n b := add(b, s)\n continue\n }\n if iszero(lt(add(u, signed), add(v, signed))) {\n b := add(b, s)\n continue\n }\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n }\n for {} iszero(gt(a, aEnd)) {} {\n k := add(k, s)\n mstore(k, mload(a))\n a := add(a, s)\n }\n mstore(c, shr(5, sub(k, c))) // Store the length of `c`.\n mstore(0x40, add(k, s)) // Allocate the memory for `c`.\n }\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed)\n private\n pure\n returns (uint256[] memory c)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let s := 0x20\n let aEnd := add(a, shl(5, mload(a)))\n let bEnd := add(b, shl(5, mload(b)))\n c := mload(0x40) // Set `c` to the free memory pointer.\n a := add(a, s)\n b := add(b, s)\n let k := c\n for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {\n let u := mload(a)\n let v := mload(b)\n if iszero(xor(u, v)) {\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n b := add(b, s)\n continue\n }\n if iszero(lt(add(u, signed), add(v, signed))) {\n b := add(b, s)\n continue\n }\n a := add(a, s)\n }\n mstore(c, shr(5, sub(k, c))) // Store the length of `c`.\n mstore(0x40, add(k, s)) // Allocate the memory for `c`.\n }\n }\n\n /// @dev Returns the sorted set union of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function _union(uint256[] memory a, uint256[] memory b, uint256 signed)\n private\n pure\n returns (uint256[] memory c)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let s := 0x20\n let aEnd := add(a, shl(5, mload(a)))\n let bEnd := add(b, shl(5, mload(b)))\n c := mload(0x40) // Set `c` to the free memory pointer.\n a := add(a, s)\n b := add(b, s)\n let k := c\n for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {\n let u := mload(a)\n let v := mload(b)\n if iszero(xor(u, v)) {\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n b := add(b, s)\n continue\n }\n if iszero(lt(add(u, signed), add(v, signed))) {\n k := add(k, s)\n mstore(k, v)\n b := add(b, s)\n continue\n }\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n }\n for {} iszero(gt(a, aEnd)) {} {\n k := add(k, s)\n mstore(k, mload(a))\n a := add(a, s)\n }\n for {} iszero(gt(b, bEnd)) {} {\n k := add(k, s)\n mstore(k, mload(b))\n b := add(b, s)\n }\n mstore(c, shr(5, sub(k, c))) // Store the length of `c`.\n mstore(0x40, add(k, s)) // Allocate the memory for `c`.\n }\n }\n}\n"},"lib/v2-core/src/interfaces/ISuperHook.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { Execution } from \"modulekit/accounts/erc7579/lib/ExecutionLib.sol\";\n\n/**\n * @title SuperHook System\n * @author Superform Labs\n * @notice The hook system provides a modular and composable way to execute operations on assets\n * @dev The hook system architecture consists of several interfaces that work together:\n * - ISuperHook: The base interface all hooks implement, with lifecycle methods\n * - ISuperHookResult: Provides execution results and output information\n * - Specialized interfaces (ISuperHookOutflow, ISuperHookLoans, etc.) for specific behaviors\n *\n * Hooks are executed in sequence, where each hook can access the results from previous hooks.\n * The three main types of hooks are:\n * - NONACCOUNTING: Utility hooks that don't update the accounting system\n * - INFLOW: Hooks that process deposits or additions to positions\n * - OUTFLOW: Hooks that process withdrawals or reductions to positions\n */\ninterface ISuperLockableHook {\n /// @notice The vault bank address used to lock SuperPositions\n /// @dev Only relevant for cross-chain operations where positions are locked\n /// @return The vault bank address, or address(0) if not applicable\n function vaultBank() external view returns (address);\n\n /// @notice The destination chain ID for cross-chain operations\n /// @dev Used to identify the target chain for cross-chain position transfers\n /// @return The destination chain ID, or 0 if not a cross-chain operation\n function dstChainId() external view returns (uint256);\n}\n\ninterface ISuperHookSetter {\n /// @notice Sets the output amount for the hook\n /// @dev Used for updating `outAmount` when fees were deducted\n /// @param outAmount The amount of tokens processed by the hook\n /// @param caller The caller address for context identification\n function setOutAmount(uint256 outAmount, address caller) external;\n}\n/// @title ISuperHookInspector\n/// @author Superform Labs\n/// @notice Interface for the SuperHookInspector contract that manages hook inspection\n\ninterface ISuperHookInspector {\n /// @notice Inspect the hook\n /// @param data The hook data to inspect\n /// @return argsEncoded The arguments of the hook encoded\n function inspect(bytes calldata data) external view returns (bytes memory argsEncoded);\n}\n\n/// @title ISuperHookResult\n/// @author Superform Labs\n/// @notice Interface that exposes the result of a hook execution\n/// @dev All hooks must implement this interface to provide standardized access to execution results.\n/// These results are used by subsequent hooks in the execution chain and by the executor.\ninterface ISuperHookResult {\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The type of hook\n /// @dev Used to determine how accounting should process this hook's results\n /// @return The hook type (NONACCOUNTING, INFLOW, or OUTFLOW)\n function hookType() external view returns (ISuperHook.HookType);\n\n /// @notice The SuperPosition (SP) token associated with this hook\n /// @dev For vault hooks, this would be the tokenized position representing shares\n /// @return The address of the SP token, or address(0) if not applicable\n function spToken() external view returns (address);\n\n /// @notice The underlying asset token being processed\n /// @dev For most hooks, this is the actual token being deposited or withdrawn\n /// @return The address of the asset token, or address(0) for native assets\n function asset() external view returns (address);\n\n /// @notice The amount of tokens processed by the hook in a given caller context, subject to fees after update\n /// @dev This is the primary output value used by subsequent hooks\n /// @param caller The caller address for context identification\n /// @return The amount of tokens (assets or shares) processed\n function getOutAmount(address caller) external view returns (uint256);\n}\n\n/// @title ISuperHookContextAware\n/// @author Superform Labs\n/// @notice Interface for hooks that can use previous hook results in their execution\n/// @dev Enables contextual awareness and data flow between hooks in a chain\ninterface ISuperHookContextAware {\n /// @notice Determines if this hook should use the amount from the previous hook\n /// @dev Used to create hook chains where output from one hook becomes input to the next\n /// @param data The hook-specific data containing configuration\n /// @return True if the hook should use the previous hook's output amount\n function decodeUsePrevHookAmount(bytes memory data) external pure returns (bool);\n}\n\n/// @title ISuperHookInflowOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that handle both inflows and outflows\n/// @dev Provides standardized amount extraction for both deposit and withdrawal operations\ninterface ISuperHookInflowOutflow {\n /// @notice Extracts the amount from the hook's calldata\n /// @dev Used to determine the quantity of assets or shares being processed\n /// @param data The hook-specific calldata containing the amount\n /// @return The amount of tokens to process\n function decodeAmount(bytes memory data) external pure returns (uint256);\n}\n\n/// @title ISuperHookOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that specifically handle outflows (withdrawals)\n/// @dev Provides additional functionality needed only for outflow operations\ninterface ISuperHookOutflow {\n /// @notice Replace the amount in the calldata\n /// @param data The data to replace the amount in\n /// @param amount The amount to replace\n /// @return data The data with the replaced amount\n function replaceCalldataAmount(bytes memory data, uint256 amount) external pure returns (bytes memory);\n}\n\n/// @title ISuperHookResultOutflow\n/// @author Superform Labs\n/// @notice Extended result interface for outflow hook operations\n/// @dev Extends the base result interface with outflow-specific information\ninterface ISuperHookResultOutflow is ISuperHookResult {\n /// @notice The amount of shares consumed during outflow processing\n /// @dev Used for cost basis calculation in the accounting system\n /// @return The amount of shares consumed from the user's position\n function usedShares() external view returns (uint256);\n}\n\n/// @title ISuperHookLoans\n/// @author Superform Labs\n/// @notice Interface for hooks that interact with lending protocols\n/// @dev Extends context awareness to enable loan operations within hook chains\ninterface ISuperHookLoans is ISuperHookContextAware {\n /// @notice Gets the address of the token being borrowed\n /// @dev Used to identify which asset is being borrowed from the lending protocol\n /// @param data The hook-specific data containing loan information\n /// @return The address of the borrowed token\n function getLoanTokenAddress(bytes memory data) external pure returns (address);\n\n /// @notice Gets the address of the token used as collateral\n /// @dev Used to identify which asset is being used to secure the loan\n /// @param data The hook-specific data containing collateral information\n /// @return The address of the collateral token\n function getCollateralTokenAddress(bytes memory data) external view returns (address);\n\n /// @notice Gets the current loan token balance for an account\n /// @dev Used to track outstanding loan amounts\n /// @param account The account to check the loan balance for\n /// @param data The hook-specific data containing loan parameters\n /// @return The amount of tokens currently borrowed\n function getLoanTokenBalance(address account, bytes memory data) external view returns (uint256);\n\n /// @notice Gets the current collateral token balance for an account\n /// @dev Used to track collateral positions\n /// @param account The account to check the collateral balance for\n /// @param data The hook-specific data containing collateral parameters\n /// @return The amount of tokens currently used as collateral\n function getCollateralTokenBalance(address account, bytes memory data) external view returns (uint256);\n}\n\n/// @title ISuperHookAsyncCancelations\n/// @author Superform Labs\n/// @notice Interface for hooks that can cancel asynchronous operations\n/// @dev Used to handle cancellation of pending operations that haven't completed\ninterface ISuperHookAsyncCancelations {\n /// @notice Types of cancellations that can be performed\n /// @dev Distinguishes between different operation types that can be canceled\n enum CancelationType {\n NONE, // Not a cancelation hook\n INFLOW, // Cancels a pending deposit operation\n OUTFLOW // Cancels a pending withdrawal operation\n\n }\n\n /// @notice Identifies the type of async operation this hook can cancel\n /// @dev Used to verify the hook is appropriate for the operation being canceled\n /// @return asyncType The type of cancellation this hook performs\n function isAsyncCancelHook() external pure returns (CancelationType asyncType);\n}\n\n/// @title ISuperHook\n/// @author Superform Labs\n/// @notice The core hook interface that all hooks must implement\n/// @dev Defines the lifecycle methods and execution flow for the hook system\n/// Hooks are executed in sequence with results passed between them\ninterface ISuperHook {\n /*//////////////////////////////////////////////////////////////\n\n ENUMS\n //////////////////////////////////////////////////////////////*/\n /// @notice Defines the possible types of hooks in the system\n /// @dev Used to determine how the hook affects accounting and what operations it performs\n enum HookType {\n NONACCOUNTING, // Hook doesn't affect accounting (e.g., a swap or bridge)\n INFLOW, // Hook processes deposits or positions being added\n OUTFLOW // Hook processes withdrawals or positions being removed\n\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Builds the execution array for the hook operation\n /// @dev This is the core method where hooks define their on-chain interactions\n /// The returned executions are a sequence of contract calls to perform\n /// No state changes should occur in this method\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform executions for (usually an ERC7579 account)\n /// @param data The hook-specific parameters and configuration data\n /// @return executions Array of Execution structs defining calls to make\n function build(\n address prevHook,\n address account,\n bytes calldata data\n )\n external\n view\n returns (Execution[] memory executions);\n\n /*//////////////////////////////////////////////////////////////\n PUBLIC METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Prepares the hook for execution\n /// @dev Called before the main execution, used to validate inputs and set execution context\n /// This method may perform state changes to set up the hook's execution state\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform operations for\n /// @param data The hook-specific parameters and configuration data\n function preExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Finalizes the hook after execution\n /// @dev Called after the main execution, used to update hook state and calculate results\n /// Sets output values (outAmount, usedShares, etc.) for subsequent hooks\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account operations were performed for\n /// @param data The hook-specific parameters and configuration data\n function postExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Returns the specific subtype identification for this hook\n /// @dev Used to categorize hooks beyond the basic HookType\n /// For example, a hook might be of type INFLOW but subtype VAULT_DEPOSIT\n /// @return A bytes32 identifier for the specific hook functionality\n function subtype() external view returns (bytes32);\n\n /// @notice Resets hook mutexes\n /// @param caller The caller address for context identification\n function resetExecutionState(address caller) external;\n\n /// @notice Sets the caller address that initiated the execution\n /// @dev Used for security validation between preExecute and postExecute calls\n /// @param caller The caller address for context identification\n function setExecutionContext(address caller) external;\n\n /// @notice Returns the execution nonce for the current execution context\n /// @dev Used to ensure unique execution contexts and prevent replay attacks\n /// @return The execution nonce\n function executionNonce() external view returns (uint256);\n\n /// @notice Returns the last caller registered by `setExecutionContext`\n /// @return The last caller address\n function lastCaller() external view returns (address);\n}\n"},"lib/v2-core/src/libraries/HookDataDecoder.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { BytesLib } from \"../vendor/BytesLib.sol\";\n\n/// @title HookDataDecoder\n/// @author Superform Labs\n/// @notice Library for decoding hook data\nlibrary HookDataDecoder {\n function extractYieldSourceOracleId(bytes memory data) internal pure returns (bytes32) {\n return bytes32(BytesLib.slice(data, 0, 32));\n }\n\n function extractYieldSource(bytes memory data) internal pure returns (address) {\n return BytesLib.toAddress(data, 32);\n }\n}\n"},"src/libraries/SuperVaultAccountingLib.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n/// @title SuperVaultAccountingLib\n/// @author Superform Labs\n/// @notice Stateless library for SuperVault accounting calculations\n/// @dev All functions are pure for easy auditing and testing\nlibrary SuperVaultAccountingLib {\n using Math for uint256;\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INSUFFICIENT_LIQUIDITY();\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n uint256 private constant BPS_PRECISION = 10_000;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Compute minimum acceptable assets (slippage floor)\n /// @param requestedShares Number of shares being redeemed\n /// @param averageRequestPPS PPS at time of request (slippage anchor)\n /// @param slippageBps User's slippage tolerance in basis points\n /// @param precision Precision constant for PPS calculations\n /// @return minAssetsOut User's minimum acceptable assets\n function computeMinNetOut(\n uint256 requestedShares,\n uint256 averageRequestPPS,\n uint16 slippageBps,\n uint256 precision\n )\n internal\n pure\n returns (uint256 minAssetsOut)\n {\n uint256 expectedAssets = requestedShares.mulDiv(averageRequestPPS, precision, Math.Rounding.Floor);\n minAssetsOut = expectedAssets.mulDiv(BPS_PRECISION - slippageBps, BPS_PRECISION, Math.Rounding.Floor);\n }\n\n /// @notice Calculate updated average withdraw price\n /// @param currentMaxWithdraw Current max withdrawable assets\n /// @param currentAverageWithdrawPrice Current average withdraw price\n /// @param requestedShares New shares being fulfilled\n /// @param fulfilledAssets Assets received from fulfilling the redeem request\n /// @param precision Precision constant\n /// @return newAverageWithdrawPrice Updated average withdraw price\n function calculateAverageWithdrawPrice(\n uint256 currentMaxWithdraw,\n uint256 currentAverageWithdrawPrice,\n uint256 requestedShares,\n uint256 fulfilledAssets,\n uint256 precision\n )\n internal\n pure\n returns (uint256 newAverageWithdrawPrice)\n {\n uint256 existingShares;\n uint256 existingAssets;\n\n if (currentMaxWithdraw > 0 && currentAverageWithdrawPrice > 0) {\n existingShares = currentMaxWithdraw.mulDiv(precision, currentAverageWithdrawPrice, Math.Rounding.Floor);\n existingAssets = currentMaxWithdraw;\n }\n\n uint256 newTotalShares = existingShares + requestedShares;\n uint256 newTotalAssets = existingAssets + fulfilledAssets;\n\n if (newTotalShares > 0) {\n newAverageWithdrawPrice = newTotalAssets.mulDiv(precision, newTotalShares, Math.Rounding.Floor);\n }\n\n return newAverageWithdrawPrice;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Comparators.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n function lt(uint256 a, uint256 b) internal pure returns (bool) {\n return a < b;\n }\n\n function gt(uint256 a, uint256 b) internal pure returns (bool) {\n return a > b;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using StorageSlot for bytes32;\n * using SlotDerivation for bytes32;\n *\n * // Declare a namespace\n * string private constant _NAMESPACE = \"\"; // eg. OpenZeppelin.Slot\n *\n * function setValueInNamespace(uint256 key, address newValue) internal {\n * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n * }\n *\n * function getValueInNamespace(uint256 key) internal view returns (address) {\n * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n /**\n * @dev Derive an ERC-7201 slot from a string (namespace).\n */\n function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n assembly (\"memory-safe\") {\n mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n slot := and(keccak256(0x00, 0x20), not(0xff))\n }\n }\n\n /**\n * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n */\n function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n unchecked {\n return bytes32(uint256(slot) + pos);\n }\n }\n\n /**\n * @dev Derive the location of the first element in an array from the slot where the length is stored.\n */\n function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, slot)\n result := keccak256(0x00, 0x20)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, and(key, shr(96, not(0))))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, iszero(iszero(key)))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)\npragma solidity >=0.8.4;\n\n/**\n * @dev Standard ERC-20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.\n */\ninterface IERC20Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC20InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC20InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n * @param allowance Amount of tokens a `spender` is allowed to operate with.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC20InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC-721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.\n */\ninterface IERC721Errors {\n /**\n * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.\n * Used in balance queries.\n * @param owner Address of the current owner of a token.\n */\n error ERC721InvalidOwner(address owner);\n\n /**\n * @dev Indicates a `tokenId` whose `owner` is the zero address.\n * @param tokenId Identifier number of a token.\n */\n error ERC721NonexistentToken(uint256 tokenId);\n\n /**\n * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param tokenId Identifier number of a token.\n * @param owner Address of the current owner of a token.\n */\n error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC721InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC721InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param tokenId Identifier number of a token.\n */\n error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC721InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC-1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.\n */\ninterface IERC1155Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n * @param tokenId Identifier number of a token.\n */\n error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC1155InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC1155InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param owner Address of the current owner of a token.\n */\n error ERC1155MissingApprovalForAll(address operator, address owner);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC1155InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC1155InvalidOperator(address operator);\n\n /**\n * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n * Used in batch transfers.\n * @param idsLength Length of the array of token identifiers\n * @param valuesLength Length of the array of token amounts\n */\n error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing a bytes32 `messageHash` with\n * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n * keccak256, although any bytes32 value can be safely used because the final digest will\n * be re-hashed.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing an arbitrary `message` with\n * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n return\n keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x00` (data with intended validator).\n *\n * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n * `validator` address. Then hashing the result.\n *\n * See {ECDSA-recover}.\n */\n function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n }\n\n /**\n * @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.\n */\n function toDataWithIntendedValidatorHash(\n address validator,\n bytes32 messageHash\n ) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, hex\"19_00\")\n mstore(0x02, shl(96, validator))\n mstore(0x16, messageHash)\n digest := keccak256(0x00, 0x36)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).\n *\n * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n *\n * See {ECDSA-recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n mstore(ptr, hex\"19_01\")\n mstore(add(ptr, 0x02), domainSeparator)\n mstore(add(ptr, 0x22), structHash)\n digest := keccak256(ptr, 0x42)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)\n\npragma solidity >=0.4.16;\n\ninterface IERC5267 {\n /**\n * @dev MAY be emitted to signal that the domain could have changed.\n */\n event EIP712DomainChanged();\n\n /**\n * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n * signature.\n */\n function eip712Domain()\n external\n view\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n );\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n// Types\nimport { Execution } from \"../../common/interfaces/IERC7579Account.sol\";\n\n/**\n * Helper Library for decoding Execution calldata\n * malloc for memory allocation is bad for gas. use this assembly instead\n */\nlibrary ExecutionLib {\n error ERC7579DecodingError();\n\n /**\n * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.\n * @dev code is copied from solady's LibERC7579.sol\n * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146\n * Credits to Vectorized and the Solady Team\n */\n function decodeBatch(bytes calldata executionCalldata)\n internal\n pure\n returns (Execution[] calldata executionBatch)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let u := calldataload(executionCalldata.offset)\n let s := add(executionCalldata.offset, u)\n let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)\n executionBatch.offset := add(s, 0x20)\n executionBatch.length := calldataload(s)\n if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if executionBatch.length {\n // Perform bounds checks on the decoded `executionBatch`.\n // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.\n for { let i := executionBatch.length } 1 { } {\n i := sub(i, 1)\n let p := calldataload(add(executionBatch.offset, shl(5, i)))\n let c := add(executionBatch.offset, p)\n let q := calldataload(add(c, 0x40))\n let o := add(c, q)\n // forgefmt: disable-next-item\n if or(shr(64, or(calldataload(o), or(p, q))),\n or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if iszero(i) { break }\n }\n }\n }\n }\n\n function encodeBatch(Execution[] memory executions)\n internal\n pure\n returns (bytes memory callData)\n {\n callData = abi.encode(executions);\n }\n\n function decodeSingle(bytes calldata executionCalldata)\n internal\n pure\n returns (address target, uint256 value, bytes calldata callData)\n {\n target = address(bytes20(executionCalldata[0:20]));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n function encodeSingle(\n address target,\n uint256 value,\n bytes memory callData\n )\n internal\n pure\n returns (bytes memory userOpCalldata)\n {\n userOpCalldata = abi.encodePacked(target, value, callData);\n }\n}\n"},"lib/v2-core/src/vendor/BytesLib.sol":{"content":"// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity 0.8.30;\n\nlibrary BytesLib {\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for { let cc := add(_postBytes, 0x20) } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(\n sc,\n add(\n and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),\n and(mload(mc), mask)\n )\n )\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } { sstore(sc, mload(mc)) }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } { sstore(sc, mload(mc)) }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n // We're using the unchecked block below because otherwise execution ends\n // with the native overflow error code.\n unchecked {\n require(_length + 31 >= _length, \"slice_overflow\");\n }\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for { let cc := add(_postBytes, 0x20) }\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for { } eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Strings.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SafeCast} from \"./math/SafeCast.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n using SafeCast for *;\n\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n uint8 private constant ADDRESS_LENGTH = 20;\n uint256 private constant SPECIAL_CHARS_LOOKUP =\n (1 << 0x08) | // backspace\n (1 << 0x09) | // tab\n (1 << 0x0a) | // newline\n (1 << 0x0c) | // form feed\n (1 << 0x0d) | // carriage return\n (1 << 0x22) | // double quote\n (1 << 0x5c); // backslash\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n /**\n * @dev The string being parsed contains characters that are not in scope of the given base.\n */\n error StringsInvalidChar();\n\n /**\n * @dev The string being parsed is not a properly formatted address.\n */\n error StringsInvalidAddressFormat();\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n assembly (\"memory-safe\") {\n ptr := add(add(buffer, 0x20), length)\n }\n while (true) {\n ptr--;\n assembly (\"memory-safe\") {\n mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toStringSigned(int256 value) internal pure returns (string memory) {\n return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n * representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal\n * representation, according to EIP-55.\n */\n function toChecksumHexString(address addr) internal pure returns (string memory) {\n bytes memory buffer = bytes(toHexString(addr));\n\n // hash the hex part of buffer (skip length + 2 bytes, length 40)\n uint256 hashValue;\n assembly (\"memory-safe\") {\n hashValue := shr(96, keccak256(add(buffer, 0x22), 40))\n }\n\n for (uint256 i = 41; i > 1; --i) {\n // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)\n if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {\n // case shift by xoring with 0x20\n buffer[i] ^= 0x20;\n }\n hashValue >>= 4;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `bytes` buffer to its ASCII `string` hexadecimal representation.\n */\n function toHexString(bytes memory input) internal pure returns (string memory) {\n unchecked {\n bytes memory buffer = new bytes(2 * input.length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 0; i < input.length; ++i) {\n uint8 v = uint8(input[i]);\n buffer[2 * i + 2] = HEX_DIGITS[v >> 4];\n buffer[2 * i + 3] = HEX_DIGITS[v & 0xf];\n }\n return string(buffer);\n }\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input) internal pure returns (uint256) {\n return parseUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n uint256 result = 0;\n for (uint256 i = begin; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 9) return (false, 0);\n result *= 10;\n result += chr;\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `int256`.\n *\n * Requirements:\n * - The string must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input) internal pure returns (int256) {\n return parseInt(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {\n (bool success, int256 value) = tryParseInt(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if\n * the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {\n return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);\n }\n\n uint256 private constant ABS_MIN_INT256 = 2 ** 255;\n\n /**\n * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character or if the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, int256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseIntUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseIntUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, int256 value) {\n bytes memory buffer = bytes(input);\n\n // Check presence of a negative sign.\n bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n bool positiveSign = sign == bytes1(\"+\");\n bool negativeSign = sign == bytes1(\"-\");\n uint256 offset = (positiveSign || negativeSign).toUint();\n\n (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);\n\n if (absSuccess && absValue < ABS_MIN_INT256) {\n return (true, negativeSign ? -int256(absValue) : int256(absValue));\n } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {\n return (true, type(int256).min);\n } else return (false, 0);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input) internal pure returns (uint256) {\n return parseHexUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseHexUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an\n * invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseHexUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseHexUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n // skip 0x prefix if present\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 offset = hasPrefix.toUint() * 2;\n\n uint256 result = 0;\n for (uint256 i = begin + offset; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 15) return (false, 0);\n result *= 16;\n unchecked {\n // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).\n // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.\n result += chr;\n }\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as an `address`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input) internal pure returns (address) {\n return parseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {\n (bool success, address value) = tryParseAddress(input, begin, end);\n if (!success) revert StringsInvalidAddressFormat();\n return value;\n }\n\n /**\n * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly\n * formatted address. See {parseAddress-string} requirements.\n */\n function tryParseAddress(string memory input) internal pure returns (bool success, address value) {\n return tryParseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly\n * formatted address. See {parseAddress-string-uint256-uint256} requirements.\n */\n function tryParseAddress(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, address value) {\n if (end > bytes(input).length || begin > end) return (false, address(0));\n\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 expectedLength = 40 + hasPrefix.toUint() * 2;\n\n // check that input is the correct length\n if (end - begin == expectedLength) {\n // length guarantees that this does not overflow, and value is at most type(uint160).max\n (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);\n return (s, address(uint160(v)));\n } else {\n return (false, address(0));\n }\n }\n\n function _tryParseChr(bytes1 chr) private pure returns (uint8) {\n uint8 value = uint8(chr);\n\n // Try to parse `chr`:\n // - Case 1: [0-9]\n // - Case 2: [a-f]\n // - Case 3: [A-F]\n // - otherwise not supported\n unchecked {\n if (value > 47 && value < 58) value -= 48;\n else if (value > 96 && value < 103) value -= 87;\n else if (value > 64 && value < 71) value -= 55;\n else return type(uint8).max;\n }\n\n return value;\n }\n\n /**\n * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.\n *\n * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.\n *\n * NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of\n * RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode\n * characters that are not in this range, but other tooling may provide different results.\n */\n function escapeJSON(string memory input) internal pure returns (string memory) {\n bytes memory buffer = bytes(input);\n bytes memory output = new bytes(2 * buffer.length); // worst case scenario\n uint256 outputLength = 0;\n\n for (uint256 i; i < buffer.length; ++i) {\n bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));\n if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {\n output[outputLength++] = \"\\\\\";\n if (char == 0x08) output[outputLength++] = \"b\";\n else if (char == 0x09) output[outputLength++] = \"t\";\n else if (char == 0x0a) output[outputLength++] = \"n\";\n else if (char == 0x0c) output[outputLength++] = \"f\";\n else if (char == 0x0d) output[outputLength++] = \"r\";\n else if (char == 0x5c) output[outputLength++] = \"\\\\\";\n else if (char == 0x22) {\n // solhint-disable-next-line quotes\n output[outputLength++] = '\"';\n }\n } else {\n output[outputLength++] = char;\n }\n }\n // write the actual length and deallocate unused memory\n assembly (\"memory-safe\") {\n mstore(output, outputLength)\n mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))\n }\n\n return string(output);\n }\n\n /**\n * @dev Reads a bytes32 from a bytes array without bounds checking.\n *\n * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the\n * assembly block as such would prevent some optimizations.\n */\n function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {\n // This is not memory safe in the general case, but all calls to this private function are within bounds.\n assembly (\"memory-safe\") {\n value := mload(add(add(buffer, 0x20), offset))\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n/* solhint-disable no-unused-import */\n\n// Types\nimport { CallType, ExecType, ModeCode } from \"../lib/ModeLib.sol\";\n\n// Structs\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\ninterface IERC7579Account {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by ERC-4337 EntryPoint.sol\n * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @dev Ensure adequate authorization control: i.e. onlyExecutorModule\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function executeFromExecutor(\n ModeCode mode,\n bytes calldata executionCalldata\n )\n external\n payable\n returns (bytes[] memory returnData);\n\n /**\n * @dev ERC-1271 isValidSignature\n * This function is intended to be used to validate a smart account signature\n * and may forward the call to a validator module\n *\n * @param hash The hash of the data that is signed\n * @param data The data that is signed\n */\n function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);\n\n /**\n * @dev installs a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be required on the module during `onInstall`\n * initialization.\n */\n function installModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata initData\n )\n external\n payable;\n\n /**\n * @dev uninstalls a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be required on the module during `onUninstall`\n * de-initialization.\n */\n function uninstallModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata deInitData\n )\n external\n payable;\n\n /**\n * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)\n * @param encodedMode the encoded mode\n */\n function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);\n\n /**\n * Function to check if the account supports installation of a certain module type Id\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n\n /**\n * Function to check if the account has a certain module installed\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * Note: keep in mind that some contracts can be multiple module types at the same time. It\n * thus may be necessary to query multiple module types\n * @param module the module address\n * @param additionalContext additional context data that the smart account may interpret to\n * identifiy conditions under which the module is installed.\n * usually this is not necessary, but for some special hooks that\n * are stored in mappings, this param might be needed\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n )\n external\n view\n returns (bool);\n\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n * the accountId should be structured like so:\n * \"vendorname.accountname.semver\"\n */\n function accountId() external view returns (string memory accountImplementationId);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));\n }\n }\n\n /**\n * @dev Returns the largest of two signed numbers.\n */\n function max(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two signed numbers.\n */\n function min(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two signed numbers without overflow.\n * The result is rounded towards zero.\n */\n function average(int256 a, int256 b) internal pure returns (int256) {\n // Formula from the book \"Hacker's Delight\"\n int256 x = (a & b) + ((a ^ b) >> 1);\n return x + (int256(uint256(x) >> 255) & (a ^ b));\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // Formula from the \"Bit Twiddling Hacks\" by Sean Eron Anderson.\n // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,\n // taking advantage of the most significant (or \"sign\" bit) in two's complement representation.\n // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,\n // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).\n int256 mask = n >> 255;\n\n // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.\n return uint256((n + mask) ^ mask);\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/lib/ModeLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title ModeLib\n * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat)\n * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode\n * encoding is used.\n * Function Signature of execute function:\n * function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and\n * context.\n * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that\n * implement\n * more complex execution modes may use the entire bytes32.\n *\n * |--------------------------------------------------------------------|\n * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload |\n * |--------------------------------------------------------------------|\n * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes |\n * |--------------------------------------------------------------------|\n *\n * CALLTYPE: 1 byte\n * CallType is used to determine how the executeCalldata paramter of the execute function has to be\n * decoded.\n * It can be either single, batch or delegatecall. In the future different calls could be added.\n * CALLTYPE can be used by a validation module to determine how to decode .\n *\n * EXECTYPE: 1 byte\n * ExecType is used to determine how the account should handle the execution.\n * It can indicate if the execution should revert on failure or continue execution.\n * In the future more execution modes may be added.\n * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in\n * a batch fails, the entire batch is reverted\n *\n * UNUSED: 4 bytes\n * Unused bytes are reserved for future use.\n *\n * ModeSelector: bytes4\n * The \"optional\" mode selector can be used by account vendors, to implement custom behavior in\n * their accounts.\n * the way a ModeSelector is to be calculated is bytes4(keccak256(\"vendorname.featurename\"))\n * this is to prevent collisions between different vendors, while allowing innovation and the\n * development of new features without coordination between ERC-7579 implementing accounts\n *\n * ModePayload: 22 bytes\n * Mode payload is used to pass additional data to the smart account execution, this may be\n * interpreted depending on the ModeSelector\n *\n * ExecutionCallData: n bytes\n * single, delegatecall or batch exec abi.encoded as bytes\n */\n\n// Custom type for improved developer experience\ntype ModeCode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ModeSelector is bytes4;\n\ntype ModePayload is bytes22;\n\n// Default CallType\nCallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n// Batched CallType\nCallType constant CALLTYPE_BATCH = CallType.wrap(0x01);\nCallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);\n// @dev Implementing delegatecall is OPTIONAL!\n// implement delegatecall with extreme care.\nCallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n// @dev default behavior is to revert on failure\n// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure\n// Since this is value 0x00, no additional encoding is required for simple accounts\nExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n// @dev account may elect to change execution behavior. For example \"try exec\" / \"allow fail\"\nExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\nModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));\n// Example declaration of a custom mode selector\nModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256(\"default.mode.offset\")));\n\n/**\n * @dev ModeLib is a helper library to encode/decode ModeCodes\n */\nlibrary ModeLib {\n function decode(ModeCode mode)\n internal\n pure\n returns (\n CallType _calltype,\n ExecType _execType,\n ModeSelector _modeSelector,\n ModePayload _modePayload\n )\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _calltype := mode\n _execType := shl(8, mode)\n _modeSelector := shl(48, mode)\n _modePayload := shl(80, mode)\n }\n }\n\n function encode(\n CallType callType,\n ExecType execType,\n ModeSelector mode,\n ModePayload payload\n )\n internal\n pure\n returns (ModeCode)\n {\n return ModeCode.wrap(\n bytes32(\n abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)\n )\n );\n }\n\n function encodeSimpleBatch() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function encodeSimpleSingle() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function getCallType(ModeCode mode) internal pure returns (CallType calltype) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n calltype := mode\n }\n }\n}\n\nusing { eqModeSelector as == } for ModeSelector global;\nusing { eqCallType as == } for CallType global;\nusing { neqCallType as != } for CallType global;\nusing { eqExecType as == } for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction neqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperVaultBatchOperator.standard-json-input.json b/script/locked-bytecode-dev/SuperVaultBatchOperator.standard-json-input.json new file mode 100644 index 000000000..49ddd1f05 --- /dev/null +++ b/script/locked-bytecode-dev/SuperVaultBatchOperator.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperVault/SuperVaultBatchOperator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { AccessControl } from \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ISuperVault } from \"../interfaces/SuperVault/ISuperVault.sol\";\nimport { ISuperVaultBatchOperator } from \"../interfaces/SuperVault/ISuperVaultBatchOperator.sol\";\n\n/// @title SuperVaultBatchOperator\n/// @author Superform Labs\n/// @notice Batch operator for SuperVaults allowing batched withdrawals and redeems\n/// @dev Users must approve this contract as an operator via vault.setOperator(address(this), true)\n/// @dev Only addresses with OPERATOR_ROLE can call batch methods\ncontract SuperVaultBatchOperator is ISuperVaultBatchOperator, AccessControl {\n using SafeERC20 for IERC20;\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n bytes32 public constant OPERATOR_ROLE = keccak256(\"OPERATOR_ROLE\");\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initialize the batch operator with admin and operator\n /// @param admin The address that will have DEFAULT_ADMIN_ROLE\n /// @param operator The address that will have OPERATOR_ROLE\n constructor(address admin, address operator) {\n if (admin == address(0)) revert ZERO_ADMIN_ADDRESS();\n if (operator == address(0)) revert ZERO_OPERATOR_ADDRESS();\n\n _grantRole(DEFAULT_ADMIN_ROLE, admin);\n _grantRole(OPERATOR_ROLE, operator);\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Batch withdraw assets from multiple vaults for multiple owners\n /// @param requests The array of batch withdrawal requests\n /// @dev Requires this contract to be approved as operator for each controller on each vault\n /// @dev Individual request failures do not revert the batch - they are skipped\n function batchWithdraw(BatchRequest[] calldata requests) external override onlyRole(OPERATOR_ROLE) {\n uint256 len = requests.length;\n if (len == 0) revert EMPTY_REQUESTS();\n\n uint256 successCount;\n for (uint256 i; i < len; ++i) {\n BatchRequest calldata req = requests[i];\n\n // Skip invalid requests without reverting the batch\n if (!_isValidRequest(req)) {\n emit WithdrawRequestSkipped(i, req.vault, req.controller, req.amount);\n continue;\n }\n\n // receiver == controller is enforced on the vault side\n try ISuperVault(req.vault).withdraw(req.amount, req.controller, req.controller) {\n ++successCount;\n } catch {\n emit WithdrawFailed(i, req.vault, req.controller, req.amount);\n }\n }\n\n emit BatchWithdrawExecuted(msg.sender, successCount);\n }\n\n /// @notice Batch redeem shares from multiple vaults for multiple owners\n /// @param requests The array of batch redemption requests\n /// @dev Requires this contract to be approved as operator for each controller on each vault\n /// @dev Individual request failures do not revert the batch - they are skipped\n function batchRedeem(BatchRequest[] calldata requests) external override onlyRole(OPERATOR_ROLE) {\n uint256 len = requests.length;\n if (len == 0) revert EMPTY_REQUESTS();\n\n uint256 successCount;\n for (uint256 i; i < len; ++i) {\n BatchRequest calldata req = requests[i];\n\n // Skip invalid requests without reverting the batch\n if (!_isValidRequest(req)) {\n emit RedeemRequestSkipped(i, req.vault, req.controller, req.amount);\n continue;\n }\n\n // receiver == controller is enforced on the vault side\n try ISuperVault(req.vault).redeem(req.amount, req.controller, req.controller) {\n ++successCount;\n } catch {\n emit RedeemFailed(i, req.vault, req.controller, req.amount);\n }\n }\n\n emit BatchRedeemExecuted(msg.sender, successCount);\n }\n\n /// @notice Batch emergency withdraw tokens stuck in this contract\n /// @param tokens The array of token addresses to withdraw\n /// @param to The recipient address\n /// @dev Only callable by admin. Withdraws entire balance of each token.\n function batchEmergencyWithdraw(address[] calldata tokens, address to) external override onlyRole(DEFAULT_ADMIN_ROLE) {\n if (to == address(0)) revert ZERO_TO_ADDRESS();\n\n uint256[] memory amounts = new uint256[](tokens.length);\n\n for (uint256 i = 0; i < tokens.length; ++i) {\n address token = tokens[i];\n if (token == address(0)) revert ZERO_TOKEN_ADDRESS();\n uint256 balance = IERC20(token).balanceOf(address(this));\n amounts[i] = balance;\n if (balance > 0) {\n IERC20(token).safeTransfer(to, balance);\n }\n }\n\n emit BatchEmergencyWithdraw(tokens, to, amounts);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Checks if a batch request is valid\n /// @param req The batch request to validate\n /// @return isValid True if the request has valid parameters\n function _isValidRequest(BatchRequest calldata req) internal pure returns (bool isValid) {\n return req.vault != address(0) && req.controller != address(0) && req.amount != 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/AccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {IERC165, ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account => bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"src/interfaces/SuperVault/ISuperVault.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { IERC7540Redeem, IERC7540CancelRedeem } from \"../../vendor/standards/ERC7540/IERC7540Vault.sol\";\nimport { IERC7741 } from \"../../vendor/standards/ERC7741/IERC7741.sol\";\n\n/// @title ISuperVault\n/// @notice Interface for SuperVault core contract that manages share minting\n/// @author Superform Labs\ninterface ISuperVault is IERC4626, IERC7540Redeem, IERC7741, IERC7540CancelRedeem {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INVALID_ASSET();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n error INVALID_AMOUNT();\n error UNAUTHORIZED();\n error DEADLINE_PASSED();\n error INVALID_SIGNATURE();\n error NOT_IMPLEMENTED();\n error INVALID_NONCE();\n error INVALID_WITHDRAW_PRICE();\n error INVALID_CONTROLLER();\n error CONTROLLER_MUST_EQUAL_OWNER();\n error RECEIVER_MUST_EQUAL_CONTROLLER();\n error NOT_ENOUGH_ASSETS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event NonceInvalidated(address indexed sender, bytes32 indexed nonce);\n\n event SuperGovernorSet(address indexed superGovernor);\n\n event Initialized(address indexed asset, address indexed strategy, address indexed escrow);\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Burn shares, only callable by strategy\n /// @param amount The amount of shares to burn\n function burnShares(uint256 amount) external;\n\n /// @notice Get the amount of assets escrowed\n function getEscrowedAssets() external view returns (uint256);\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get the escrow address\n function escrow() external view returns (address);\n}\n"},"src/interfaces/SuperVault/ISuperVaultBatchOperator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperVaultBatchOperator\n/// @author Superform Labs\n/// @notice Interface for SuperVaultBatchOperator - batch withdrawal/redeem operator for SuperVaults\ninterface ISuperVaultBatchOperator {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Emitted when a batch withdrawal is executed\n /// @param caller The address that executed the batch withdrawal\n /// @param requestCount The number of withdrawal requests processed\n event BatchWithdrawExecuted(address indexed caller, uint256 requestCount);\n\n /// @notice Emitted when a batch redemption is executed\n /// @param caller The address that executed the batch redemption\n /// @param requestCount The number of redemption requests processed\n event BatchRedeemExecuted(address indexed caller, uint256 requestCount);\n\n /// @notice Emitted when a withdrawal request is skipped due to invalid parameters\n /// @param index The index of the skipped request in the batch\n /// @param vault The vault address\n /// @param controller The controller address\n /// @param amount The requested amount\n event WithdrawRequestSkipped(uint256 indexed index, address indexed vault, address controller, uint256 amount);\n\n /// @notice Emitted when a withdrawal request fails during execution\n /// @param index The index of the failed request in the batch\n /// @param vault The vault address\n /// @param controller The controller address\n /// @param amount The requested amount\n event WithdrawFailed(uint256 indexed index, address indexed vault, address controller, uint256 amount);\n\n /// @notice Emitted when a redemption request is skipped due to invalid parameters\n /// @param index The index of the skipped request in the batch\n /// @param vault The vault address\n /// @param controller The controller address\n /// @param amount The requested amount\n event RedeemRequestSkipped(uint256 indexed index, address indexed vault, address controller, uint256 amount);\n\n /// @notice Emitted when a redemption request fails during execution\n /// @param index The index of the failed request in the batch\n /// @param vault The vault address\n /// @param controller The controller address\n /// @param amount The requested amount\n event RedeemFailed(uint256 indexed index, address indexed vault, address controller, uint256 amount);\n\n /// @notice Emitted when tokens are rescued via batch emergency withdraw\n /// @param tokens The token addresses that were withdrawn\n /// @param to The recipient address\n /// @param amounts The amounts of tokens withdrawn\n event BatchEmergencyWithdraw(address[] tokens, address indexed to, uint256[] amounts);\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n error EMPTY_REQUESTS();\n error ZERO_ADMIN_ADDRESS();\n error ZERO_OPERATOR_ADDRESS();\n error ZERO_TOKEN_ADDRESS();\n error ZERO_TO_ADDRESS();\n\n /*//////////////////////////////////////////////////////////////\n TYPES\n //////////////////////////////////////////////////////////////*/\n\n struct BatchRequest {\n address vault;\n address controller; // address that controls the shares and receives assets (must have approved this operator)\n uint256 amount; // assets for withdraw, shares for redeem\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Batch withdraw assets from multiple vaults for multiple owners\n /// @param requests The array of batch withdrawal requests\n /// @dev Requires this contract to be approved as operator for each controller on each vault\n /// @dev Individual request failures do not revert the batch - they are skipped\n function batchWithdraw(BatchRequest[] calldata requests) external;\n\n /// @notice Batch redeem shares from multiple vaults for multiple owners\n /// @param requests The array of batch redemption requests\n /// @dev Requires this contract to be approved as operator for each controller on each vault\n /// @dev Individual request failures do not revert the batch - they are skipped\n function batchRedeem(BatchRequest[] calldata requests) external;\n\n /// @notice Batch emergency withdraw tokens stuck in this contract\n /// @param tokens The array of token addresses to withdraw\n /// @param to The recipient address\n /// @dev Only callable by admin. Withdraws entire balance of each token.\n function batchEmergencyWithdraw(address[] calldata tokens, address to) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"src/vendor/standards/ERC7540/IERC7540Vault.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport { IERC7741 } from \"../ERC7741/IERC7741.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller) external view returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller) external view returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7540CancelDeposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 assets);\n}\n\n//IERC7887Redeem\ninterface IERC7540CancelRedeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 shares);\n}\n\n/**\n * @title IERC7540\n * @dev Fully async ERC7540 implementation according to the standard\n * @dev Adapted from Centrifuge's IERC7540 implementation\n */\ninterface IERC7540 is IERC7540Deposit, IERC7540Redeem { }\n\n/**\n * @title IERC7540Vault\n * @dev This is the specific set of interfaces used by the SuperVaults\n */\ninterface IERC7540Vault is IERC7540, IERC7741 {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n}\n"},"src/vendor/standards/ERC7741/IERC7741.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n )\n external\n returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperVaultEscrow.standard-json-input.json b/script/locked-bytecode-dev/SuperVaultEscrow.standard-json-input.json new file mode 100644 index 000000000..add156502 --- /dev/null +++ b/script/locked-bytecode-dev/SuperVaultEscrow.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperVault/SuperVaultEscrow.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ISuperVaultEscrow } from \"../interfaces/SuperVault/ISuperVaultEscrow.sol\";\n\n/// @title SuperVaultEscrow\n/// @author Superform Labs\n/// @notice Escrow contract for SuperVault shares during request/claim process\ncontract SuperVaultEscrow is ISuperVaultEscrow {\n using SafeERC20 for IERC20;\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n bool public initialized;\n address public vault;\n\n /*//////////////////////////////////////////////////////////////\n MODIFIERS\n //////////////////////////////////////////////////////////////*/\n modifier onlyVault() {\n _onlyVault();\n _;\n }\n\n function _onlyVault() internal view {\n if (msg.sender != vault) revert UNAUTHORIZED();\n }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultEscrow\n function initialize(address vaultAddress) external {\n if (initialized) revert ALREADY_INITIALIZED();\n if (vaultAddress == address(0)) revert ZERO_ADDRESS();\n\n initialized = true;\n vault = vaultAddress;\n\n emit Initialized(vaultAddress);\n }\n\n /*//////////////////////////////////////////////////////////////\n VAULT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultEscrow\n function escrowShares(address from, uint256 amount) external onlyVault {\n if (amount == 0) revert ZERO_AMOUNT();\n IERC20(vault).safeTransferFrom(from, address(this), amount);\n emit SharesEscrowed(from, amount);\n }\n\n /// @inheritdoc ISuperVaultEscrow\n function returnShares(address to, uint256 amount) external onlyVault {\n if (amount == 0) revert ZERO_AMOUNT();\n IERC20(vault).safeTransfer(to, amount);\n emit SharesReturned(to, amount);\n }\n\n /// @inheritdoc ISuperVaultEscrow\n function returnAssets(address to, uint256 amount) external onlyVault {\n if (amount == 0) revert ZERO_AMOUNT();\n if (to == address(0)) revert ZERO_ADDRESS();\n IERC20(IERC4626(vault).asset()).safeTransfer(to, amount);\n emit AssetsReturned(to, amount);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"src/interfaces/SuperVault/ISuperVaultEscrow.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n/// @title ISuperVaultEscrow\n/// @notice Interface for SuperVault escrow contract that holds shares during request/claim process\n/// @author Superform Labs\ninterface ISuperVaultEscrow {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error ALREADY_INITIALIZED();\n error UNAUTHORIZED();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when escrow is initialized\n /// @param vault The vault contract address\n event Initialized(address indexed vault);\n\n /// @notice Emitted when shares are transferred to escrow\n /// @param from The address shares were transferred from\n /// @param amount The amount of shares escrowed\n event SharesEscrowed(address indexed from, uint256 amount);\n\n /// @notice Emitted when shares are returned from escrow\n /// @param to The address shares were returned to\n /// @param amount The amount of shares returned\n event SharesReturned(address indexed to, uint256 amount);\n\n /// @notice Emitted when assets are returned from escrow\n /// @param to The address assets were returned to\n /// @param amount The amount of assets returned\n event AssetsReturned(address indexed to, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initialize the escrow with required parameters\n /// @param vaultAddress The vault contract address\n function initialize(address vaultAddress) external;\n\n /*//////////////////////////////////////////////////////////////\n VAULT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Transfer shares from user to escrow during redeem request\n /// @param from The address to transfer shares from\n /// @param amount The amount of shares to transfer\n function escrowShares(address from, uint256 amount) external;\n\n /// @notice Return shares from escrow to user during redeem cancellation\n /// @param to The address to return shares to\n /// @param amount The amount of shares to return\n function returnShares(address to, uint256 amount) external;\n\n /// @notice Return assets from escrow to vault during deposit cancellation\n /// @param to The address to return assets to\n /// @param amount The amount of assets to return\n function returnAssets(address to, uint256 amount) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperVaultStrategy.standard-json-input.json b/script/locked-bytecode-dev/SuperVaultStrategy.standard-json-input.json new file mode 100644 index 000000000..8ba5845b7 --- /dev/null +++ b/script/locked-bytecode-dev/SuperVaultStrategy.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/SuperVault/SuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// External\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { LibSort } from \"solady/utils/LibSort.sol\";\n\n// Core Interfaces\nimport {\n ISuperHook,\n ISuperHookResult,\n ISuperHookContextAware,\n ISuperHookInspector\n} from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n// Periphery Interfaces\nimport { ISuperVault } from \"../interfaces/SuperVault/ISuperVault.sol\";\nimport { HookDataDecoder } from \"@superform-v2-core/src/libraries/HookDataDecoder.sol\";\nimport { ISuperVaultStrategy } from \"../interfaces/SuperVault/ISuperVaultStrategy.sol\";\nimport { ISuperGovernor, FeeType } from \"../interfaces/ISuperGovernor.sol\";\nimport { ISuperVaultAggregator } from \"../interfaces/SuperVault/ISuperVaultAggregator.sol\";\nimport { SuperVaultAccountingLib } from \"../libraries/SuperVaultAccountingLib.sol\";\nimport { AssetMetadataLib } from \"../libraries/AssetMetadataLib.sol\";\n\n/// @title SuperVaultStrategy\n/// @author Superform Labs\n/// @notice Strategy implementation for SuperVault that executes strategies\ncontract SuperVaultStrategy is ISuperVaultStrategy, Initializable, ReentrancyGuardUpgradeable {\n using LibSort for address[];\n\n using EnumerableSet for EnumerableSet.AddressSet;\n using SafeERC20 for IERC20;\n using Math for uint256;\n using AssetMetadataLib for address;\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n uint256 private constant BPS_PRECISION = 10_000;\n uint256 private constant MAX_PERFORMANCE_FEE = 5100; // 51% max performance fee\n\n /// @dev Default redeem slippage tolerance when user hasn't set their own (0.5%)\n uint16 public constant DEFAULT_REDEEM_SLIPPAGE_BPS = 50;\n\n /// @dev Minimum allowed staleness threshold for PPS updates (prevents too-frequent validation)\n uint256 private constant MIN_PPS_EXPIRATION_THRESHOLD = 1 minutes;\n\n /// @dev Maximum allowed staleness threshold for PPS updates (prevents indefinite stale data usage)\n uint256 private constant MAX_PPS_EXPIRATION_THRESHOLD = 1 weeks;\n\n /// @dev Timelock period after unpause during which performance fee skimming is disabled (rug prevention)\n uint256 private constant POST_UNPAUSE_SKIM_TIMELOCK = 12 hours;\n\n /// @dev Timelock duration for fee config and PPS expiration threshold updates\n uint256 private constant PROPOSAL_TIMELOCK = 1 weeks;\n\n uint256 public PRECISION; // Slot 0: 32 bytes\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n // Packed slot 1: saves 1 storage slot\n address private _vault; // 20 bytes\n uint8 private _vaultDecimals; // 1 byte\n uint88 private __gap1; // 11 bytes padding\n\n // Packed slot 2\n IERC20 private _asset; // 20 bytes (address)\n uint96 private __gap2; // 12 bytes padding\n\n // Global configuration\n\n // Fee configuration\n FeeConfig private feeConfig; // Slots 3-5 (96 bytes: 2 uint256 + 1 address)\n FeeConfig private proposedFeeConfig;\n uint256 private feeConfigEffectiveTime;\n\n // Core contracts\n ISuperGovernor public immutable SUPER_GOVERNOR;\n\n // PPS expiry threshold\n uint256 public proposedPPSExpiryThreshold;\n uint256 public ppsExpiryThresholdEffectiveTime;\n uint256 public ppsExpiration;\n\n // Yield source configuration - simplified mapping from source to oracle\n mapping(address source => address oracle) private yieldSources;\n EnumerableSet.AddressSet private yieldSourcesList;\n\n // --- Global Vault High-Water Mark (PPS-based) ---\n /// @notice High-water mark price-per-share for performance fee calculation\n /// @dev Represents the PPS at which performance fees were last collected\n /// Scaled by PRECISION (e.g., 1e6 for USDC vaults, 1e18 for 18-decimal vaults)\n /// Updated during skimPerformanceFee() when fees are taken, and in executeVaultFeeConfigUpdate()\n uint256 public vaultHwmPps;\n\n // --- Redeem Request State ---\n mapping(address controller => SuperVaultState state) private superVaultState;\n\n constructor(address superGovernor_) {\n if (superGovernor_ == address(0)) revert ZERO_ADDRESS();\n\n SUPER_GOVERNOR = ISuperGovernor(superGovernor_);\n emit SuperGovernorSet(superGovernor_);\n _disableInitializers();\n }\n\n /// @notice Allows the contract to receive native ETH\n /// @dev Required for hooks that may send ETH back to the strategy\n receive() external payable { }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external initializer {\n if (vaultAddress == address(0)) revert INVALID_VAULT();\n // if either fee is configured, check if recipient is address (0), if it is revert with ZERO ADDRESS\n // if both fees are 0, no need check address (it just passes the if). Recipient can be configured later\n if (\n (feeConfigData.performanceFeeBps > 0 || feeConfigData.managementFeeBps > 0)\n && feeConfigData.recipient == address(0)\n ) revert ZERO_ADDRESS();\n if (feeConfigData.performanceFeeBps > MAX_PERFORMANCE_FEE) revert INVALID_PERFORMANCE_FEE_BPS();\n if (feeConfigData.managementFeeBps > BPS_PRECISION) revert INVALID_PERFORMANCE_FEE_BPS();\n\n __ReentrancyGuard_init();\n\n _vault = vaultAddress;\n _asset = IERC20(IERC4626(vaultAddress).asset());\n _vaultDecimals = IERC20Metadata(vaultAddress).decimals();\n PRECISION = 10 ** _vaultDecimals;\n feeConfig = feeConfigData;\n\n ppsExpiration = 1 days;\n\n // Initialize HWM to 1.0 using asset decimals (same as aggregator)\n // Get asset decimals the same way aggregator does\n (bool success, uint8 assetDecimals) = address(_asset).tryGetAssetDecimals();\n if (!success) revert INVALID_ASSET();\n vaultHwmPps = 10 ** assetDecimals; // 1.0 as initial PPS (matches aggregator)\n\n emit Initialized(_vault);\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc ISuperVaultStrategy\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet) {\n _requireVault();\n\n if (assetsGross == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n\n if (aggregator.isGlobalHooksRootVetoed()) {\n revert OPERATIONS_BLOCKED_BY_VETO();\n }\n\n _validateStrategyState(aggregator);\n\n // Fee skim in ASSETS (asset-side entry fee)\n uint256 feeBps = feeConfig.managementFeeBps;\n uint256 feeAssets = feeBps == 0 ? 0 : Math.mulDiv(assetsGross, feeBps, BPS_PRECISION, Math.Rounding.Ceil);\n\n uint256 assetsNet = assetsGross - feeAssets;\n if (assetsNet == 0) revert INVALID_AMOUNT();\n\n if (feeAssets != 0) {\n address recipient = feeConfig.recipient;\n if (recipient == address(0)) revert ZERO_ADDRESS();\n _safeTokenTransfer(address(_asset), recipient, feeAssets);\n emit ManagementFeePaid(controller, recipient, feeAssets, feeBps);\n }\n\n // Compute shares on NET using current PPS\n uint256 pps = getStoredPPS();\n if (pps == 0) revert INVALID_PPS();\n sharesNet = Math.mulDiv(assetsNet, PRECISION, pps, Math.Rounding.Floor);\n if (sharesNet == 0) revert INVALID_AMOUNT();\n\n // No HWM update needed - deposits are PPS-neutral by design\n\n emit DepositHandled(controller, assetsNet, sharesNet);\n return sharesNet;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external\n {\n _requireVault();\n\n if (sharesNet == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n\n if (aggregator.isGlobalHooksRootVetoed()) {\n revert OPERATIONS_BLOCKED_BY_VETO();\n }\n\n _validateStrategyState(aggregator);\n\n uint256 feeBps = feeConfig.managementFeeBps;\n // Transfer fee if needed\n if (feeBps != 0) {\n uint256 feeAssets = assetsGross - assetsNet;\n if (feeAssets != 0) {\n address recipient = feeConfig.recipient;\n if (recipient == address(0)) revert ZERO_ADDRESS();\n _safeTokenTransfer(address(_asset), recipient, feeAssets);\n emit ManagementFeePaid(controller, recipient, feeAssets, feeBps);\n }\n }\n\n // No HWM update needed - mints are PPS-neutral by design\n\n emit DepositHandled(controller, assetsNet, sharesNet);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet) {\n uint256 pps = getStoredPPS();\n if (pps == 0) revert INVALID_PPS();\n assetsNet = Math.mulDiv(shares, pps, PRECISION, Math.Rounding.Ceil);\n if (assetsNet == 0) revert INVALID_AMOUNT();\n\n uint256 feeBps = feeConfig.managementFeeBps;\n if (feeBps == 0) return (assetsNet, assetsNet);\n if (feeBps >= BPS_PRECISION) revert INVALID_AMOUNT(); // prevents div-by-zero (100% fee)\n assetsGross = Math.mulDiv(assetsNet, BPS_PRECISION, (BPS_PRECISION - feeBps), Math.Rounding.Ceil);\n return (assetsGross, assetsNet);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function handleOperations7540(Operation operation, address controller, address receiver, uint256 amount) external {\n _requireVault();\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n\n if (operation == Operation.RedeemRequest) {\n _validateStrategyState(aggregator);\n _handleRequestRedeem(controller, amount); // amount = shares\n } else if (operation == Operation.ClaimCancelRedeem) {\n _handleClaimCancelRedeem(controller);\n } else if (operation == Operation.ClaimRedeem) {\n _handleClaimRedeem(controller, receiver, amount); // amount = assets\n } else if (operation == Operation.CancelRedeemRequest) {\n _handleCancelRedeemRequest(controller);\n } else {\n revert ACTION_TYPE_DISALLOWED();\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function executeHooks(ExecuteArgs calldata args) external payable nonReentrant {\n _isManager(msg.sender);\n\n uint256 hooksLength = args.hooks.length;\n if (hooksLength == 0) revert ZERO_LENGTH();\n if (args.hookCalldata.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n if (args.expectedAssetsOrSharesOut.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n if (args.globalProofs.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n if (args.strategyProofs.length != hooksLength) revert INVALID_ARRAY_LENGTH();\n\n address prevHook;\n for (uint256 i; i < hooksLength; ++i) {\n address hook = args.hooks[i];\n if (!_isRegisteredHook(hook)) revert INVALID_HOOK();\n\n // Check if the hook was validated\n if (!_validateHook(hook, args.hookCalldata[i], args.globalProofs[i], args.strategyProofs[i])) {\n revert HOOK_VALIDATION_FAILED();\n }\n\n prevHook =\n _processSingleHookExecution(hook, prevHook, args.hookCalldata[i], args.expectedAssetsOrSharesOut[i]);\n }\n emit HooksExecuted(args.hooks);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function fulfillCancelRedeemRequests(address[] memory controllers) external nonReentrant {\n _isManager(msg.sender);\n\n uint256 controllersLength = controllers.length;\n if (controllersLength == 0) revert ZERO_LENGTH();\n\n for (uint256 i; i < controllersLength; ++i) {\n SuperVaultState storage state = superVaultState[controllers[i]];\n if (state.pendingCancelRedeemRequest) {\n state.claimableCancelRedeemRequest += state.pendingRedeemRequest;\n state.pendingRedeemRequest = 0;\n state.averageRequestPPS = 0;\n emit RedeemCancelRequestFulfilled(controllers[i], state.claimableCancelRedeemRequest);\n }\n }\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function fulfillRedeemRequests(\n address[] calldata controllers,\n uint256[] calldata totalAssetsOut\n )\n external\n nonReentrant\n {\n _isManager(msg.sender);\n\n _validateStrategyState(_getSuperVaultAggregator());\n\n uint256 len = controllers.length;\n if (len == 0 || totalAssetsOut.length != len) revert INVALID_ARRAY_LENGTH();\n\n FulfillRedeemVars memory vars;\n vars.currentPPS = getStoredPPS();\n if (vars.currentPPS == 0) revert INVALID_PPS();\n\n // Process each controller with all validations in one loop\n for (uint256 i; i < len; ++i) {\n // Validate controllers are sorted and unique\n if (i > 0 && controllers[i] <= controllers[i - 1]) revert CONTROLLERS_NOT_SORTED_UNIQUE();\n\n // Load pending shares into memory and accumulate total\n uint256 pendingShares = superVaultState[controllers[i]].pendingRedeemRequest;\n vars.totalRequestedShares += pendingShares;\n\n // Disallow fulfillment for controllers with zero pending shares\n if (pendingShares == 0) revert ZERO_SHARE_FULFILLMENT_DISALLOWED();\n\n // Process fulfillment and accumulate assets\n _processExactFulfillmentBatch(controllers[i], totalAssetsOut[i], vars.currentPPS, pendingShares);\n vars.totalNetAssetsOut += totalAssetsOut[i];\n }\n\n // Balance check (no fees expected)\n vars.strategyBalance = _getTokenBalance(address(_asset), address(this));\n if (vars.strategyBalance < vars.totalNetAssetsOut) {\n revert INSUFFICIENT_LIQUIDITY();\n }\n\n // Burn shares\n ISuperVault(_vault).burnShares(vars.totalRequestedShares);\n\n // Transfer net assets to escrow\n if (vars.totalNetAssetsOut > 0) {\n _asset.safeTransfer(ISuperVault(_vault).escrow(), vars.totalNetAssetsOut);\n }\n\n emit RedeemRequestsFulfilled(controllers, vars.totalRequestedShares, vars.currentPPS);\n }\n\n /// @notice Skim performance fees based on per-share High Water Mark\n /// @dev Can be called by any manager when vault PPS has grown above HWM\n /// @dev Uses PPS-based HWM which eliminates redemption-related vulnerabilities\n function skimPerformanceFee() external nonReentrant {\n _isManager(msg.sender);\n\n ISuperVaultAggregator aggregator = _getSuperVaultAggregator();\n _validateStrategyState(aggregator);\n\n // Prevent skim for 12 hours after unpause\n // This timelock gives a detection window for potential abuse of fee skimming\n // post unpausing with an abnormal PPS update\n uint256 lastUnpause = aggregator.getLastUnpauseTimestamp(address(this));\n if (block.timestamp < lastUnpause + POST_UNPAUSE_SKIM_TIMELOCK) {\n revert SKIM_TIMELOCK_ACTIVE();\n }\n\n IERC4626 vault = IERC4626(_vault);\n uint256 totalSupplyLocal = vault.totalSupply();\n\n // Early return if no supply - cannot calculate PPS or collect fees\n if (totalSupplyLocal == 0) return;\n\n // Get current PPS from aggregator\n uint256 currentPPS = aggregator.getPPS(address(this));\n if (currentPPS == 0) revert INVALID_PPS();\n\n // Get the high-water mark PPS (baseline for fee calculation)\n uint256 hwmPps = vaultHwmPps;\n\n // Check if there's any per-share growth above HWM\n if (currentPPS <= hwmPps) {\n // No growth above HWM, no fee to collect\n return;\n }\n\n // Calculate PPS growth above HWM\n uint256 ppsGrowth = currentPPS - hwmPps;\n\n // Calculate total profit: (PPS growth) * (total shares) / PRECISION\n // This represents the total assets gained above the high-water mark\n uint256 profit = Math.mulDiv(ppsGrowth, totalSupplyLocal, PRECISION, Math.Rounding.Floor);\n\n // Safety check: profit must be non-zero to collect fees\n if (profit == 0) return;\n\n // Calculate fee as percentage of profit\n uint256 fee = Math.mulDiv(profit, feeConfig.performanceFeeBps, BPS_PRECISION, Math.Rounding.Ceil);\n\n // Edge case: profit exists but fee rounds to zero\n if (fee == 0) return;\n\n // Split fee between Superform treasury and strategy recipient\n uint256 sfFee =\n Math.mulDiv(fee, SUPER_GOVERNOR.getFee(FeeType.PERFORMANCE_FEE_SHARE), BPS_PRECISION, Math.Rounding.Floor);\n uint256 recipientFee = fee - sfFee;\n\n // Check if strategy has sufficient liquid assets for fee transfer\n if (_getTokenBalance(address(_asset), address(this)) < fee) revert NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n\n // Transfer fees to recipients\n _safeTokenTransfer(address(_asset), SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.TREASURY()), sfFee);\n _safeTokenTransfer(address(_asset), feeConfig.recipient, recipientFee);\n\n emit PerformanceFeeSkimmed(fee, sfFee);\n\n // Calculate the new PPS after fee extraction\n // Fee extraction reduces vault assets while shares stay constant, lowering PPS\n uint256 ppsReduction = Math.mulDiv(fee, PRECISION, totalSupplyLocal, Math.Rounding.Floor);\n\n // Safety check: ensure reduction doesn't crash PPS to zero\n if (ppsReduction >= currentPPS) revert INVALID_PPS();\n\n uint256 newPPS = currentPPS - ppsReduction;\n\n // Safety check: new PPS must be positive\n if (newPPS == 0) revert INVALID_PPS();\n\n // Update HWM to the new post-fee PPS\n // This becomes the new baseline for future fee calculations\n vaultHwmPps = newPPS;\n\n emit HWMPPSUpdated(newPPS, currentPPS, profit, fee);\n\n // Update PPS in aggregator to reflect fee extraction\n aggregator.updatePPSAfterSkim(newPPS, fee);\n }\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external {\n _isPrimaryManager(msg.sender);\n _manageYieldSource(source, oracle, actionType);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external\n {\n _isPrimaryManager(msg.sender);\n\n uint256 length = sources.length;\n if (length == 0) revert ZERO_LENGTH();\n if (oracles.length != length) revert INVALID_ARRAY_LENGTH();\n if (actionTypes.length != length) revert INVALID_ARRAY_LENGTH();\n\n for (uint256 i; i < length; ++i) {\n _manageYieldSource(sources[i], oracles[i], actionTypes[i]);\n }\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function changeFeeRecipient(address newRecipient) external {\n if (msg.sender != address(_getSuperVaultAggregator())) revert ACCESS_DENIED();\n\n feeConfig.recipient = newRecipient;\n emit FeeRecipientChanged(newRecipient);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external\n {\n _isPrimaryManager(msg.sender);\n\n if (performanceFeeBps > MAX_PERFORMANCE_FEE) revert INVALID_PERFORMANCE_FEE_BPS();\n if (managementFeeBps > BPS_PRECISION) revert INVALID_PERFORMANCE_FEE_BPS();\n if (recipient == address(0)) revert ZERO_ADDRESS();\n proposedFeeConfig = FeeConfig({\n performanceFeeBps: performanceFeeBps, managementFeeBps: managementFeeBps, recipient: recipient\n });\n feeConfigEffectiveTime = block.timestamp + PROPOSAL_TIMELOCK;\n emit VaultFeeConfigProposed(performanceFeeBps, managementFeeBps, recipient, feeConfigEffectiveTime);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function executeVaultFeeConfigUpdate() external {\n _isPrimaryManager(msg.sender);\n\n if (block.timestamp < feeConfigEffectiveTime) revert INVALID_TIMESTAMP();\n if (proposedFeeConfig.recipient == address(0)) revert ZERO_ADDRESS();\n\n // Get current PPS before updating fee config\n uint256 currentPPS = getStoredPPS();\n uint256 oldHwmPps = vaultHwmPps;\n\n // Update fee config\n feeConfig = proposedFeeConfig;\n delete proposedFeeConfig;\n feeConfigEffectiveTime = 0;\n\n // Reset HWM PPS to current PPS to avoid incorrect fee calculations with new fee structure\n vaultHwmPps = currentPPS;\n\n emit VaultFeeConfigUpdated(feeConfig.performanceFeeBps, feeConfig.managementFeeBps, feeConfig.recipient);\n emit HWMPPSUpdated(currentPPS, oldHwmPps, 0, 0);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function resetHighWaterMark(uint256 newHwmPps) external {\n if (msg.sender != address(_getSuperVaultAggregator())) revert ACCESS_DENIED();\n\n if (newHwmPps == 0) revert INVALID_PPS();\n\n vaultHwmPps = newHwmPps;\n\n emit HighWaterMarkReset(newHwmPps);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function managePPSExpiration(PPSExpirationAction action, uint256 staleness_) external {\n if (action == PPSExpirationAction.Propose) {\n _proposePPSExpiration(staleness_);\n } else if (action == PPSExpirationAction.Execute) {\n _updatePPSExpiration();\n } else if (action == PPSExpirationAction.Cancel) {\n _cancelPPSExpirationProposalUpdate();\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function setRedeemSlippage(uint16 slippageBps) external {\n if (slippageBps > BPS_PRECISION) revert INVALID_REDEEM_SLIPPAGE_BPS();\n\n superVaultState[msg.sender].redeemSlippageBps = slippageBps;\n\n emit RedeemSlippageSet(msg.sender, slippageBps);\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @inheritdoc ISuperVaultStrategy\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals) {\n vault = _vault;\n asset = address(_asset);\n vaultDecimals = _vaultDecimals;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getConfigInfo() external view returns (FeeConfig memory feeConfig_) {\n feeConfig_ = feeConfig;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getStoredPPS() public view returns (uint256) {\n return _getSuperVaultAggregator().getPPS(address(this));\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state) {\n return superVaultState[controller];\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSource(address source) external view returns (YieldSource memory) {\n return YieldSource({ oracle: yieldSources[source] });\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory) {\n uint256 length = yieldSourcesList.length();\n YieldSourceInfo[] memory sourcesInfo = new YieldSourceInfo[](length);\n\n for (uint256 i; i < length; ++i) {\n address sourceAddress = yieldSourcesList.at(i);\n address oracle = yieldSources[sourceAddress];\n\n sourcesInfo[i] = YieldSourceInfo({ sourceAddress: sourceAddress, oracle: oracle });\n }\n\n return sourcesInfo;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSources() external view returns (address[] memory) {\n return yieldSourcesList.values();\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getYieldSourcesCount() external view returns (uint256) {\n return yieldSourcesList.length();\n }\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n function vaultUnrealizedProfit() external view returns (uint256) {\n IERC4626 vault = IERC4626(_vault);\n uint256 totalSupplyLocal = vault.totalSupply();\n\n // No profit if no shares exist\n if (totalSupplyLocal == 0) return 0;\n\n uint256 currentPPS = _getSuperVaultAggregator().getPPS(address(this));\n\n // No profit if current PPS is at or below HWM\n if (currentPPS <= vaultHwmPps) return 0;\n\n // Calculate profit as: (PPS growth) * (shares) / PRECISION\n uint256 ppsGrowth = currentPPS - vaultHwmPps;\n return Math.mulDiv(ppsGrowth, totalSupplyLocal, PRECISION, Math.Rounding.Floor);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function containsYieldSource(address source) external view returns (bool) {\n return yieldSourcesList.contains(source);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares) {\n return superVaultState[controller].pendingRedeemRequest;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets) {\n return superVaultState[controller].maxWithdraw;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function pendingCancelRedeemRequest(address controller) external view returns (bool) {\n return superVaultState[controller].pendingCancelRedeemRequest;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares) {\n if (!superVaultState[controller].pendingCancelRedeemRequest) return 0;\n return superVaultState[controller].claimableCancelRedeemRequest;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice) {\n return superVaultState[controller].averageWithdrawPrice;\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets)\n {\n SuperVaultState memory state = superVaultState[controller];\n shares = state.pendingRedeemRequest;\n\n if (shares == 0) return (0, 0, 0);\n\n uint256 pps = getStoredPPS();\n theoreticalAssets = shares.mulDiv(pps, PRECISION, Math.Rounding.Floor);\n\n uint16 slippageBps = state.redeemSlippageBps > 0 ? state.redeemSlippageBps : DEFAULT_REDEEM_SLIPPAGE_BPS;\n\n minAssets = SuperVaultAccountingLib.computeMinNetOut(shares, state.averageRequestPPS, slippageBps, PRECISION);\n\n return (shares, theoreticalAssets, minAssets);\n }\n\n /// @inheritdoc ISuperVaultStrategy\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets)\n {\n if (controllers.length == 0) revert ZERO_LENGTH();\n\n individualAssets = new uint256[](controllers.length);\n totalTheoAssets = 0;\n\n for (uint256 i = 0; i < controllers.length; i++) {\n // Get theoretical assets for this controller\n (, uint256 theoreticalAssets,) = this.previewExactRedeem(controllers[i]);\n individualAssets[i] = theoreticalAssets;\n totalTheoAssets += theoreticalAssets;\n }\n\n return (totalTheoAssets, individualAssets);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Process a single hook execution\n /// @param hook Hook address\n /// @param prevHook Previous hook address\n /// @param hookCalldata Hook calldata\n /// @param expectedAssetsOrSharesOut Expected assets or shares output\n /// @return processedHook Processed hook address\n function _processSingleHookExecution(\n address hook,\n address prevHook,\n bytes memory hookCalldata,\n uint256 expectedAssetsOrSharesOut\n )\n internal\n returns (address)\n {\n ExecutionVars memory vars;\n vars.hookContract = ISuperHook(hook);\n\n vars.targetedYieldSource = HookDataDecoder.extractYieldSource(hookCalldata);\n\n // Bool flagging if the hook uses the previous hook's outAmount\n // No slippage checks performed here as they have already been performed in the previous hook execution\n bool usePrevHookAmount = _decodeHookUsePrevHookAmount(hook, hookCalldata);\n\n ISuperHook(address(vars.hookContract)).setExecutionContext(address(this));\n vars.executions = vars.hookContract.build(prevHook, address(this), hookCalldata);\n for (uint256 j; j < vars.executions.length; ++j) {\n // Block hooks from calling the SuperVaultAggregator directly\n address aggregatorAddr = address(_getSuperVaultAggregator());\n if (vars.executions[j].target == aggregatorAddr) revert OPERATION_FAILED();\n (vars.success,) =\n vars.executions[j].target.call{ value: vars.executions[j].value }(vars.executions[j].callData);\n if (!vars.success) revert OPERATION_FAILED();\n }\n ISuperHook(address(vars.hookContract)).resetExecutionState(address(this));\n\n uint256 actualOutput = ISuperHookResult(hook).getOutAmount(address(this));\n\n // this is not to protect the user but rather a honest manager from doing a mistake\n if (actualOutput < expectedAssetsOrSharesOut) {\n revert MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n }\n\n emit HookExecuted(hook, prevHook, vars.targetedYieldSource, usePrevHookAmount, hookCalldata);\n\n return hook;\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL REDEMPTION PROCESSING\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Process exact fulfillment for batch processing\n /// @dev Handles all accounting updates for fulfilled redemption:\n /// 1. Validates slippage bounds (minAssets <= actual <= theoretical)\n /// 2. Updates weighted average withdraw price across multiple fulfillments\n /// 3. Clears pending state and makes assets claimable\n /// 4. Resets cancellation flags\n /// @dev SECURITY: Bounds validation ensures manager cannot underfill/overfill\n /// @dev ACCOUNTING: Average withdraw price uses weighted formula to track historical execution prices\n /// @param controller Controller address\n /// @param totalAssetsOut Total assets available for this controller (from executeHooks)\n /// @param currentPPS Current price per share\n /// @param pendingShares Pending shares for this controller (passed to avoid re-reading from storage)\n function _processExactFulfillmentBatch(\n address controller,\n uint256 totalAssetsOut,\n uint256 currentPPS,\n uint256 pendingShares\n )\n internal\n {\n SuperVaultState storage state = superVaultState[controller];\n\n // Slippage validation\n uint16 slippageBps = state.redeemSlippageBps > 0 ? state.redeemSlippageBps : DEFAULT_REDEEM_SLIPPAGE_BPS;\n\n uint256 theoreticalAssets = pendingShares.mulDiv(currentPPS, PRECISION, Math.Rounding.Floor);\n\n uint256 minAssetsOut =\n SuperVaultAccountingLib.computeMinNetOut(pendingShares, state.averageRequestPPS, slippageBps, PRECISION);\n\n // Bounds check: totalAssetsOut must be between minAssetsOut and theoreticalAssets\n if (totalAssetsOut < minAssetsOut || totalAssetsOut > theoreticalAssets) {\n revert BOUNDS_EXCEEDED(minAssetsOut, theoreticalAssets, totalAssetsOut);\n }\n\n // Update average withdraw price (use actual assets received)\n state.averageWithdrawPrice = SuperVaultAccountingLib.calculateAverageWithdrawPrice(\n state.maxWithdraw, state.averageWithdrawPrice, pendingShares, totalAssetsOut, PRECISION\n );\n\n // Reset state\n state.pendingRedeemRequest = 0;\n state.maxWithdraw += totalAssetsOut;\n state.averageRequestPPS = 0;\n state.pendingCancelRedeemRequest = false;\n state.claimableCancelRedeemRequest = 0;\n\n emit RedeemClaimable(controller, totalAssetsOut, pendingShares, state.averageWithdrawPrice);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL HELPER FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Internal function to get the SuperVaultAggregator\n /// @return The SuperVaultAggregator\n function _getSuperVaultAggregator() internal view returns (ISuperVaultAggregator) {\n address aggregatorAddress = SUPER_GOVERNOR.getAddress(SUPER_GOVERNOR.SUPER_VAULT_AGGREGATOR());\n\n return ISuperVaultAggregator(aggregatorAddress);\n }\n\n /// @notice Internal function to check if a manager is authorized\n /// @param manager_ The manager to check\n function _isManager(address manager_) internal view {\n if (!_getSuperVaultAggregator().isAnyManager(manager_, address(this))) {\n revert MANAGER_NOT_AUTHORIZED();\n }\n }\n\n /// @notice Internal function to check if a manager is the primary manager\n /// @param manager_ The manager to check\n function _isPrimaryManager(address manager_) internal view {\n if (!_getSuperVaultAggregator().isMainManager(manager_, address(this))) {\n revert MANAGER_NOT_AUTHORIZED();\n }\n }\n\n /// @notice Internal function to manage a yield source\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle\n /// @param actionType Type of action (see YieldSourceAction enum)\n function _manageYieldSource(address source, address oracle, YieldSourceAction actionType) internal {\n if (actionType == YieldSourceAction.Add) {\n _addYieldSource(source, oracle);\n } else if (actionType == YieldSourceAction.UpdateOracle) {\n _updateYieldSourceOracle(source, oracle);\n } else if (actionType == YieldSourceAction.Remove) {\n _removeYieldSource(source);\n }\n }\n\n /// @notice Internal function to add a yield source\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle\n function _addYieldSource(address source, address oracle) internal {\n if (source == address(0) || oracle == address(0)) revert ZERO_ADDRESS();\n if (yieldSources[source] != address(0)) revert YIELD_SOURCE_ALREADY_EXISTS();\n yieldSources[source] = oracle;\n if (!yieldSourcesList.add(source)) revert YIELD_SOURCE_ALREADY_EXISTS();\n\n emit YieldSourceAdded(source, oracle);\n }\n\n /// @notice Internal function to update a yield source's oracle\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle\n function _updateYieldSourceOracle(address source, address oracle) internal {\n if (oracle == address(0)) revert ZERO_ADDRESS();\n address oldOracle = yieldSources[source];\n if (oldOracle == address(0)) revert YIELD_SOURCE_NOT_FOUND();\n yieldSources[source] = oracle;\n\n emit YieldSourceOracleUpdated(source, oldOracle, oracle);\n }\n\n /// @notice Internal function to remove a yield source\n /// @param source Address of the yield source\n function _removeYieldSource(address source) internal {\n if (yieldSources[source] == address(0)) revert YIELD_SOURCE_NOT_FOUND();\n\n // Remove from mapping\n delete yieldSources[source];\n\n // Remove from EnumerableSet\n if (!yieldSourcesList.remove(source)) revert YIELD_SOURCE_NOT_FOUND();\n\n emit YieldSourceRemoved(source);\n }\n\n /// @notice Internal function to propose a PPS expiry threshold\n /// @param _threshold The new PPS expiry threshold\n function _proposePPSExpiration(uint256 _threshold) internal {\n _isPrimaryManager(msg.sender);\n\n if (_threshold < MIN_PPS_EXPIRATION_THRESHOLD || _threshold > MAX_PPS_EXPIRATION_THRESHOLD) {\n revert INVALID_PPS_EXPIRY_THRESHOLD();\n }\n\n uint256 currentProposedThreshold = proposedPPSExpiryThreshold;\n proposedPPSExpiryThreshold = _threshold;\n ppsExpiryThresholdEffectiveTime = block.timestamp + PROPOSAL_TIMELOCK;\n\n emit PPSExpirationProposed(currentProposedThreshold, _threshold, ppsExpiryThresholdEffectiveTime);\n }\n\n /// @notice Internal function to perform a PPS expiry threshold\n function _updatePPSExpiration() internal {\n _isPrimaryManager(msg.sender);\n\n // Must have a valid proposal\n if (block.timestamp < ppsExpiryThresholdEffectiveTime) revert INVALID_TIMESTAMP();\n\n if (proposedPPSExpiryThreshold == 0) revert INVALID_PPS_EXPIRY_THRESHOLD();\n\n uint256 _proposed = proposedPPSExpiryThreshold;\n ppsExpiration = _proposed;\n ppsExpiryThresholdEffectiveTime = 0;\n proposedPPSExpiryThreshold = 0;\n\n emit PPSExpiryThresholdUpdated(_proposed);\n }\n\n /// @notice Internal function to cancel a PPS expiry threshold proposal\n function _cancelPPSExpirationProposalUpdate() internal {\n _isPrimaryManager(msg.sender);\n\n if (ppsExpiryThresholdEffectiveTime == 0) revert NO_PROPOSAL();\n\n proposedPPSExpiryThreshold = 0;\n ppsExpiryThresholdEffectiveTime = 0;\n\n emit PPSExpiryThresholdProposalCanceled();\n }\n\n /// @notice Internal function to check if a hook is registered\n /// @param hook Address of the hook\n /// @return True if the hook is registered, false otherwise\n function _isRegisteredHook(address hook) private view returns (bool) {\n return SUPER_GOVERNOR.isHookRegistered(hook);\n }\n\n /// @notice Internal function to decode a hook's use previous hook amount\n /// @param hook Address of the hook\n /// @param hookCalldata Call data for the hook\n /// @return True if the hook should use the previous hook amount, false otherwise\n function _decodeHookUsePrevHookAmount(address hook, bytes memory hookCalldata) private pure returns (bool) {\n try ISuperHookContextAware(hook).decodeUsePrevHookAmount(hookCalldata) returns (bool usePrevHookAmount) {\n return usePrevHookAmount;\n } catch {\n return false;\n }\n }\n\n /// @notice Internal function to handle a redeem\n /// @param controller Address of the controller\n /// @param shares Amount of shares\n function _handleRequestRedeem(address controller, uint256 shares) private {\n if (shares == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n\n // Get current PPS from aggregator to use as baseline for slippage protection\n uint256 currentPPS = getStoredPPS();\n if (currentPPS == 0) revert INVALID_PPS();\n\n // Calculate weighted average of PPS if there's an existing request\n if (state.pendingRedeemRequest > 0) {\n // Incremental request: Calculate weighted average PPS\n // This protects users from PPS manipulation between multiple requests\n // Formula: avgPPS = (oldShares * oldPPS + newShares * newPPS) / totalShares\n uint256 existingSharesInRequest = state.pendingRedeemRequest;\n uint256 newTotalSharesInRequest = existingSharesInRequest + shares;\n\n // Weighted average ensures fair pricing across multiple request timestamps\n state.averageRequestPPS =\n ((existingSharesInRequest * state.averageRequestPPS) + (shares * currentPPS)) / newTotalSharesInRequest;\n\n state.pendingRedeemRequest = newTotalSharesInRequest;\n } else {\n // First request: Initialize with current PPS as baseline for slippage protection\n state.pendingRedeemRequest = shares;\n state.averageRequestPPS = currentPPS;\n }\n\n emit RedeemRequestPlaced(controller, controller, shares);\n }\n\n /// @notice Internal function to handle a redeem cancellation request\n /// @param controller Address of the controller\n function _handleCancelRedeemRequest(address controller) private {\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n if (state.pendingRedeemRequest == 0) revert REQUEST_NOT_FOUND();\n if (state.pendingCancelRedeemRequest) revert CANCELLATION_REDEEM_REQUEST_PENDING();\n\n state.pendingCancelRedeemRequest = true;\n emit RedeemCancelRequestPlaced(controller);\n }\n\n /// @notice Internal function to handle a claim redeem cancellation\n /// @param controller Address of the controller\n function _handleClaimCancelRedeem(address controller) private {\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n uint256 pendingShares = state.claimableCancelRedeemRequest;\n if (pendingShares == 0) revert REQUEST_NOT_FOUND();\n\n if (!state.pendingCancelRedeemRequest) revert CANCELLATION_REDEEM_REQUEST_PENDING();\n\n // Clear pending request metadata\n state.pendingCancelRedeemRequest = false;\n state.claimableCancelRedeemRequest = 0;\n emit RedeemRequestCanceled(controller, pendingShares);\n }\n\n /// @notice Internal function to handle a redeem claim\n /// @dev Only updates state. Vault is responsible for calling Escrow.returnAssets() after this returns.\n /// Callers (SuperVault.withdraw/redeem) already validate assetsToClaim <= state.maxWithdraw.\n /// @param controller Address of the controller\n /// @param receiver Address of the receiver (used for event only)\n /// @param assetsToClaim Amount of assets to claim\n function _handleClaimRedeem(address controller, address receiver, uint256 assetsToClaim) private {\n if (assetsToClaim == 0) revert INVALID_AMOUNT();\n if (controller == address(0)) revert ZERO_ADDRESS();\n SuperVaultState storage state = superVaultState[controller];\n state.maxWithdraw -= assetsToClaim;\n emit RedeemRequestClaimed(receiver, controller, assetsToClaim, 0);\n }\n\n /// @notice Internal function to safely transfer tokens\n /// @param token Address of the token\n /// @param recipient Address to receive the tokens\n /// @param amount Amount of tokens to transfer\n function _safeTokenTransfer(address token, address recipient, uint256 amount) private {\n if (amount > 0) IERC20(token).safeTransfer(recipient, amount);\n }\n\n /// @notice Internal function to get the token balance of an account\n /// @param token Address of the token\n /// @param account Address of the account\n /// @return Token balance of the account\n function _getTokenBalance(address token, address account) private view returns (uint256) {\n return IERC20(token).balanceOf(account);\n }\n\n /// @notice Internal function to check if the caller is the vault\n /// @dev This is used to prevent unauthorized access to certain functions\n function _requireVault() internal view {\n if (msg.sender != _vault) revert ACCESS_DENIED();\n }\n\n /// @notice Checks if the strategy is currently paused\n /// @dev This calls SuperVaultAggregator.isStrategyPaused to determine pause status\n /// @return True if the strategy is paused, false otherwise\n function _isPaused(ISuperVaultAggregator aggregator) internal view returns (bool) {\n return aggregator.isStrategyPaused(address(this));\n }\n\n /// @notice Checks if the PPS is stale\n /// @dev This calls SuperVaultAggregator.isPPSStale to determine stale status\n /// @return True if the PPS is stale, false otherwise\n function _isPPSStale(ISuperVaultAggregator aggregator) internal view returns (bool) {\n return aggregator.isPPSStale(address(this));\n }\n\n /// @notice Checks if the PPS is not updated\n /// @dev This checks if the PPS has not been updated since the `ppsExpiration` time\n /// @param aggregator The SuperVaultAggregator contract\n /// @return True if the PPS is not updated, false otherwise\n function _isPPSNotUpdated(ISuperVaultAggregator aggregator) internal view returns (bool) {\n // The `ppsExpiration` serves a different purpose:\n // if the oracle network stops pushing updates for some reasons (e.g. quite some nodes go down and the\n // quorum is never reached)\n // then the onchain PPS gets never updated and eventually it should not be used anymore, which is what the\n // `ppsExpiration` logic controls\n uint256 lastPPSUpdateTimestamp = aggregator.getLastUpdateTimestamp(address(this));\n return block.timestamp - lastPPSUpdateTimestamp > ppsExpiration;\n }\n\n /// @notice Validates full pps state by checking pause, stale, and PPS update status\n /// @dev Used for operations that require current PPS for calculations:\n /// - handleOperations4626Deposit: Needs PPS to calculate shares from assets\n /// - handleOperations4626Mint: Needs PPS to validate asset requirements\n /// - fulfillRedeemRequests: Needs current PPS to calculate assets from shares\n /// @param aggregator The SuperVaultAggregator contract\n function _validateStrategyState(ISuperVaultAggregator aggregator) internal view {\n if (_isPaused(aggregator)) revert STRATEGY_PAUSED();\n if (_isPPSStale(aggregator)) revert STALE_PPS();\n if (_isPPSNotUpdated(aggregator)) revert PPS_EXPIRED();\n }\n\n /// @notice Validates a hook using the Merkle root system\n /// @param hook Address of the hook to validate\n /// @param hookCalldata Calldata to be passed to the hook\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n /// @return isValid True if the hook is valid, false otherwise\n function _validateHook(\n address hook,\n bytes memory hookCalldata,\n bytes32[] memory globalProof,\n bytes32[] memory strategyProof\n )\n internal\n view\n returns (bool)\n {\n return _getSuperVaultAggregator()\n .validateHook(\n address(this),\n ISuperVaultAggregator.ValidateHookArgs({\n hookAddress: hook,\n hookArgs: ISuperHookInspector(hook).inspect(hookCalldata),\n globalProof: globalProof,\n strategyProof: strategyProof\n })\n );\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reinitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n *\n * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n */\n function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n return INITIALIZABLE_STORAGE;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n bytes32 slot = _initializableStorageSlot();\n assembly {\n $.slot := slot\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant NOT_ENTERED = 1;\n uint256 private constant ENTERED = 2;\n\n /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n struct ReentrancyGuardStorage {\n uint256 _status;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n assembly {\n $.slot := ReentrancyGuardStorageLocation\n }\n }\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if ($._status == ENTERED) {\n revert ReentrancyGuardReentrantCall();\n }\n\n // Any calls to nonReentrant after this point will fail\n $._status = ENTERED;\n }\n\n function _nonReentrantAfter() private {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n $._status = NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n return $._status == ENTERED;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\nimport {Arrays} from \"../Arrays.sol\";\nimport {Math} from \"../math/Math.sol\";\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n * - Set can be cleared (all elements removed) in O(n).\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * The following types are supported:\n *\n * - `bytes32` (`Bytes32Set`) since v3.3.0\n * - `address` (`AddressSet`) since v3.3.0\n * - `uint256` (`UintSet`) since v3.3.0\n * - `string` (`StringSet`) since v5.4.0\n * - `bytes` (`BytesSet`) since v5.4.0\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that\n * using it may render the function uncallable if the set grows to the point where clearing it consumes too much\n * gas to fit in a block.\n */\n function _clear(Set storage set) private {\n uint256 len = _length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {\n unchecked {\n end = Math.min(end, _length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes32[] memory result = new bytes32[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(Bytes32Set storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n bytes32[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(AddressSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n address[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(UintSet storage set) internal {\n _clear(set._inner);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner, start, end);\n uint256[] memory result;\n\n assembly (\"memory-safe\") {\n result := store\n }\n\n return result;\n }\n\n struct StringSet {\n // Storage of set values\n string[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(string value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(StringSet storage set, string memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(StringSet storage set, string memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n string memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(StringSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(StringSet storage set, string memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(StringSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(StringSet storage set, uint256 index) internal view returns (string memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set) internal view returns (string[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n string[] memory result = new string[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n\n struct BytesSet {\n // Storage of set values\n bytes[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes value => uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(BytesSet storage set, bytes memory value) internal returns (bool) {\n if (!contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(BytesSet storage set, bytes memory value) internal returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes memory lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes all the values from a set. O(n).\n *\n * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the\n * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.\n */\n function clear(BytesSet storage set) internal {\n uint256 len = length(set);\n for (uint256 i = 0; i < len; ++i) {\n delete set._positions[set._values[i]];\n }\n Arrays.unsafeSetLength(set._values, 0);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(BytesSet storage set) internal view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set) internal view returns (bytes[] memory) {\n return set._values;\n }\n\n /**\n * @dev Return a slice of the set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {\n unchecked {\n end = Math.min(end, length(set));\n start = Math.min(start, end);\n\n uint256 len = end - start;\n bytes[] memory result = new bytes[](len);\n for (uint256 i = 0; i < len; ++i) {\n result[i] = Arrays.unsafeAccess(set._values, start + i).value;\n }\n return result;\n }\n }\n}\n"},"lib/v2-core/lib/solady/src/utils/LibSort.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Optimized sorts and operations for sorted arrays.\n/// @author Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibSort.sol)\nlibrary LibSort {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INSERTION SORT */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // - Faster on small arrays (32 or lesser elements).\n // - Faster on almost sorted arrays.\n // - Smaller bytecode (about 300 bytes smaller than sort, which uses intro-quicksort).\n // - May be suitable for view functions intended for off-chain querying.\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(a) // Length of `a`.\n mstore(a, 0) // For insertion sort's inner loop to terminate.\n let h := add(a, shl(5, n)) // High slot.\n let w := not(0x1f)\n for { let i := add(a, 0x20) } 1 {} {\n i := add(i, 0x20)\n if gt(i, h) { break }\n let k := mload(i) // Key.\n let j := add(i, w) // The slot before the current slot.\n let v := mload(j) // The value of `j`.\n if iszero(gt(v, k)) { continue }\n for {} 1 {} {\n mstore(add(j, 0x20), v)\n j := add(j, w) // `sub(j, 0x20)`.\n v := mload(j)\n if iszero(gt(v, k)) { break }\n }\n mstore(add(j, 0x20), k)\n }\n mstore(a, n) // Restore the length of `a`.\n }\n }\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(int256[] memory a) internal pure {\n _flipSign(a);\n insertionSort(_toUints(a));\n _flipSign(a);\n }\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(address[] memory a) internal pure {\n insertionSort(_toUints(a));\n }\n\n /// @dev Sorts the array in-place with insertion sort.\n function insertionSort(bytes32[] memory a) internal pure {\n insertionSort(_toUints(a));\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTRO-QUICKSORT */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // - Faster on larger arrays (more than 32 elements).\n // - Robust performance.\n // - Larger bytecode.\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n function swap(a_, b_) -> _a, _b {\n _b := a_\n _a := b_\n }\n function mswap(i_, j_) {\n let t_ := mload(i_)\n mstore(i_, mload(j_))\n mstore(j_, t_)\n }\n function sortInner(w_, l_, h_) {\n // Do insertion sort if `h_ - l_ <= 0x20 * 12`.\n // Threshold is fine-tuned via trial and error.\n if iszero(gt(sub(h_, l_), 0x180)) {\n // Hardcode sort the first 2 elements.\n let i_ := add(l_, 0x20)\n if iszero(lt(mload(l_), mload(i_))) { mswap(i_, l_) }\n for {} 1 {} {\n i_ := add(i_, 0x20)\n if gt(i_, h_) { break }\n let k_ := mload(i_) // Key.\n let j_ := add(i_, w_) // The slot before the current slot.\n let v_ := mload(j_) // The value of `j_`.\n if iszero(gt(v_, k_)) { continue }\n for {} 1 {} {\n mstore(add(j_, 0x20), v_)\n j_ := add(j_, w_)\n v_ := mload(j_)\n if iszero(gt(v_, k_)) { break }\n }\n mstore(add(j_, 0x20), k_)\n }\n leave\n }\n // Pivot slot is the average of `l_` and `h_`.\n let p_ := add(shl(5, shr(6, add(l_, h_))), and(31, l_))\n // Median of 3 with sorting.\n {\n let e0_ := mload(l_)\n let e1_ := mload(p_)\n if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) }\n let e2_ := mload(h_)\n if iszero(lt(e1_, e2_)) {\n e1_, e2_ := swap(e1_, e2_)\n if iszero(lt(e0_, e1_)) { e0_, e1_ := swap(e0_, e1_) }\n }\n mstore(h_, e2_)\n mstore(p_, e1_)\n mstore(l_, e0_)\n }\n // Hoare's partition.\n {\n // The value of the pivot slot.\n let x_ := mload(p_)\n p_ := h_\n for { let i_ := l_ } 1 {} {\n for {} 1 {} {\n i_ := add(0x20, i_)\n if iszero(gt(x_, mload(i_))) { break }\n }\n let j_ := p_\n for {} 1 {} {\n j_ := add(w_, j_)\n if iszero(lt(x_, mload(j_))) { break }\n }\n p_ := j_\n if iszero(lt(i_, p_)) { break }\n mswap(i_, p_)\n }\n }\n if iszero(eq(add(p_, 0x20), h_)) { sortInner(w_, add(p_, 0x20), h_) }\n if iszero(eq(p_, l_)) { sortInner(w_, l_, p_) }\n }\n\n for { let n := mload(a) } iszero(lt(n, 2)) {} {\n let w := not(0x1f) // `-0x20`.\n let l := add(a, 0x20) // Low slot.\n let h := add(a, shl(5, n)) // High slot.\n let j := h\n // While `mload(j - 0x20) <= mload(j): j -= 0x20`.\n for {} iszero(gt(mload(add(w, j)), mload(j))) {} { j := add(w, j) }\n // If the array is already sorted, break.\n if iszero(gt(j, l)) { break }\n // While `mload(j - 0x20) >= mload(j): j -= 0x20`.\n for { j := h } iszero(lt(mload(add(w, j)), mload(j))) {} { j := add(w, j) }\n // If the array is reversed sorted.\n if iszero(gt(j, l)) {\n for {} 1 {} {\n let t := mload(l)\n mstore(l, mload(h))\n mstore(h, t)\n h := add(w, h)\n l := add(l, 0x20)\n if iszero(lt(l, h)) { break }\n }\n break\n }\n mstore(a, 0) // For insertion sort's inner loop to terminate.\n sortInner(w, l, h)\n mstore(a, n) // Restore the length of `a`.\n break\n }\n }\n }\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(int256[] memory a) internal pure {\n _flipSign(a);\n sort(_toUints(a));\n _flipSign(a);\n }\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(address[] memory a) internal pure {\n sort(_toUints(a));\n }\n\n /// @dev Sorts the array in-place with intro-quicksort.\n function sort(bytes32[] memory a) internal pure {\n sort(_toUints(a));\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* OTHER USEFUL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance, the `uniquifySorted` methods will not revert if the\n // array is not sorted -- it will simply remove consecutive duplicate elements.\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n // If the length of `a` is greater than 1.\n if iszero(lt(mload(a), 2)) {\n let x := add(a, 0x20)\n let y := add(a, 0x40)\n let end := add(a, shl(5, add(mload(a), 1)))\n for {} 1 {} {\n if iszero(eq(mload(x), mload(y))) {\n x := add(x, 0x20)\n mstore(x, mload(y))\n }\n y := add(y, 0x20)\n if eq(y, end) { break }\n }\n mstore(a, shr(5, sub(x, a)))\n }\n }\n }\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(int256[] memory a) internal pure {\n uniquifySorted(_toUints(a));\n }\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(address[] memory a) internal pure {\n uniquifySorted(_toUints(a));\n }\n\n /// @dev Removes duplicate elements from a ascendingly sorted memory array.\n function uniquifySorted(bytes32[] memory a) internal pure {\n uniquifySorted(_toUints(a));\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(uint256[] memory a, uint256 needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(a, needle, 0);\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(int256[] memory a, int256 needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255);\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(address[] memory a, address needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(_toUints(a), uint160(needle), 0);\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function searchSorted(bytes32[] memory a, bytes32 needle)\n internal\n pure\n returns (bool found, uint256 index)\n {\n (found, index) = _searchSorted(_toUints(a), uint256(needle), 0);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(uint256[] memory a, uint256 needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(int256[] memory a, int256 needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(address[] memory a, address needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Returns whether `a` contains `needle`.\n function inSorted(bytes32[] memory a, bytes32 needle) internal pure returns (bool found) {\n (found,) = searchSorted(a, needle);\n }\n\n /// @dev Reverses the array in-place.\n function reverse(uint256[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(mload(a), 2)) {\n let s := 0x20\n let w := not(0x1f)\n let h := add(a, shl(5, mload(a)))\n for { a := add(a, s) } 1 {} {\n let t := mload(a)\n mstore(a, mload(h))\n mstore(h, t)\n h := add(h, w)\n a := add(a, s)\n if iszero(lt(a, h)) { break }\n }\n }\n }\n }\n\n /// @dev Reverses the array in-place.\n function reverse(int256[] memory a) internal pure {\n reverse(_toUints(a));\n }\n\n /// @dev Reverses the array in-place.\n function reverse(address[] memory a) internal pure {\n reverse(_toUints(a));\n }\n\n /// @dev Reverses the array in-place.\n function reverse(bytes32[] memory a) internal pure {\n reverse(_toUints(a));\n }\n\n /// @dev Returns a copy of the array.\n function copy(uint256[] memory a) internal pure returns (uint256[] memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let end := add(add(result, 0x20), shl(5, mload(a)))\n let o := result\n for { let d := sub(a, result) } 1 {} {\n mstore(o, mload(add(o, d)))\n o := add(0x20, o)\n if eq(o, end) { break }\n }\n mstore(0x40, o)\n }\n }\n\n /// @dev Returns a copy of the array.\n function copy(int256[] memory a) internal pure returns (int256[] memory result) {\n result = _toInts(copy(_toUints(a)));\n }\n\n /// @dev Returns a copy of the array.\n function copy(address[] memory a) internal pure returns (address[] memory result) {\n result = _toAddresses(copy(_toUints(a)));\n }\n\n /// @dev Returns a copy of the array.\n function copy(bytes32[] memory a) internal pure returns (bytes32[] memory result) {\n result = _toBytes32s(copy(_toUints(a)));\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(uint256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := iszero(gt(p, mload(a)))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(int256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := iszero(sgt(p, mload(a)))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(address[] memory a) internal pure returns (bool result) {\n result = isSorted(_toUints(a));\n }\n\n /// @dev Returns whether the array is sorted in ascending order.\n function isSorted(bytes32[] memory a) internal pure returns (bool result) {\n result = isSorted(_toUints(a));\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := lt(p, mload(a))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := 1\n if iszero(lt(mload(a), 2)) {\n let end := add(a, shl(5, mload(a)))\n for { a := add(a, 0x20) } 1 {} {\n let p := mload(a)\n a := add(a, 0x20)\n result := slt(p, mload(a))\n if iszero(mul(result, xor(a, end))) { break }\n }\n }\n }\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) {\n result = isSortedAndUniquified(_toUints(a));\n }\n\n /// @dev Returns whether the array is strictly ascending (sorted and uniquified).\n function isSortedAndUniquified(bytes32[] memory a) internal pure returns (bool result) {\n result = isSortedAndUniquified(_toUints(a));\n }\n\n /// @dev Returns the sorted set difference of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(uint256[] memory a, uint256[] memory b)\n internal\n pure\n returns (uint256[] memory c)\n {\n c = _difference(a, b, 0);\n }\n\n /// @dev Returns the sorted set difference between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(int256[] memory a, int256[] memory b)\n internal\n pure\n returns (int256[] memory c)\n {\n c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255));\n }\n\n /// @dev Returns the sorted set difference between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(address[] memory a, address[] memory b)\n internal\n pure\n returns (address[] memory c)\n {\n c = _toAddresses(_difference(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set difference between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function difference(bytes32[] memory a, bytes32[] memory b)\n internal\n pure\n returns (bytes32[] memory c)\n {\n c = _toBytes32s(_difference(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(uint256[] memory a, uint256[] memory b)\n internal\n pure\n returns (uint256[] memory c)\n {\n c = _intersection(a, b, 0);\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(int256[] memory a, int256[] memory b)\n internal\n pure\n returns (int256[] memory c)\n {\n c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255));\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(address[] memory a, address[] memory b)\n internal\n pure\n returns (address[] memory c)\n {\n c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function intersection(bytes32[] memory a, bytes32[] memory b)\n internal\n pure\n returns (bytes32[] memory c)\n {\n c = _toBytes32s(_intersection(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set union of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(uint256[] memory a, uint256[] memory b)\n internal\n pure\n returns (uint256[] memory c)\n {\n c = _union(a, b, 0);\n }\n\n /// @dev Returns the sorted set union of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(int256[] memory a, int256[] memory b)\n internal\n pure\n returns (int256[] memory c)\n {\n c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255));\n }\n\n /// @dev Returns the sorted set union between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(address[] memory a, address[] memory b)\n internal\n pure\n returns (address[] memory c)\n {\n c = _toAddresses(_union(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Returns the sorted set union between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function union(bytes32[] memory a, bytes32[] memory b)\n internal\n pure\n returns (bytes32[] memory c)\n {\n c = _toBytes32s(_union(_toUints(a), _toUints(b), 0));\n }\n\n /// @dev Cleans the upper 96 bits of the addresses.\n /// In case `a` is produced via assembly and might have dirty upper bits.\n function clean(address[] memory a) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n let addressMask := shr(96, not(0))\n for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} {\n a := add(a, 0x20)\n mstore(a, and(mload(a), addressMask))\n }\n }\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(uint256[] memory keys, uint256[] memory values) internal pure {\n /// @solidity memory-safe-assembly\n assembly {\n function mswap(i_, j_) {\n let t_ := mload(i_)\n mstore(i_, mload(j_))\n mstore(j_, t_)\n }\n function sortInner(l_, h_, d_) {\n let p_ := mload(l_)\n let j_ := l_\n for { let i_ := add(l_, 0x20) } 1 {} {\n if lt(mload(i_), p_) {\n j_ := add(j_, 0x20)\n mswap(i_, j_)\n mswap(add(i_, d_), add(j_, d_))\n }\n i_ := add(0x20, i_)\n if iszero(lt(i_, h_)) { break }\n }\n mswap(l_, j_)\n mswap(add(l_, d_), add(j_, d_))\n if iszero(gt(add(0x40, l_), j_)) { sortInner(l_, j_, d_) }\n if iszero(gt(add(0x60, j_), h_)) { sortInner(add(j_, 0x20), h_, d_) }\n }\n let n := mload(values)\n if iszero(eq(mload(keys), n)) {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, 0x32) // Array out of bounds panic if the arrays lengths differ.\n revert(0x1c, 0x24)\n }\n if iszero(lt(n, 2)) {\n let d := sub(values, keys)\n let x := add(keys, 0x20)\n let end := add(x, shl(5, n))\n sortInner(x, end, d)\n let s := mload(add(x, d))\n for { let y := add(keys, 0x40) } 1 {} {\n if iszero(eq(mload(x), mload(y))) {\n mstore(add(x, d), s) // Write sum.\n s := 0\n x := add(x, 0x20)\n mstore(x, mload(y))\n }\n s := add(s, mload(add(y, d)))\n if lt(s, mload(add(y, d))) {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, 0x11) // Overflow panic if the addition overflows.\n revert(0x1c, 0x24)\n }\n y := add(y, 0x20)\n if eq(y, end) { break }\n }\n mstore(add(x, d), s) // Write sum.\n mstore(keys, shr(5, sub(x, keys))) // Truncate.\n mstore(values, mload(keys)) // Truncate.\n }\n }\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(address[] memory keys, uint256[] memory values) internal pure {\n groupSum(_toUints(keys), values);\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(bytes32[] memory keys, uint256[] memory values) internal pure {\n groupSum(_toUints(keys), values);\n }\n\n /// @dev Sorts and uniquifies `keys`. Updates `values` with the grouped sums by key.\n function groupSum(int256[] memory keys, uint256[] memory values) internal pure {\n groupSum(_toUints(keys), values);\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(uint256[] memory a) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n function p(i_, x_) -> _y {\n _y := or(shr(i_, x_), x_)\n }\n let n := mload(a)\n if iszero(lt(n, 2)) {\n let m := mload(0x40) // Use free memory temporarily for hashmap.\n let w := not(0x1f) // `-0x20`.\n let c := and(w, p(16, p(8, p(4, p(2, p(1, mul(0x30, n)))))))\n calldatacopy(m, calldatasize(), add(0x20, c)) // Zeroize hashmap.\n for { let i := add(a, shl(5, n)) } 1 {} {\n // See LibPRNG for explanation of this formula.\n let r := mulmod(mload(i), 0x100000000000000000000000000000051, not(0xbc))\n // Linear probing.\n for {} 1 { r := add(0x20, r) } {\n let o := add(m, and(r, c)) // Non-zero pointer into hashmap.\n if iszero(mload(o)) {\n mstore(o, i) // Store non-zero pointer into hashmap.\n break\n }\n if eq(mload(mload(o)), mload(i)) {\n result := 1\n i := a // To break the outer loop.\n break\n }\n }\n i := add(i, w) // Iterate `a` backwards.\n if iszero(lt(a, i)) { break }\n }\n if shr(31, n) { invalid() } // Just in case.\n }\n }\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(address[] memory a) internal pure returns (bool) {\n return hasDuplicate(_toUints(a));\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(bytes32[] memory a) internal pure returns (bool) {\n return hasDuplicate(_toUints(a));\n }\n\n /// @dev Returns if `a` has any duplicate. Does NOT mutate `a`. `O(n)`.\n function hasDuplicate(int256[] memory a) internal pure returns (bool) {\n return hasDuplicate(_toUints(a));\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Reinterpret cast to an uint256 array.\n function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an uint256 array.\n function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n // As any address written to memory will have the upper 96 bits\n // of the word zeroized (as per Solidity spec), we can directly\n // compare these addresses as if they are whole uint256 words.\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an uint256 array.\n function _toUints(bytes32[] memory a) private pure returns (uint256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an int array.\n function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an address array.\n function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Reinterpret cast to an bytes32 array.\n function _toBytes32s(uint256[] memory a) private pure returns (bytes32[] memory casted) {\n /// @solidity memory-safe-assembly\n assembly {\n casted := a\n }\n }\n\n /// @dev Converts an array of signed integers to unsigned\n /// integers suitable for sorting or vice versa.\n function _flipSign(int256[] memory a) private pure {\n /// @solidity memory-safe-assembly\n assembly {\n let q := shl(255, 1)\n for { let i := add(a, shl(5, mload(a))) } iszero(eq(a, i)) {} {\n mstore(i, add(mload(i), q))\n i := sub(i, 0x20)\n }\n }\n }\n\n /// @dev Returns whether `a` contains `needle`, and the index of `needle`.\n /// `index` precedence: equal to > nearest before > nearest after.\n function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed)\n private\n pure\n returns (bool found, uint256 index)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0)\n let l := 1\n let h := mload(a)\n let t := 0\n for { needle := add(signed, needle) } 1 {} {\n index := shr(1, add(l, h))\n t := add(signed, mload(add(a, shl(5, index))))\n if or(gt(l, h), eq(t, needle)) { break }\n // Decide whether to search the left or right half.\n if iszero(gt(needle, t)) {\n h := add(index, w)\n continue\n }\n l := add(index, 1)\n }\n // `index` will be zero in the case of an empty array,\n // or when the value is less than the smallest value in the array.\n found := eq(t, needle)\n t := iszero(iszero(index))\n index := mul(add(index, w), t)\n found := and(found, t)\n }\n }\n\n /// @dev Returns the sorted set difference of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function _difference(uint256[] memory a, uint256[] memory b, uint256 signed)\n private\n pure\n returns (uint256[] memory c)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let s := 0x20\n let aEnd := add(a, shl(5, mload(a)))\n let bEnd := add(b, shl(5, mload(b)))\n c := mload(0x40) // Set `c` to the free memory pointer.\n a := add(a, s)\n b := add(b, s)\n let k := c\n for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {\n let u := mload(a)\n let v := mload(b)\n if iszero(xor(u, v)) {\n a := add(a, s)\n b := add(b, s)\n continue\n }\n if iszero(lt(add(u, signed), add(v, signed))) {\n b := add(b, s)\n continue\n }\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n }\n for {} iszero(gt(a, aEnd)) {} {\n k := add(k, s)\n mstore(k, mload(a))\n a := add(a, s)\n }\n mstore(c, shr(5, sub(k, c))) // Store the length of `c`.\n mstore(0x40, add(k, s)) // Allocate the memory for `c`.\n }\n }\n\n /// @dev Returns the sorted set intersection between `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed)\n private\n pure\n returns (uint256[] memory c)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let s := 0x20\n let aEnd := add(a, shl(5, mload(a)))\n let bEnd := add(b, shl(5, mload(b)))\n c := mload(0x40) // Set `c` to the free memory pointer.\n a := add(a, s)\n b := add(b, s)\n let k := c\n for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {\n let u := mload(a)\n let v := mload(b)\n if iszero(xor(u, v)) {\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n b := add(b, s)\n continue\n }\n if iszero(lt(add(u, signed), add(v, signed))) {\n b := add(b, s)\n continue\n }\n a := add(a, s)\n }\n mstore(c, shr(5, sub(k, c))) // Store the length of `c`.\n mstore(0x40, add(k, s)) // Allocate the memory for `c`.\n }\n }\n\n /// @dev Returns the sorted set union of `a` and `b`.\n /// Note: Behaviour is undefined if inputs are not sorted and uniquified.\n function _union(uint256[] memory a, uint256[] memory b, uint256 signed)\n private\n pure\n returns (uint256[] memory c)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let s := 0x20\n let aEnd := add(a, shl(5, mload(a)))\n let bEnd := add(b, shl(5, mload(b)))\n c := mload(0x40) // Set `c` to the free memory pointer.\n a := add(a, s)\n b := add(b, s)\n let k := c\n for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {\n let u := mload(a)\n let v := mload(b)\n if iszero(xor(u, v)) {\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n b := add(b, s)\n continue\n }\n if iszero(lt(add(u, signed), add(v, signed))) {\n k := add(k, s)\n mstore(k, v)\n b := add(b, s)\n continue\n }\n k := add(k, s)\n mstore(k, u)\n a := add(a, s)\n }\n for {} iszero(gt(a, aEnd)) {} {\n k := add(k, s)\n mstore(k, mload(a))\n a := add(a, s)\n }\n for {} iszero(gt(b, bEnd)) {} {\n k := add(k, s)\n mstore(k, mload(b))\n b := add(b, s)\n }\n mstore(c, shr(5, sub(k, c))) // Store the length of `c`.\n mstore(0x40, add(k, s)) // Allocate the memory for `c`.\n }\n }\n}\n"},"lib/v2-core/src/interfaces/ISuperHook.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\n// external\nimport { Execution } from \"modulekit/accounts/erc7579/lib/ExecutionLib.sol\";\n\n/**\n * @title SuperHook System\n * @author Superform Labs\n * @notice The hook system provides a modular and composable way to execute operations on assets\n * @dev The hook system architecture consists of several interfaces that work together:\n * - ISuperHook: The base interface all hooks implement, with lifecycle methods\n * - ISuperHookResult: Provides execution results and output information\n * - Specialized interfaces (ISuperHookOutflow, ISuperHookLoans, etc.) for specific behaviors\n *\n * Hooks are executed in sequence, where each hook can access the results from previous hooks.\n * The three main types of hooks are:\n * - NONACCOUNTING: Utility hooks that don't update the accounting system\n * - INFLOW: Hooks that process deposits or additions to positions\n * - OUTFLOW: Hooks that process withdrawals or reductions to positions\n */\ninterface ISuperLockableHook {\n /// @notice The vault bank address used to lock SuperPositions\n /// @dev Only relevant for cross-chain operations where positions are locked\n /// @return The vault bank address, or address(0) if not applicable\n function vaultBank() external view returns (address);\n\n /// @notice The destination chain ID for cross-chain operations\n /// @dev Used to identify the target chain for cross-chain position transfers\n /// @return The destination chain ID, or 0 if not a cross-chain operation\n function dstChainId() external view returns (uint256);\n}\n\ninterface ISuperHookSetter {\n /// @notice Sets the output amount for the hook\n /// @dev Used for updating `outAmount` when fees were deducted\n /// @param outAmount The amount of tokens processed by the hook\n /// @param caller The caller address for context identification\n function setOutAmount(uint256 outAmount, address caller) external;\n}\n/// @title ISuperHookInspector\n/// @author Superform Labs\n/// @notice Interface for the SuperHookInspector contract that manages hook inspection\n\ninterface ISuperHookInspector {\n /// @notice Inspect the hook\n /// @param data The hook data to inspect\n /// @return argsEncoded The arguments of the hook encoded\n function inspect(bytes calldata data) external view returns (bytes memory argsEncoded);\n}\n\n/// @title ISuperHookResult\n/// @author Superform Labs\n/// @notice Interface that exposes the result of a hook execution\n/// @dev All hooks must implement this interface to provide standardized access to execution results.\n/// These results are used by subsequent hooks in the execution chain and by the executor.\ninterface ISuperHookResult {\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The type of hook\n /// @dev Used to determine how accounting should process this hook's results\n /// @return The hook type (NONACCOUNTING, INFLOW, or OUTFLOW)\n function hookType() external view returns (ISuperHook.HookType);\n\n /// @notice The SuperPosition (SP) token associated with this hook\n /// @dev For vault hooks, this would be the tokenized position representing shares\n /// @return The address of the SP token, or address(0) if not applicable\n function spToken() external view returns (address);\n\n /// @notice The underlying asset token being processed\n /// @dev For most hooks, this is the actual token being deposited or withdrawn\n /// @return The address of the asset token, or address(0) for native assets\n function asset() external view returns (address);\n\n /// @notice The amount of tokens processed by the hook in a given caller context, subject to fees after update\n /// @dev This is the primary output value used by subsequent hooks\n /// @param caller The caller address for context identification\n /// @return The amount of tokens (assets or shares) processed\n function getOutAmount(address caller) external view returns (uint256);\n}\n\n/// @title ISuperHookContextAware\n/// @author Superform Labs\n/// @notice Interface for hooks that can use previous hook results in their execution\n/// @dev Enables contextual awareness and data flow between hooks in a chain\ninterface ISuperHookContextAware {\n /// @notice Determines if this hook should use the amount from the previous hook\n /// @dev Used to create hook chains where output from one hook becomes input to the next\n /// @param data The hook-specific data containing configuration\n /// @return True if the hook should use the previous hook's output amount\n function decodeUsePrevHookAmount(bytes memory data) external pure returns (bool);\n}\n\n/// @title ISuperHookInflowOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that handle both inflows and outflows\n/// @dev Provides standardized amount extraction for both deposit and withdrawal operations\ninterface ISuperHookInflowOutflow {\n /// @notice Extracts the amount from the hook's calldata\n /// @dev Used to determine the quantity of assets or shares being processed\n /// @param data The hook-specific calldata containing the amount\n /// @return The amount of tokens to process\n function decodeAmount(bytes memory data) external pure returns (uint256);\n}\n\n/// @title ISuperHookOutflow\n/// @author Superform Labs\n/// @notice Interface for hooks that specifically handle outflows (withdrawals)\n/// @dev Provides additional functionality needed only for outflow operations\ninterface ISuperHookOutflow {\n /// @notice Replace the amount in the calldata\n /// @param data The data to replace the amount in\n /// @param amount The amount to replace\n /// @return data The data with the replaced amount\n function replaceCalldataAmount(bytes memory data, uint256 amount) external pure returns (bytes memory);\n}\n\n/// @title ISuperHookResultOutflow\n/// @author Superform Labs\n/// @notice Extended result interface for outflow hook operations\n/// @dev Extends the base result interface with outflow-specific information\ninterface ISuperHookResultOutflow is ISuperHookResult {\n /// @notice The amount of shares consumed during outflow processing\n /// @dev Used for cost basis calculation in the accounting system\n /// @return The amount of shares consumed from the user's position\n function usedShares() external view returns (uint256);\n}\n\n/// @title ISuperHookLoans\n/// @author Superform Labs\n/// @notice Interface for hooks that interact with lending protocols\n/// @dev Extends context awareness to enable loan operations within hook chains\ninterface ISuperHookLoans is ISuperHookContextAware {\n /// @notice Gets the address of the token being borrowed\n /// @dev Used to identify which asset is being borrowed from the lending protocol\n /// @param data The hook-specific data containing loan information\n /// @return The address of the borrowed token\n function getLoanTokenAddress(bytes memory data) external pure returns (address);\n\n /// @notice Gets the address of the token used as collateral\n /// @dev Used to identify which asset is being used to secure the loan\n /// @param data The hook-specific data containing collateral information\n /// @return The address of the collateral token\n function getCollateralTokenAddress(bytes memory data) external view returns (address);\n\n /// @notice Gets the current loan token balance for an account\n /// @dev Used to track outstanding loan amounts\n /// @param account The account to check the loan balance for\n /// @param data The hook-specific data containing loan parameters\n /// @return The amount of tokens currently borrowed\n function getLoanTokenBalance(address account, bytes memory data) external view returns (uint256);\n\n /// @notice Gets the current collateral token balance for an account\n /// @dev Used to track collateral positions\n /// @param account The account to check the collateral balance for\n /// @param data The hook-specific data containing collateral parameters\n /// @return The amount of tokens currently used as collateral\n function getCollateralTokenBalance(address account, bytes memory data) external view returns (uint256);\n}\n\n/// @title ISuperHookAsyncCancelations\n/// @author Superform Labs\n/// @notice Interface for hooks that can cancel asynchronous operations\n/// @dev Used to handle cancellation of pending operations that haven't completed\ninterface ISuperHookAsyncCancelations {\n /// @notice Types of cancellations that can be performed\n /// @dev Distinguishes between different operation types that can be canceled\n enum CancelationType {\n NONE, // Not a cancelation hook\n INFLOW, // Cancels a pending deposit operation\n OUTFLOW // Cancels a pending withdrawal operation\n\n }\n\n /// @notice Identifies the type of async operation this hook can cancel\n /// @dev Used to verify the hook is appropriate for the operation being canceled\n /// @return asyncType The type of cancellation this hook performs\n function isAsyncCancelHook() external pure returns (CancelationType asyncType);\n}\n\n/// @title ISuperHook\n/// @author Superform Labs\n/// @notice The core hook interface that all hooks must implement\n/// @dev Defines the lifecycle methods and execution flow for the hook system\n/// Hooks are executed in sequence with results passed between them\ninterface ISuperHook {\n /*//////////////////////////////////////////////////////////////\n\n ENUMS\n //////////////////////////////////////////////////////////////*/\n /// @notice Defines the possible types of hooks in the system\n /// @dev Used to determine how the hook affects accounting and what operations it performs\n enum HookType {\n NONACCOUNTING, // Hook doesn't affect accounting (e.g., a swap or bridge)\n INFLOW, // Hook processes deposits or positions being added\n OUTFLOW // Hook processes withdrawals or positions being removed\n\n }\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Builds the execution array for the hook operation\n /// @dev This is the core method where hooks define their on-chain interactions\n /// The returned executions are a sequence of contract calls to perform\n /// No state changes should occur in this method\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform executions for (usually an ERC7579 account)\n /// @param data The hook-specific parameters and configuration data\n /// @return executions Array of Execution structs defining calls to make\n function build(\n address prevHook,\n address account,\n bytes calldata data\n )\n external\n view\n returns (Execution[] memory executions);\n\n /*//////////////////////////////////////////////////////////////\n PUBLIC METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Prepares the hook for execution\n /// @dev Called before the main execution, used to validate inputs and set execution context\n /// This method may perform state changes to set up the hook's execution state\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account to perform operations for\n /// @param data The hook-specific parameters and configuration data\n function preExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Finalizes the hook after execution\n /// @dev Called after the main execution, used to update hook state and calculate results\n /// Sets output values (outAmount, usedShares, etc.) for subsequent hooks\n /// @param prevHook The address of the previous hook in the chain, or address(0) if first\n /// @param account The account operations were performed for\n /// @param data The hook-specific parameters and configuration data\n function postExecute(address prevHook, address account, bytes memory data) external;\n\n /// @notice Returns the specific subtype identification for this hook\n /// @dev Used to categorize hooks beyond the basic HookType\n /// For example, a hook might be of type INFLOW but subtype VAULT_DEPOSIT\n /// @return A bytes32 identifier for the specific hook functionality\n function subtype() external view returns (bytes32);\n\n /// @notice Resets hook mutexes\n /// @param caller The caller address for context identification\n function resetExecutionState(address caller) external;\n\n /// @notice Sets the caller address that initiated the execution\n /// @dev Used for security validation between preExecute and postExecute calls\n /// @param caller The caller address for context identification\n function setExecutionContext(address caller) external;\n\n /// @notice Returns the execution nonce for the current execution context\n /// @dev Used to ensure unique execution contexts and prevent replay attacks\n /// @return The execution nonce\n function executionNonce() external view returns (uint256);\n\n /// @notice Returns the last caller registered by `setExecutionContext`\n /// @return The last caller address\n function lastCaller() external view returns (address);\n}\n"},"src/interfaces/SuperVault/ISuperVault.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { IERC7540Redeem, IERC7540CancelRedeem } from \"../../vendor/standards/ERC7540/IERC7540Vault.sol\";\nimport { IERC7741 } from \"../../vendor/standards/ERC7741/IERC7741.sol\";\n\n/// @title ISuperVault\n/// @notice Interface for SuperVault core contract that manages share minting\n/// @author Superform Labs\ninterface ISuperVault is IERC4626, IERC7540Redeem, IERC7741, IERC7540CancelRedeem {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INVALID_ASSET();\n error ZERO_ADDRESS();\n error ZERO_AMOUNT();\n error INVALID_AMOUNT();\n error UNAUTHORIZED();\n error DEADLINE_PASSED();\n error INVALID_SIGNATURE();\n error NOT_IMPLEMENTED();\n error INVALID_NONCE();\n error INVALID_WITHDRAW_PRICE();\n error INVALID_CONTROLLER();\n error CONTROLLER_MUST_EQUAL_OWNER();\n error RECEIVER_MUST_EQUAL_CONTROLLER();\n error NOT_ENOUGH_ASSETS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event NonceInvalidated(address indexed sender, bytes32 indexed nonce);\n\n event SuperGovernorSet(address indexed superGovernor);\n\n event Initialized(address indexed asset, address indexed strategy, address indexed escrow);\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Burn shares, only callable by strategy\n /// @param amount The amount of shares to burn\n function burnShares(uint256 amount) external;\n\n /// @notice Get the amount of assets escrowed\n function getEscrowedAssets() external view returns (uint256);\n\n /*//////////////////////////////////////////////////////////////\n VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n /// @notice Get the escrow address\n function escrow() external view returns (address);\n}\n"},"lib/v2-core/src/libraries/HookDataDecoder.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { BytesLib } from \"../vendor/BytesLib.sol\";\n\n/// @title HookDataDecoder\n/// @author Superform Labs\n/// @notice Library for decoding hook data\nlibrary HookDataDecoder {\n function extractYieldSourceOracleId(bytes memory data) internal pure returns (bytes32) {\n return bytes32(BytesLib.slice(data, 0, 32));\n }\n\n function extractYieldSource(bytes memory data) internal pure returns (address) {\n return BytesLib.toAddress(data, 32);\n }\n}\n"},"src/interfaces/SuperVault/ISuperVaultStrategy.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { ISuperHook, Execution } from \"@superform-v2-core/src/interfaces/ISuperHook.sol\";\n\n/// @title ISuperVaultStrategy\n/// @author Superform Labs\n/// @notice Interface for SuperVault strategy implementation that manages yield sources and executes strategies\ninterface ISuperVaultStrategy {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n error ZERO_LENGTH();\n error INVALID_HOOK();\n error ZERO_ADDRESS();\n error ACCESS_DENIED();\n error INVALID_AMOUNT();\n error OPERATION_FAILED();\n error INVALID_TIMESTAMP();\n error REQUEST_NOT_FOUND();\n error INVALID_ARRAY_LENGTH();\n error ACTION_TYPE_DISALLOWED();\n error YIELD_SOURCE_NOT_FOUND();\n error YIELD_SOURCE_ALREADY_EXISTS();\n error INVALID_PERFORMANCE_FEE_BPS();\n error MINIMUM_OUTPUT_AMOUNT_ASSETS_NOT_MET();\n error MANAGER_NOT_AUTHORIZED();\n error INVALID_PPS();\n error INVALID_VAULT();\n error INVALID_ASSET();\n error OPERATIONS_BLOCKED_BY_VETO();\n error HOOK_VALIDATION_FAILED();\n error STRATEGY_PAUSED();\n error NO_PROPOSAL();\n error INVALID_REDEEM_SLIPPAGE_BPS();\n error CANCELLATION_REDEEM_REQUEST_PENDING();\n error STALE_PPS();\n error PPS_EXPIRED();\n error INVALID_PPS_EXPIRY_THRESHOLD();\n error BOUNDS_EXCEEDED(uint256 minAllowed, uint256 maxAllowed, uint256 actual);\n error INSUFFICIENT_LIQUIDITY();\n error CONTROLLERS_NOT_SORTED_UNIQUE();\n error ZERO_SHARE_FULFILLMENT_DISALLOWED();\n error NOT_ENOUGH_FREE_ASSETS_FEE_SKIM();\n error SKIM_TIMELOCK_ACTIVE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event SuperGovernorSet(address indexed superGovernor);\n event Initialized(address indexed vault);\n event YieldSourceAdded(address indexed source, address indexed oracle);\n event YieldSourceOracleUpdated(address indexed source, address indexed oldOracle, address indexed newOracle);\n event YieldSourceRemoved(address indexed source);\n\n event VaultFeeConfigUpdated(uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient);\n event VaultFeeConfigProposed(\n uint256 performanceFeeBps, uint256 managementFeeBps, address indexed recipient, uint256 effectiveTime\n );\n event HooksExecuted(address[] hooks);\n event RedeemRequestPlaced(address indexed controller, address indexed owner, uint256 shares);\n event RedeemRequestClaimed(address indexed controller, address indexed receiver, uint256 assets, uint256 shares);\n event RedeemRequestsFulfilled(address[] controllers, uint256 processedShares, uint256 currentPPS);\n event RedeemRequestCanceled(address indexed controller, uint256 shares);\n event RedeemCancelRequestPlaced(address indexed controller);\n event RedeemCancelRequestFulfilled(address indexed controller, uint256 shares);\n event HookExecuted(\n address indexed hook,\n address indexed prevHook,\n address indexed targetedYieldSource,\n bool usePrevHookAmount,\n bytes hookCalldata\n );\n\n event PPSUpdated(uint256 newPPS, uint256 calculationBlock);\n event FeeRecipientChanged(address indexed newRecipient);\n event ManagementFeePaid(address indexed controller, address indexed recipient, uint256 feeAssets, uint256 feeBps);\n event DepositHandled(address indexed controller, uint256 assets, uint256 shares);\n event RedeemClaimable(\n address indexed controller, uint256 assetsFulfilled, uint256 sharesFulfilled, uint256 averageWithdrawPrice\n );\n event RedeemSlippageSet(address indexed controller, uint16 slippageBps);\n\n event PPSExpirationProposed(uint256 currentProposedThreshold, uint256 ppsExpiration, uint256 effectiveTime);\n event PPSExpiryThresholdUpdated(uint256 ppsExpiration);\n event PPSExpiryThresholdProposalCanceled();\n\n /// @notice Emitted when the high-water mark PPS is updated after fee collection\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n /// @param previousPps The PPS before fee collection\n /// @param profit The total profit above HWM (in assets)\n /// @param feeCollected The total fee collected (in assets)\n event HWMPPSUpdated(uint256 newHwmPps, uint256 previousPps, uint256 profit, uint256 feeCollected);\n\n /// @notice Emitted when the high-water mark PPS is reset\n /// @param newHwmPps The new high-water mark PPS (post-fee)\n event HighWaterMarkReset(uint256 newHwmPps);\n\n /// @notice Emitted when performance fees are skimmed\n /// @param totalFee The total fee collected (in assets)\n /// @param superformFee The fee collected for Superform (in assets)\n event PerformanceFeeSkimmed(uint256 totalFee, uint256 superformFee);\n\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n struct FeeConfig {\n uint256 performanceFeeBps; // On profit at fulfill time\n uint256 managementFeeBps; // Entry fee on deposit/mint (asset-side)\n address recipient; // Fee sink (entry + performance)\n }\n\n /// @notice Structure for hook execution arguments\n struct ExecuteArgs {\n /// @notice Array of hooks to execute\n address[] hooks;\n /// @notice Calldata for each hook (must match hooks array length)\n bytes[] hookCalldata;\n /// @notice Expected output amounts or output shares\n uint256[] expectedAssetsOrSharesOut;\n /// @notice Global Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] globalProofs;\n /// @notice Strategy-specific Merkle proofs for hook validation (must match hooks array length)\n bytes32[][] strategyProofs;\n }\n\n struct YieldSource {\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice Comprehensive information about a yield source including its address and configuration\n struct YieldSourceInfo {\n address sourceAddress; // Address of the yield source\n address oracle; // Associated yield source oracle address\n }\n\n /// @notice State specific to asynchronous redeem requests\n struct SuperVaultState {\n // Cancellation\n bool pendingCancelRedeemRequest;\n uint256 claimableCancelRedeemRequest;\n // Redeems\n uint256 pendingRedeemRequest; // Shares requested\n uint256 maxWithdraw; // Assets claimable after fulfillment\n uint256 averageRequestPPS; // Average PPS at the time of redeem request\n uint256 averageWithdrawPrice; // Average price for claimable assets\n uint16 redeemSlippageBps; // User-defined slippage tolerance in BPS for redeem fulfillment\n }\n\n struct ExecutionVars {\n bool success;\n address targetedYieldSource;\n uint256 outAmount;\n ISuperHook hookContract;\n Execution[] executions;\n }\n\n struct FulfillRedeemVars {\n uint256 totalRequestedShares;\n uint256 totalNetAssetsOut;\n uint256 currentPPS;\n uint256 strategyBalance;\n }\n\n /*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n enum Operation {\n RedeemRequest,\n CancelRedeemRequest,\n ClaimCancelRedeem,\n ClaimRedeem\n }\n\n /// @notice Action types for yield source management\n enum YieldSourceAction {\n Add, // 0: Add a new yield source\n UpdateOracle, // 1: Update an existing yield source's oracle\n Remove // 2: Remove a yield source\n }\n\n /// @notice Action types for PPS expiration threshold management\n enum PPSExpirationAction {\n Propose, // 0: Propose a new PPS expiration threshold\n Execute, // 1: Execute the proposed threshold update\n Cancel // 2: Cancel the pending threshold proposal\n }\n\n /*//////////////////////////////////////////////////////////////\n CORE STRATEGY OPERATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the strategy with required parameters\n /// @param vaultAddress Address of the associated SuperVault\n /// @param feeConfigData Fee configuration\n function initialize(address vaultAddress, FeeConfig memory feeConfigData) external;\n\n /// @notice Execute a 4626 deposit by processing assets.\n /// @param controller The controller address\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @return sharesNet The amount of net shares to mint\n function handleOperations4626Deposit(address controller, uint256 assetsGross) external returns (uint256 sharesNet);\n\n /// @notice Execute a 4626 mint by processing shares.\n /// @param controller The controller address\n /// @param sharesNet The amount of shares to mint\n /// @param assetsGross The amount of gross assets user has to deposit\n /// @param assetsNet The amount of net assets that strategy will receive\n function handleOperations4626Mint(\n address controller,\n uint256 sharesNet,\n uint256 assetsGross,\n uint256 assetsNet\n )\n external;\n\n /// @notice Quotes the amount of assets that will be received for a given amount of shares.\n /// @param shares The amount of shares to mint\n /// @return assetsGross The amount of gross assets that will be received\n /// @return assetsNet The amount of net assets that will be received\n function quoteMintAssetsGross(uint256 shares) external view returns (uint256 assetsGross, uint256 assetsNet);\n\n /// @notice Execute async redeem requests (redeem, cancel, claim).\n /// @param op The operation type (RedeemRequest, CancelRedeem, ClaimRedeem)\n /// @param controller The controller address\n /// @param receiver The receiver address\n /// @param amount The amount of assets or shares\n function handleOperations7540(Operation op, address controller, address receiver, uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER EXTERNAL ACCESS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Execute hooks for general strategy management (rebalancing, etc.).\n /// @param args Execution arguments containing hooks, calldata, proofs, expectations.\n function executeHooks(ExecuteArgs calldata args) external payable;\n\n /// @notice Fulfills pending cancel redeem requests by making shares claimable\n /// @dev Processes all controllers with pending cancellation flags\n /// @dev Can only be called by authorized managers\n /// @param controllers Array of controller addresses with pending cancel requests\n function fulfillCancelRedeemRequests(address[] memory controllers) external;\n\n /// @notice Fulfills pending redeem requests with exact total assets per controller (pre-fee).\n /// @dev PRE: Off-chain sort/unique controllers. Call executeHooks(sum(totalAssetsOut)) first.\n /// @dev Social: totalAssetsOut[i] = theoreticalGross[i] (full). Selective: totalAssetsOut[i] < theoreticalGross[i].\n /// @dev NOTE: totalAssetsOut includes fees - actual net amount received is calculated internally after fee\n /// deduction. @param controllers Ordered/unique controllers with pending requests.\n /// @param totalAssetsOut Total PRE-FEE assets available for each controller[i] (from executeHooks).\n function fulfillRedeemRequests(address[] calldata controllers, uint256[] calldata totalAssetsOut) external;\n\n /// @notice Skim performance fees based on per-share High Water Mark (PPS-based)\n /// @dev Can be called by any manager when vault PPS has grown above HWM PPS\n /// @dev Uses PPS growth to calculate profit: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev HWM is only updated during this function, not during deposits/redemptions\n function skimPerformanceFee() external;\n\n /*//////////////////////////////////////////////////////////////\n YIELD SOURCE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Manage a single yield source: add, update oracle, or remove\n /// @param source Address of the yield source\n /// @param oracle Address of the oracle (used for adding/updating, ignored for removal)\n /// @param actionType Type of action (see YieldSourceAction enum)\n function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external;\n\n /// @notice Batch manage multiple yield sources in a single transaction\n /// @param sources Array of yield source addresses\n /// @param oracles Array of oracle addresses (used for adding/updating, ignored for removal)\n /// @param actionTypes Array of action types (see YieldSourceAction enum)\n function manageYieldSources(\n address[] calldata sources,\n address[] calldata oracles,\n YieldSourceAction[] calldata actionTypes\n )\n external;\n\n /// @notice Change the fee recipient when the primary manager is changed\n /// @param newRecipient New fee recipient\n function changeFeeRecipient(address newRecipient) external;\n\n /// @notice Propose or execute a hook root update\n /// @notice Propose changes to vault-specific fee configuration\n /// @param performanceFeeBps New performance fee in basis points\n /// @param managementFeeBps New management fee in basis points\n /// @param recipient New fee recipient\n /// @dev IMPORTANT: Before executing the proposed update (via executeVaultFeeConfigUpdate),\n /// manager should call skimPerformanceFee() to collect performance fees on existing profits\n /// under the current fee structure to avoid losing profit or incorrect fee calculations.\n function proposeVaultFeeConfigUpdate(\n uint256 performanceFeeBps,\n uint256 managementFeeBps,\n address recipient\n )\n external;\n\n /// @notice Execute the proposed vault fee configuration update after timelock\n /// @dev IMPORTANT: Manager should call skimPerformanceFee() before executing this update\n /// to collect performance fees on existing profits under the current fee structure.\n /// Otherwise, profit earned under the old fee percentage will be lost or incorrectly calculated.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// to avoid incorrect fee calculations with the new fee structure.\n function executeVaultFeeConfigUpdate() external;\n\n /// @notice Reset the high-water mark PPS to the current PPS\n /// @dev This function is only callable by Aggregator\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value\n /// @param newHwmPps The new high-water mark PPS value\n function resetHighWaterMark(uint256 newHwmPps) external;\n\n /// @notice Manage PPS expiry threshold\n /// @param action Type of action (see PPSExpirationAction enum)\n /// @param ppsExpiration The new PPS expiry threshold\n function managePPSExpiration(PPSExpirationAction action, uint256 ppsExpiration) external;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /*//////////////////////////////////////////////////////////////\n USER OPERATIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Set the slippage tolerance for all future redeem request fulfillments, until reset using this function\n /// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)\n function setRedeemSlippage(uint16 slippageBps) external;\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Get the vault info\n function getVaultInfo() external view returns (address vault, address asset, uint8 vaultDecimals);\n\n /// @notice Get the fee configurations\n function getConfigInfo() external view returns (FeeConfig memory feeConfig);\n\n /// @notice Returns the currently stored PPS value.\n function getStoredPPS() external view returns (uint256);\n\n /// @notice Get a yield source's configuration\n function getYieldSource(address source) external view returns (YieldSource memory);\n\n /// @notice Get all yield sources with their information\n /// @return Array of YieldSourceInfo structs\n function getYieldSourcesList() external view returns (YieldSourceInfo[] memory);\n\n /// @notice Get all yield source addresses\n /// @return Array of yield source addresses\n function getYieldSources() external view returns (address[] memory);\n\n /// @notice Get the count of yield sources\n /// @return Number of yield sources\n function getYieldSourcesCount() external view returns (uint256);\n\n /// @notice Check if a yield source exists\n /// @param source Address of the yield source\n /// @return True if the yield source exists\n function containsYieldSource(address source) external view returns (bool);\n\n /// @notice Get the average withdraw price for a controller\n /// @param controller The controller address\n /// @return averageWithdrawPrice The average withdraw price\n function getAverageWithdrawPrice(address controller) external view returns (uint256 averageWithdrawPrice);\n\n /// @notice Get the super vault state for a controller\n /// @param controller The controller address\n /// @return state The super vault state\n function getSuperVaultState(address controller) external view returns (SuperVaultState memory state);\n\n /// @notice Get the pending redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return pendingShares The amount of shares pending redemption\n function pendingRedeemRequest(address controller) external view returns (uint256 pendingShares);\n\n /// @notice Get the pending cancellation for a redeem request for a controller\n /// @param controller The controller address\n /// @return isPending True if the redeem request is pending cancellation\n function pendingCancelRedeemRequest(address controller) external view returns (bool isPending);\n\n /// @notice Get the claimable cancel redeem request amount (shares) for a controller\n /// @param controller The controller address\n /// @return claimableShares The amount of shares claimable\n function claimableCancelRedeemRequest(address controller) external view returns (uint256 claimableShares);\n\n /// @notice Get the claimable withdraw amount (assets) for a controller\n /// @param controller The controller address\n /// @return claimableAssets The amount of assets claimable\n function claimableWithdraw(address controller) external view returns (uint256 claimableAssets);\n\n /// @notice Preview exact redeem fulfillment for off-chain calculation\n /// @param controller The controller address to preview\n /// @return shares Pending redeem shares\n /// @return theoreticalAssets Theoretical assets at current PPS\n /// @return minAssets Minimum acceptable assets (slippage floor)\n function previewExactRedeem(address controller)\n external\n view\n returns (uint256 shares, uint256 theoreticalAssets, uint256 minAssets);\n\n /// @notice Batch preview exact redeem fulfillment for multiple controllers\n /// @dev Efficiently batches multiple previewExactRedeem calls to reduce RPC overhead\n /// @param controllers Array of controller addresses to preview\n /// @return totalTheoAssets Total theoretical assets across all controllers\n /// @return individualAssets Array of theoretical assets per controller\n function previewExactRedeemBatch(address[] calldata controllers)\n external\n view\n returns (uint256 totalTheoAssets, uint256[] memory individualAssets);\n\n /// @notice Get the current unrealized profit above the High Water Mark\n /// @return profit Current profit above High Water Mark (in assets), 0 if no profit\n /// @dev Calculates based on PPS growth: (currentPPS - hwmPPS) * totalSupply / PRECISION\n /// @dev Returns 0 if totalSupply is 0 or currentPPS <= hwmPPS\n function vaultUnrealizedProfit() external view returns (uint256);\n}\n"},"src/interfaces/ISuperGovernor.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IAccessControl } from \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/*//////////////////////////////////////////////////////////////\n ENUMS\n //////////////////////////////////////////////////////////////*/\n/// @notice Enum representing different types of fees that can be managed\nenum FeeType {\n REVENUE_SHARE,\n PERFORMANCE_FEE_SHARE\n}\n/// @title ISuperGovernor\n/// @author Superform Labs\n/// @notice Interface for the SuperGovernor contract\n/// @dev Central registry for all deployed contracts in the Superform periphery\n\ninterface ISuperGovernor is IAccessControl {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Structure containing Merkle root data for a hook\n struct HookMerkleRootData {\n bytes32 currentRoot; // Current active Merkle root for the hook\n bytes32 proposedRoot; // Proposed new Merkle root (zero if no proposal exists)\n uint256 effectiveTime; // Timestamp when the proposed root becomes effective\n }\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when trying to access a contract that is not registered\n error CONTRACT_NOT_FOUND();\n /// @notice Thrown when providing an invalid address (typically zero address)\n error INVALID_ADDRESS();\n /// @notice Thrown when a hook is not approved but expected to be\n error HOOK_NOT_APPROVED();\n /// @notice Thrown when an invalid fee value is proposed (must be <= BPS_MAX)\n error INVALID_FEE_VALUE();\n /// @notice Thrown when no proposed fee exists but one is expected\n error NO_PROPOSED_FEE(FeeType feeType);\n /// @notice Thrown when timelock period has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when a validator is already registered\n error VALIDATOR_ALREADY_REGISTERED();\n /// @notice Thrown when trying to change active PPS oracle directly\n error MUST_USE_TIMELOCK_FOR_CHANGE();\n /// @notice Thrown when a SuperBank hook Merkle root is not registered but expected to be\n /// @dev This error is defined here for use by other contracts in the system (SuperVaultStrategy,\n /// SuperVaultAggregator, ECDSAPPSOracle)\n error INVALID_TIMESTAMP();\n /// @notice Thrown when attempting to set an invalid quorum value (typically zero)\n error INVALID_QUORUM();\n /// @notice Thrown when validator and public key array lengths don't match\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when trying to set validator config with an empty validator array\n error EMPTY_VALIDATOR_ARRAY();\n /// @notice Thrown when no active PPS oracle is set but one is required\n error NO_ACTIVE_PPS_ORACLE();\n /// @notice Thrown when no proposed PPS oracle exists but one is expected\n error NO_PROPOSED_PPS_ORACLE();\n /// @notice Error thrown when manager takeovers are frozen\n error MANAGER_TAKEOVERS_FROZEN();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error NO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed Merkle root exists but one is expected\n error ZERO_PROPOSED_MERKLE_ROOT();\n /// @notice Thrown when no proposed minimum staleness exists but one is expected\n error NO_PROPOSED_MIN_STALENESS();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when there's no pending change but one is expected\n error NO_PENDING_CHANGE();\n /// @notice Thrown when the super oracle is not found\n error SUPER_ORACLE_NOT_FOUND();\n /// @notice Thrown when the up token is not found\n error UP_NOT_FOUND();\n /// @notice Thrown when the upkeep token is not found\n error UPKEEP_TOKEN_NOT_FOUND();\n /// @notice Thrown when the gas info is invalid\n error INVALID_GAS_INFO();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when an address is set in the registry\n /// @param key The key used to reference the address\n /// @param oldValue The old address value\n /// @param value The address value\n event AddressSet(bytes32 indexed key, address indexed oldValue, address indexed value);\n\n /// @notice Emitted when a hook is approved\n /// @param hook The address of the approved hook\n event HookApproved(address indexed hook);\n\n /// @notice Emitted when validator configuration is set\n /// @param version The version of the configuration\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys (for signature verification)\n /// @param quorum The quorum required for validator consensus\n /// @param offchainConfig Offchain configuration data\n event ValidatorConfigSet(\n uint256 version, address[] validators, bytes[] validatorPublicKeys, uint256 quorum, bytes offchainConfig\n );\n\n /// @notice Emitted when a hook is removed\n /// @param hook The address of the removed hook\n event HookRemoved(address indexed hook);\n\n /// @notice Emitted when a new fee is proposed\n /// @param feeType The type of fee being proposed\n /// @param value The proposed fee value (in basis points)\n /// @param effectiveTime The timestamp when the fee will be effective\n event FeeProposed(FeeType indexed feeType, uint256 value, uint256 effectiveTime);\n\n /// @notice Emitted when a fee is updated\n /// @param feeType The type of fee being updated\n /// @param value The new fee value (in basis points)\n event FeeUpdated(FeeType indexed feeType, uint256 value);\n\n /// @notice Emitted when a new SuperBank hook Merkle root is proposed\n /// @param hook The hook address for which the Merkle root is being proposed\n /// @param newRoot The new Merkle root\n /// @param effectiveTime The timestamp when the new root will be effective\n event SuperBankHookMerkleRootProposed(address indexed hook, bytes32 newRoot, uint256 effectiveTime);\n\n /// @notice Emitted when the SuperBank hook Merkle root is updated.\n /// @param hook The address of the hook for which the Merkle root was updated.\n /// @param newRoot The new Merkle root.\n event SuperBankHookMerkleRootUpdated(address indexed hook, bytes32 newRoot);\n\n /// @notice Emitted when an active PPS oracle is initially set\n /// @param oracle The address of the set oracle\n event ActivePPSOracleSet(address indexed oracle);\n\n /// @notice Emitted when a new PPS oracle is proposed\n /// @param oracle The address of the proposed oracle\n /// @param effectiveTime The timestamp when the proposal will be effective\n event ActivePPSOracleProposed(address indexed oracle, uint256 effectiveTime);\n\n /// @notice Emitted when the active PPS oracle is changed\n /// @param oldOracle The address of the previous oracle\n /// @param newOracle The address of the new oracle\n event ActivePPSOracleChanged(address indexed oldOracle, address indexed newOracle);\n\n /// @notice Event emitted when manager takeovers are permanently frozen\n event ManagerTakeoversFrozen();\n\n /// @notice Emitted when a change to upkeep payments status is proposed\n /// @param enabled The proposed status (enabled/disabled)\n /// @param effectiveTime The timestamp when the status change will be effective\n event UpkeepPaymentsChangeProposed(bool enabled, uint256 effectiveTime);\n\n /// @notice Emitted when upkeep payments status is changed\n /// @param enabled The new status (enabled/disabled)\n event UpkeepPaymentsChanged(bool enabled);\n\n /// @notice Emitted when a new minimum staleness is proposed\n /// @param newMinStaleness The proposed minimum staleness value\n /// @param effectiveTime The timestamp when the new value will be effective\n event MinStalenessProposed(uint256 newMinStaleness, uint256 effectiveTime);\n\n /// @notice Emitted when the minimum staleness is changed\n /// @param newMinStaleness The new minimum staleness value\n event MinStalenessChanged(uint256 newMinStaleness);\n\n /// @notice Emitted when gas info is set\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n event GasInfoSet(address indexed oracle, uint256 gasIncreasePerEntryBatch);\n\n /*//////////////////////////////////////////////////////////////\n CONTRACT REGISTRY FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets an address in the registry\n /// @param key The key to associate with the address\n /// @param value The address value\n function setAddress(bytes32 key, address value) external;\n\n /*//////////////////////////////////////////////////////////////\n PERIPHERY CONFIGURATIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Change the primary manager for a strategy\n /// @dev Only SuperGovernor can call this function directly\n /// @param strategy The strategy address\n /// @param newManager The new primary manager address\n /// @param feeRecipient The new fee recipient address\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Resets the high-water mark PPS to the current PPS\n /// @dev Only SuperGovernor can call this function\n /// @dev If a manager is replaced while the strategy is below its\n /// previous HWM, the new manager would otherwise inherit a \"loss\" state and be unable to earn performance fees\n /// until the fee config are updated after the week timelock.\n /// @dev This function will reset the High Water Mark (vaultHwmPps) to the current PPS value for the given strategy\n /// @param strategy Address of the strategy to reset the high-water mark for\n function resetHighWaterMark(address strategy) external;\n\n /// @notice Permanently freezes all manager takeovers globally\n function freezeManagerTakeover() external;\n\n /// @notice Changes the hooks root update timelock duration\n /// @param newTimelock New timelock duration in seconds\n function changeHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes a new global hooks Merkle root\n /// @dev Only GOVERNOR_ROLE can call this function\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Sets veto status for global hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Sets veto status for a strategy-specific hooks Merkle root\n /// @dev Only GUARDIAN_ROLE can call this function\n /// @param strategy Address of the strategy to affect\n /// @param vetoed Whether to veto (true) or unveto (false) the strategy hooks root\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Sets the maximum staleness period for all oracle feeds\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleMaxStaleness(uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness period for a specific oracle feed\n /// @param feed The address of the feed to set staleness for\n /// @param newMaxStaleness The new maximum staleness period in seconds\n function setOracleFeedMaxStaleness(address feed, uint256 newMaxStaleness) external;\n\n /// @notice Sets the maximum staleness periods for multiple oracle feeds in batch\n /// @param feeds The addresses of the feeds to set staleness for\n /// @param newMaxStalenessList The new maximum staleness periods in seconds\n function setOracleFeedMaxStalenessBatch(address[] calldata feeds, uint256[] calldata newMaxStalenessList) external;\n\n /// @notice Queues an oracle update for execution after timelock period\n /// @param bases Base asset addresses\n /// @param quotes Quote asset addresses\n /// @param providers Provider identifiers\n /// @param feeds Feed addresses\n function queueOracleUpdate(\n address[] calldata bases,\n address[] calldata quotes,\n bytes32[] calldata providers,\n address[] calldata feeds\n )\n external;\n\n /// @notice Executes a previously queued oracle update after timelock has expired\n function executeOracleUpdate() external;\n\n /// @notice Queues a provider removal for execution after timelock period\n /// @param providers The providers to remove\n function queueOracleProviderRemoval(bytes32[] calldata providers) external;\n\n /// @notice Sets uptime feeds for multiple data oracles in batch (Layer 2 only)\n /// @param dataOracles Array of data oracle addresses to set uptime feeds for\n /// @param uptimeOracles Array of uptime feed addresses to set\n /// @param gracePeriods Array of grace periods in seconds after sequencer restart\n function batchSetOracleUptimeFeed(\n address[] calldata dataOracles,\n address[] calldata uptimeOracles,\n uint256[] calldata gracePeriods\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Registers a hook for use in SuperVaults\n /// @param hook The address of the hook to register\n function registerHook(address hook) external;\n\n /// @notice Unregisters a hook from the approved list\n /// @param hook The address of the hook to unregister\n function unregisterHook(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n VALIDATOR MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the validator configuration for the protocol\n /// @dev This function atomically updates all validator configuration including quorum.\n /// The entire validator set is replaced (not incrementally updated).\n /// Version must be managed externally for cross-chain synchronization.\n /// Quorum updates require providing the full validator list.\n /// @param version The version number for the configuration (for cross-chain sync)\n /// @param validators Array of validator addresses\n /// @param validatorPublicKeys Array of validator public keys for signature verification\n /// @param quorum The number of validators required for consensus\n /// @param offchainConfig Offchain configuration data (emitted but not stored)\n function setValidatorConfig(\n uint256 version,\n address[] calldata validators,\n bytes[] calldata validatorPublicKeys,\n uint256 quorum,\n bytes calldata offchainConfig\n )\n external;\n\n /*//////////////////////////////////////////////////////////////\n PPS ORACLE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets the active PPS oracle (only if there is no active oracle yet)\n /// @param oracle Address of the PPS oracle to set as active\n function setActivePPSOracle(address oracle) external;\n\n /// @notice Proposes a new active PPS oracle (when there is already an active one)\n /// @param oracle Address of the PPS oracle to propose as active\n function proposeActivePPSOracle(address oracle) external;\n\n /// @notice Executes a previously proposed PPS oracle change after timelock has expired\n function executeActivePPSOracleChange() external;\n\n /*//////////////////////////////////////////////////////////////\n REVENUE SHARE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new fee value\n /// @param feeType The type of fee to propose\n /// @param value The proposed fee value (in basis points)\n function proposeFee(FeeType feeType, uint256 value) external;\n\n /// @notice Executes a previously proposed fee update after timelock has expired\n /// @param feeType The type of ffee to execute the update for\n function executeFeeUpdate(FeeType feeType) external;\n\n /// @notice Executes an upkeep claim on `SuperVaultAggregator`\n /// @param amount The amount to claim\n function executeUpkeepClaim(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP COST MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets gas info for an oracle\n /// @param oracle The address of the oracle\n /// @param gasIncreasePerEntryBatch The gas increase per entry for the oracle\n function setGasInfo(address oracle, uint256 gasIncreasePerEntryBatch) external;\n\n /// @notice Proposes a change to upkeep payments enabled status\n /// @param enabled The proposed enabled status\n function proposeUpkeepPaymentsChange(bool enabled) external;\n\n /// @notice Executes a previously proposed upkeep payments status change\n function executeUpkeepPaymentsChange() external;\n\n /*//////////////////////////////////////////////////////////////\n MIN STALENESS MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new minimum staleness value to prevent maxStaleness from being set too low\n /// @param newMinStaleness The proposed new minimum staleness value in seconds\n function proposeMinStaleness(uint256 newMinStaleness) external;\n\n /// @notice Executes a previously proposed minimum staleness change after timelock has expired\n function executeMinStalenessChange() external;\n\n /*//////////////////////////////////////////////////////////////\n SUPERBANK HOOKS MGMT\n //////////////////////////////////////////////////////////////*/\n /// @notice Proposes a new Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to update the Merkle root for.\n /// @param proposedRoot The proposed new Merkle root.\n function proposeSuperBankHookMerkleRoot(address hook, bytes32 proposedRoot) external;\n\n /// @notice Executes a previously proposed Merkle root update for a specific hook if the effective time has passed.\n /// @param hook The address of the hook to execute the update for.\n function executeSuperBankHookMerkleRootUpdate(address hook) external;\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice The identifier of the role that grants access to critical governance functions\n function SUPER_GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to daily operations like hooks and validators\n function GOVERNOR_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to bank management functions\n function BANK_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to gas management functions\n function GAS_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to oracle management functions\n function ORACLE_MANAGER_ROLE() external view returns (bytes32);\n\n /// @notice The identifier of the role that grants access to guardian functions\n function GUARDIAN_ROLE() external view returns (bytes32);\n\n /// @notice Gets an address from the registry\n /// @param key The key of the address to get\n /// @return The address value\n function getAddress(bytes32 key) external view returns (address);\n\n /// @notice Checks if manager takeovers are frozen\n /// @return True if manager takeovers are frozen, false otherwise\n function isManagerTakeoverFrozen() external view returns (bool);\n\n /// @notice Checks if a hook is registered\n /// @param hook The address of the hook to check\n /// @return True if the hook is registered, false otherwise\n function isHookRegistered(address hook) external view returns (bool);\n\n /// @notice Gets all registered hooks\n /// @return An array of registered hook addresses\n function getRegisteredHooks() external view returns (address[] memory);\n\n /// @notice Checks if an address is an approved validator\n /// @param validator The address to check\n /// @return True if the address is an approved validator, false otherwise\n function isValidator(address validator) external view returns (bool);\n\n /// @notice Checks if an address has the guardian role\n /// @param guardian Address to check\n /// @return true if the address has the GUARDIAN_ROLE\n function isGuardian(address guardian) external view returns (bool);\n\n /// @notice Returns the complete validator configuration\n /// @return version The current configuration version number\n /// @return validators Array of all registered validator addresses\n /// @return validatorPublicKeys Array of validator public keys\n /// @return quorum The number of validators required for consensus\n function getValidatorConfig()\n external\n view\n returns (uint256 version, address[] memory validators, bytes[] memory validatorPublicKeys, uint256 quorum);\n\n /// @notice Returns all registered validators\n /// @return List of validator addresses\n function getValidators() external view returns (address[] memory);\n\n /// @notice Returns the number of registered validators (O(1))\n function getValidatorsCount() external view returns (uint256);\n\n /// @notice Returns a validator address by index (0 … count-1)\n /// @param index The index into the validators set\n /// @return validator The validator address at the given index\n function getValidatorAt(uint256 index) external view returns (address validator);\n\n /// @notice Gets the proposed active PPS oracle and its effective time\n /// @return proposedOracle The proposed oracle address\n /// @return effectiveTime The timestamp when the proposed oracle will become effective\n function getProposedActivePPSOracle() external view returns (address proposedOracle, uint256 effectiveTime);\n\n /// @notice Gets the current quorum requirement for the active PPS Oracle\n /// @return The current quorum requirement\n function getPPSOracleQuorum() external view returns (uint256);\n\n /// @notice Gets the active PPS oracle\n /// @return The active PPS oracle address\n function getActivePPSOracle() external view returns (address);\n\n /// @notice Checks if an address is the current active PPS oracle\n /// @param oracle The address to check\n /// @return True if the address is the active PPS oracle, false otherwise\n function isActivePPSOracle(address oracle) external view returns (bool);\n\n /// @notice Gets the current fee value for a specific fee type\n /// @param feeType The type of fee to get\n /// @return The current fee value (in basis points)\n function getFee(FeeType feeType) external view returns (uint256);\n\n /// @notice Gets the current upkeep cost for an entry\n function getUpkeepCostPerSingleUpdate(address oracle_) external view returns (uint256);\n\n /// @notice Gets the proposed upkeep cost per update and its effective time\n /// @notice Gets the current minimum staleness value\n /// @return The current minimum staleness value in seconds\n function getMinStaleness() external view returns (uint256);\n\n /// @notice Gets the proposed minimum staleness value and its effective time\n /// @return proposedMinStaleness The proposed new minimum staleness value\n /// @return effectiveTime The timestamp when the new value will become effective\n function getProposedMinStaleness() external view returns (uint256 proposedMinStaleness, uint256 effectiveTime);\n\n /// @notice Returns the current Merkle root for a specific hook's allowed targets.\n /// @param hook The address of the hook to get the Merkle root for.\n /// @return The Merkle root for the hook's allowed targets.\n function getSuperBankHookMerkleRoot(address hook) external view returns (bytes32);\n\n /// @notice Gets the proposed Merkle root and its effective time for a specific hook.\n /// @param hook The address of the hook to get the proposed Merkle root for.\n /// @return proposedRoot The proposed Merkle root.\n /// @return effectiveTime The timestamp when the proposed root will become effective.\n function getProposedSuperBankHookMerkleRoot(address hook)\n external\n view\n returns (bytes32 proposedRoot, uint256 effectiveTime);\n\n /// @notice Checks if upkeep payments are currently enabled\n /// @return enabled True if upkeep payments are enabled\n function isUpkeepPaymentsEnabled() external view returns (bool);\n\n /// @notice Gets the proposed upkeep payments status and effective time\n /// @return enabled The proposed status\n /// @return effectiveTime The timestamp when the change becomes effective\n function getProposedUpkeepPaymentsStatus() external view returns (bool enabled, uint256 effectiveTime);\n\n /// @notice Gets the SUP strategy ID\n /// @return The ID of the SUP strategy vault\n function SUP_STRATEGY() external view returns (bytes32);\n\n /// @notice Gets the UP ID\n /// @return The ID of the UP token\n function UP() external view returns (bytes32);\n\n /// @notice Gets the UPKEEP_TOKEN ID\n /// @return The ID of the UPKEEP_TOKEN (used for upkeep payments, can be UP on mainnet or WETH/USDC on L2s)\n function UPKEEP_TOKEN() external view returns (bytes32);\n\n /// @notice Gets the Treasury ID\n /// @return The ID for the Treasury in the registry\n function TREASURY() external view returns (bytes32);\n\n /// @notice Gets the SuperOracle ID\n /// @return The ID for the SuperOracle in the registry\n function SUPER_ORACLE() external view returns (bytes32);\n\n /// @notice Gets the ECDSA PPS Oracle ID\n /// @return The ID for the ECDSA PPS Oracle in the registry\n function ECDSAPPSORACLE() external view returns (bytes32);\n\n /// @notice Gets the SuperVaultAggregator ID\n /// @return The ID for the SuperVaultAggregator in the registry\n function SUPER_VAULT_AGGREGATOR() external view returns (bytes32);\n\n /// @notice Gets the SuperBank ID\n /// @return The ID for the SuperBank in the registry\n function SUPER_BANK() external view returns (bytes32);\n\n /// @notice Gets the gas info for a specific SuperVault PPS Oracle\n /// @param oracle_ The address of the oracle to get gas info for\n /// @return The gas info for the specified oracle\n function getGasInfo(address oracle_) external view returns (uint256);\n\n /// @notice Cancels a previously proposed oracle provider removal\n function cancelOracleProviderRemoval() external;\n\n /// @notice Executes a previously proposed oracle provider removal after timelock has expired\n function executeOracleProviderRemoval() external;\n}\n"},"src/interfaces/SuperVault/ISuperVaultAggregator.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { ISuperVaultStrategy } from \"../SuperVault/ISuperVaultStrategy.sol\";\n\n/// @title ISuperVaultAggregator\n/// @author Superform Labs\n/// @notice Interface for the SuperVaultAggregator contract\n/// @dev Registry and PPS oracle for all SuperVaults\ninterface ISuperVaultAggregator {\n /*//////////////////////////////////////////////////////////////\n STRUCTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for forwarding PPS updates to avoid stack too deep errors\n /// @param strategy Address of the strategy being updated\n /// @param isExempt Whether the update is exempt from paying upkeep\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp when the value was generated\n /// @param upkeepCost Amount of upkeep tokens to charge if not exempt\n struct PPSUpdateData {\n address strategy;\n bool isExempt;\n uint256 pps;\n uint256 timestamp;\n uint256 upkeepCost;\n }\n\n /// @notice Local variables for vault creation to avoid stack too deep\n /// @param currentNonce Current vault creation nonce\n /// @param salt Salt for deterministic proxy creation\n /// @param initialPPS Initial price-per-share value\n struct VaultCreationLocalVars {\n uint256 currentNonce;\n bytes32 salt;\n uint256 initialPPS;\n }\n\n /// @notice Strategy configuration and state data\n /// @param pps Current price-per-share value\n /// @param lastUpdateTimestamp Last time PPS was updated\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param isPaused Whether the strategy is paused\n /// @param mainManager Address of the primary manager controlling the strategy\n /// @param secondaryManagers Set of secondary managers that can manage the strategy\n struct StrategyData {\n uint256 pps; // Slot 0: 32 bytes\n uint256 lastUpdateTimestamp; // Slot 1: 32 bytes\n uint256 minUpdateInterval; // Slot 2: 32 bytes\n uint256 maxStaleness; // Slot 3: 32 bytes\n // Packed slot 4: saves 2 storage slots (~4000 gas per read)\n address mainManager; // 20 bytes\n bool ppsStale; // 1 byte\n bool isPaused; // 1 byte\n bool hooksRootVetoed; // 1 byte\n uint72 __gap1; // 9 bytes padding\n EnumerableSet.AddressSet secondaryManagers;\n // Manager change proposal data\n address proposedManager;\n address proposedFeeRecipient;\n uint256 managerChangeEffectiveTime;\n // Hook validation data\n bytes32 managerHooksRoot;\n // Hook root update proposal data\n bytes32 proposedHooksRoot;\n uint256 hooksRootEffectiveTime;\n // PPS Verification thresholds\n uint256 deviationThreshold; // Threshold for abs(new - current) / current\n // Banned global leaves mapping\n mapping(bytes32 => bool) bannedLeaves; // Mapping of leaf hash to banned status\n // Min update interval proposal data\n uint256 proposedMinUpdateInterval;\n uint256 minUpdateIntervalEffectiveTime;\n uint256 lastUnpauseTimestamp; // Timestamp of last unpause (for skim timelock)\n }\n\n /// @notice Parameters for creating a new SuperVault trio\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param mainManager Address of the vault mainManager\n /// @param minUpdateInterval Minimum time interval between PPS updates\n /// @param maxStaleness Maximum time allowed between PPS updates before staleness\n /// @param feeConfig Fee configuration for the vault\n struct VaultCreationParams {\n address asset;\n string name;\n string symbol;\n address mainManager;\n address[] secondaryManagers;\n uint256 minUpdateInterval;\n uint256 maxStaleness;\n ISuperVaultStrategy.FeeConfig feeConfig;\n }\n\n /// @notice Struct to hold cached hook validation state variables to avoid stack too deep\n /// @param globalHooksRootVetoed Cached global hooks root veto status\n /// @param globalHooksRoot Cached global hooks root\n /// @param strategyHooksRootVetoed Cached strategy hooks root veto status\n /// @param strategyRoot Cached strategy hooks root\n struct HookValidationCache {\n bool globalHooksRootVetoed;\n bytes32 globalHooksRoot;\n bool strategyHooksRootVetoed;\n bytes32 strategyRoot;\n }\n\n /// @notice Arguments for validating a hook to avoid stack too deep\n /// @param hookAddress Address of the hook contract\n /// @param hookArgs Encoded arguments for the hook operation\n /// @param globalProof Merkle proof for the global root\n /// @param strategyProof Merkle proof for the strategy-specific root\n struct ValidateHookArgs {\n address hookAddress;\n bytes hookArgs;\n bytes32[] globalProof;\n bytes32[] strategyProof;\n }\n\n /// @notice Two-step upkeep withdrawal request\n /// @param amount Amount to withdraw (full balance at time of request)\n /// @param effectiveTime When withdrawal can be executed (timestamp + 24h)\n struct UpkeepWithdrawalRequest {\n uint256 amount;\n uint256 effectiveTime;\n }\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /// @notice Emitted when a new vault trio is created\n /// @param vault Address of the created SuperVault\n /// @param strategy Address of the created SuperVaultStrategy\n /// @param escrow Address of the created SuperVaultEscrow\n /// @param asset Address of the underlying asset\n /// @param name Name of the vault token\n /// @param symbol Symbol of the vault token\n /// @param nonce The nonce used for vault creation\n event VaultDeployed(\n address indexed vault,\n address indexed strategy,\n address escrow,\n address asset,\n string name,\n string symbol,\n uint256 indexed nonce\n );\n\n /// @notice Emitted when a PPS value is updated\n /// @param strategy Address of the strategy\n /// @param pps New price-per-share value\n /// @param timestamp Timestamp of the update\n event PPSUpdated(address indexed strategy, uint256 pps, uint256 timestamp);\n\n /// @notice Emitted when a strategy is paused due to missed updates\n /// @param strategy Address of the paused strategy\n event StrategyPaused(address indexed strategy);\n\n /// @notice Emitted when a strategy is unpaused\n /// @param strategy Address of the unpaused strategy\n event StrategyUnpaused(address indexed strategy);\n\n /// @notice Emitted when a strategy validation check fails but execution continues\n /// @param strategy Address of the strategy that failed the check\n /// @param reason String description of which check failed\n event StrategyCheckFailed(address indexed strategy, string reason);\n\n /// @notice Emitted when upkeep tokens are deposited\n /// @param strategy Address of the strategy\n /// @param depositor Address of the depositor\n /// @param amount Amount of upkeep tokens deposited\n event UpkeepDeposited(address indexed strategy, address indexed depositor, uint256 amount);\n\n /// @notice Emitted when upkeep tokens are withdrawn\n /// @param strategy Address of the strategy\n /// @param withdrawer Address of the withdrawer (main manager of the strategy)\n /// @param amount Amount of upkeep tokens withdrawn\n event UpkeepWithdrawn(address indexed strategy, address indexed withdrawer, uint256 amount);\n\n /// @notice Emitted when an upkeep withdrawal is proposed (start of 24h timelock)\n /// @param strategy Address of the strategy\n /// @param mainManager Address of the main manager who proposed the withdrawal\n /// @param amount Amount of upkeep tokens to withdraw\n /// @param effectiveTime Timestamp when withdrawal can be executed\n event UpkeepWithdrawalProposed(\n address indexed strategy, address indexed mainManager, uint256 amount, uint256 effectiveTime\n );\n\n /// @notice Emitted when a pending upkeep withdrawal is cancelled (e.g., during governance takeover)\n /// @param strategy Address of the strategy\n event UpkeepWithdrawalCancelled(address indexed strategy);\n\n /// @notice Emitted when upkeep tokens are spent for validation\n /// @param strategy Address of the strategy\n /// @param amount Amount of upkeep tokens spent\n /// @param balance Current balance of the strategy\n /// @param claimableUpkeep Amount of upkeep tokens claimable\n event UpkeepSpent(address indexed strategy, uint256 amount, uint256 balance, uint256 claimableUpkeep);\n\n /// @notice Emitted when a secondary manager is added to a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager added\n event SecondaryManagerAdded(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a secondary manager is removed from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager removed\n event SecondaryManagerRemoved(address indexed strategy, address indexed manager);\n\n /// @notice Emitted when a primary manager is changed\n /// @param strategy Address of the strategy\n /// @param oldManager Address of the old primary manager\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n event PrimaryManagerChanged(\n address indexed strategy, address indexed oldManager, address indexed newManager, address feeRecipient\n );\n\n /// @notice Emitted when a change to primary manager is proposed by a secondary manager\n /// @param strategy Address of the strategy\n /// @param proposer Address of the secondary manager who made the proposal\n /// @param newManager Address of the proposed new primary manager\n /// @param effectiveTime Timestamp when the proposal can be executed\n event PrimaryManagerChangeProposed(\n address indexed strategy,\n address indexed proposer,\n address indexed newManager,\n address feeRecipient,\n uint256 effectiveTime\n );\n\n /// @notice Emitted when a primary manager change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledManager Address of the manager that was proposed\n event PrimaryManagerChangeCancelled(address indexed strategy, address indexed cancelledManager);\n\n /// @notice Emitted when the High Water Mark for a strategy is reset to PPS\n /// @param strategy Address of the strategy\n /// @param newHWM The new High Water Mark (PPS)\n event HighWaterMarkReset(address indexed strategy, uint256 indexed newHWM);\n\n /// @notice Emitted when a PPS update is stale (Validators could get slashed for innactivity)\n /// @param strategy Address of the strategy\n /// @param updateAuthority Address of the update authority\n /// @param timestamp Timestamp of the stale update\n event StaleUpdate(address indexed strategy, address indexed updateAuthority, uint256 timestamp);\n\n /// @notice Emitted when the global hooks Merkle root is being updated\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event GlobalHooksRootUpdateProposed(bytes32 indexed root, uint256 effectiveTime);\n\n /// @notice Emitted when the global hooks Merkle root is updated\n /// @param oldRoot Previous root value\n /// @param newRoot New root value\n event GlobalHooksRootUpdated(bytes32 indexed oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is updated\n /// @param strategy Address of the strategy\n /// @param oldRoot Previous root value (may be zero)\n /// @param newRoot New root value\n event StrategyHooksRootUpdated(address indexed strategy, bytes32 oldRoot, bytes32 newRoot);\n\n /// @notice Emitted when a strategy-specific hooks Merkle root is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the account proposing the new root\n /// @param root New root value\n /// @param effectiveTime Timestamp when the root becomes effective\n event StrategyHooksRootUpdateProposed(\n address indexed strategy, address indexed proposer, bytes32 root, uint256 effectiveTime\n );\n\n /// @notice Emitted when a proposed global hooks root update is vetoed by SuperGovernor\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event GlobalHooksRootVetoStatusChanged(bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's hooks Merkle root veto status changes\n /// @param strategy Address of the strategy\n /// @param vetoed Whether the root is being vetoed (true) or unvetoed (false)\n /// @param root The root value affected\n event StrategyHooksRootVetoStatusChanged(address indexed strategy, bool vetoed, bytes32 indexed root);\n\n /// @notice Emitted when a strategy's deviation threshold is updated\n /// @param strategy Address of the strategy\n /// @param deviationThreshold New deviation threshold (abs diff/current)\n event DeviationThresholdUpdated(address indexed strategy, uint256 deviationThreshold);\n\n /// @notice Emitted when the hooks root update timelock is changed\n /// @param newTimelock New timelock duration in seconds\n event HooksRootUpdateTimelockChanged(uint256 newTimelock);\n\n /// @notice Emitted when global leaves status is changed for a strategy\n /// @param strategy Address of the strategy\n /// @param leaves Array of leaf hashes that had their status changed\n /// @param statuses Array of new banned statuses (true = banned, false = allowed)\n event GlobalLeavesStatusChanged(address indexed strategy, bytes32[] leaves, bool[] statuses);\n\n /// @notice Emitted when upkeep is claimed\n /// @param superBank Address of the superBank\n /// @param amount Amount of upkeep claimed\n event UpkeepClaimed(address indexed superBank, uint256 amount);\n\n /// @notice Emitted when PPS update is too frequent (before minUpdateInterval)\n event UpdateTooFrequent();\n\n /// @notice Emitted when PPS update timestamp is not monotonically increasing\n event TimestampNotMonotonic();\n\n /// @notice Emitted when PPS update is rejected due to stale signature after unpause\n event StaleSignatureAfterUnpause(\n address indexed strategy, uint256 signatureTimestamp, uint256 lastUnpauseTimestamp\n );\n\n /// @notice Emitted when a strategy does not have enough upkeep balance\n event InsufficientUpkeep(address indexed strategy, address indexed strategyAddr, uint256 balance, uint256 cost);\n\n /// @notice Emitted when the provided timestamp is too large\n event ProvidedTimestampExceedsBlockTimestamp(\n address indexed strategy, uint256 argsTimestamp, uint256 blockTimestamp\n );\n\n /// @notice Emitted when a strategy is unknown\n event UnknownStrategy(address indexed strategy);\n\n /// @notice Emitted when the old primary manager is removed from the strategy\n /// @dev This can happen because of reaching the max number of secondary managers\n event OldPrimaryManagerRemoved(address indexed strategy, address indexed oldManager);\n\n /// @notice Emitted when a strategy's PPS is stale\n event StrategyPPSStale(address indexed strategy);\n\n /// @notice Emitted when a strategy's PPS is reset\n event StrategyPPSStaleReset(address indexed strategy);\n\n /// @notice Emitted when PPS is updated after performance fee skimming\n /// @param strategy Address of the strategy\n /// @param oldPPS Previous price-per-share value\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee skimmed that caused the PPS update\n /// @param timestamp Timestamp of the update\n event PPSUpdatedAfterSkim(\n address indexed strategy, uint256 oldPPS, uint256 newPPS, uint256 feeAmount, uint256 timestamp\n );\n\n /// @notice Emitted when a change to minUpdateInterval is proposed\n /// @param strategy Address of the strategy\n /// @param proposer Address of the manager who made the proposal\n /// @param newMinUpdateInterval The proposed new minimum update interval\n /// @param effectiveTime Timestamp when the proposal can be executed\n event MinUpdateIntervalChangeProposed(\n address indexed strategy, address indexed proposer, uint256 newMinUpdateInterval, uint256 effectiveTime\n );\n\n /// @notice Emitted when a minUpdateInterval change is executed\n /// @param strategy Address of the strategy\n /// @param oldMinUpdateInterval Previous minimum update interval\n /// @param newMinUpdateInterval New minimum update interval\n event MinUpdateIntervalChanged(\n address indexed strategy, uint256 oldMinUpdateInterval, uint256 newMinUpdateInterval\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is rejected due to validation failure\n /// @param strategy Address of the strategy\n /// @param proposedInterval The proposed interval that was rejected\n /// @param currentMaxStaleness The current maxStaleness value that caused rejection\n event MinUpdateIntervalChangeRejected(\n address indexed strategy, uint256 proposedInterval, uint256 currentMaxStaleness\n );\n\n /// @notice Emitted when a minUpdateInterval change proposal is cancelled\n /// @param strategy Address of the strategy\n /// @param cancelledInterval The proposed interval that was cancelled\n event MinUpdateIntervalChangeCancelled(address indexed strategy, uint256 cancelledInterval);\n\n /// @notice Emitted when a PPS update is rejected because strategy is paused\n /// @param strategy Address of the paused strategy\n event PPSUpdateRejectedStrategyPaused(address indexed strategy);\n\n /*///////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n /// @notice Thrown when address provided is zero\n error ZERO_ADDRESS();\n /// @notice Thrown when amount provided is zero\n error ZERO_AMOUNT();\n /// @notice Thrown when vault creation parameters are invalid (empty name or symbol)\n error INVALID_VAULT_PARAMS();\n /// @notice Thrown when array length is zero\n error ZERO_ARRAY_LENGTH();\n /// @notice Thrown when array length is zero\n error ARRAY_LENGTH_MISMATCH();\n /// @notice Thrown when asset is invalid\n error INVALID_ASSET();\n /// @notice Thrown when insufficient upkeep balance for operation\n error INSUFFICIENT_UPKEEP();\n /// @notice Thrown when caller is not authorized\n error CALLER_NOT_AUTHORIZED();\n /// @notice Thrown when caller is not an approved PPS oracle\n error UNAUTHORIZED_PPS_ORACLE();\n /// @notice Thrown when caller is not authorized for update\n error UNAUTHORIZED_UPDATE_AUTHORITY();\n /// @notice Thrown when strategy address is not a known SuperVault strategy\n error UNKNOWN_STRATEGY();\n /// @notice Thrown when trying to unpause a strategy that is not paused\n error STRATEGY_NOT_PAUSED();\n /// @notice Thrown when trying to pause a strategy that is already paused\n error STRATEGY_ALREADY_PAUSED();\n /// @notice Thrown when array index is out of bounds\n error INDEX_OUT_OF_BOUNDS();\n /// @notice Thrown when attempting to add a manager that already exists\n error MANAGER_ALREADY_EXISTS();\n /// @notice Thrown when attempting to add a manager that is the primary manager\n error SECONDARY_MANAGER_CANNOT_BE_PRIMARY();\n /// @notice Thrown when there is no pending global hooks root change\n error NO_PENDING_GLOBAL_ROOT_CHANGE();\n /// @notice Thrown when attempting to execute a hooks root change before timelock has elapsed\n error ROOT_UPDATE_NOT_READY();\n /// @notice Thrown when a provided hook fails Merkle proof validation\n error HOOK_VALIDATION_FAILED();\n /// @notice Thrown when manager is not found\n error MANAGER_NOT_FOUND();\n /// @notice Thrown when there is no pending manager change proposal\n error NO_PENDING_MANAGER_CHANGE();\n /// @notice Thrown when caller is not authorized to update settings\n error UNAUTHORIZED_CALLER();\n /// @notice Thrown when the timelock for a proposed change has not expired\n error TIMELOCK_NOT_EXPIRED();\n /// @notice Thrown when an array length is invalid\n error INVALID_ARRAY_LENGTH();\n /// @notice Thrown when the provided maxStaleness is less than the minimum required staleness\n error MAX_STALENESS_TOO_LOW();\n /// @notice Thrown when arrays have mismatched lengths\n error MISMATCHED_ARRAY_LENGTHS();\n /// @notice Thrown when timestamp is invalid\n error INVALID_TIMESTAMP(uint256 index);\n /// @notice Thrown when too many secondary managers are added\n error TOO_MANY_SECONDARY_MANAGERS();\n /// @notice Thrown when upkeep withdrawal timelock has not passed yet\n error UPKEEP_WITHDRAWAL_NOT_READY();\n /// @notice Thrown when no pending upkeep withdrawal request exists\n error UPKEEP_WITHDRAWAL_NOT_FOUND();\n /// @notice PPS must decrease after skimming fees\n error PPS_MUST_DECREASE_AFTER_SKIM();\n /// @notice PPS deduction is larger than the maximum allowed fee rate\n error PPS_DEDUCTION_TOO_LARGE();\n /// @notice Thrown when no minUpdateInterval change proposal is pending\n error NO_PENDING_MIN_UPDATE_INTERVAL_CHANGE();\n /// @notice Thrown when minUpdateInterval >= maxStaleness\n error MIN_UPDATE_INTERVAL_TOO_HIGH();\n /// @notice Thrown when trying to update PPS while strategy is paused\n error STRATEGY_PAUSED();\n /// @notice Thrown when trying to update PPS while PPS is stale\n error PPS_STALE();\n\n /*//////////////////////////////////////////////////////////////\n VAULT CREATION\n //////////////////////////////////////////////////////////////*/\n /// @notice Creates a new SuperVault trio (SuperVault, SuperVaultStrategy, SuperVaultEscrow)\n /// @param params Parameters for the new vault creation\n /// @return superVault Address of the created SuperVault\n /// @return strategy Address of the created SuperVaultStrategy\n /// @return escrow Address of the created SuperVaultEscrow\n function createVault(VaultCreationParams calldata params)\n external\n returns (address superVault, address strategy, address escrow);\n\n /*//////////////////////////////////////////////////////////////\n PPS UPDATE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Arguments for batch forwarding PPS updates\n /// @param strategies Array of strategy addresses\n /// @param ppss Array of price-per-share values\n /// @param timestamps Array of timestamps when values were generated\n /// @param updateAuthority Address of the update authority\n struct ForwardPPSArgs {\n address[] strategies;\n uint256[] ppss;\n uint256[] timestamps;\n address updateAuthority;\n }\n\n /// @notice Batch forwards validated PPS updates to multiple strategies\n /// @param args Struct containing all batch PPS update parameters\n function forwardPPS(ForwardPPSArgs calldata args) external;\n\n /// @notice Updates PPS directly after performance fee skimming\n /// @dev Only callable by the strategy contract itself (msg.sender must be a registered strategy)\n /// @param newPPS New price-per-share value after fee deduction\n /// @param feeAmount Amount of fee that was skimmed (for event logging)\n function updatePPSAfterSkim(uint256 newPPS, uint256 feeAmount) external;\n\n /*//////////////////////////////////////////////////////////////\n UPKEEP MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Deposits upkeep tokens for strategy upkeep\n /// @dev The upkeep token is configurable per chain (UP on mainnet, WETH on L2s, etc.)\n /// @param strategy Address of the strategy to deposit for\n /// @param amount Amount of upkeep tokens to deposit\n function depositUpkeep(address strategy, uint256 amount) external;\n\n /// @notice Proposes withdrawal of upkeep tokens from strategy upkeep balance (starts 24h timelock)\n /// @dev Only the main manager can propose. Withdraws full balance at time of proposal.\n /// @param strategy Address of the strategy to withdraw from\n function proposeWithdrawUpkeep(address strategy) external;\n\n /// @notice Executes a pending upkeep withdrawal after 24h timelock\n /// @dev Anyone can execute, but funds go to the main manager of the strategy\n /// @param strategy Address of the strategy to withdraw from\n function executeWithdrawUpkeep(address strategy) external;\n\n /// @notice Claims upkeep tokens from the contract\n /// @param amount Amount of upkeep tokens to claim\n function claimUpkeep(uint256 amount) external;\n\n /*//////////////////////////////////////////////////////////////\n PAUSE MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Manually pauses a strategy\n /// @param strategy Address of the strategy to pause\n function pauseStrategy(address strategy) external;\n\n /// @notice Manually unpauses a strategy\n /// @param strategy Address of the strategy to unpause\n function unpauseStrategy(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MANAGER MANAGEMENT FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Adds a secondary manager to a strategy\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to add\n function addSecondaryManager(address strategy, address manager) external;\n\n /// @notice Removes a secondary manager from a strategy\n /// @param strategy Address of the strategy\n /// @param manager Address of the manager to remove\n function removeSecondaryManager(address strategy, address manager) external;\n\n /// @notice Changes the primary manager of a strategy immediately (only callable by SuperGovernor)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function changePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Proposes a change to the primary manager (callable by secondary managers)\n /// @notice A manager can either be secondary or primary\n /// @param strategy Address of the strategy\n /// @param newManager Address of the proposed new primary manager\n /// @param feeRecipient Address of the new fee recipient\n function proposeChangePrimaryManager(address strategy, address newManager, address feeRecipient) external;\n\n /// @notice Cancels a pending primary manager change proposal\n /// @dev Only the current primary manager can cancel the proposal\n /// @param strategy Address of the strategy\n function cancelChangePrimaryManager(address strategy) external;\n\n /// @notice Executes a previously proposed change to the primary manager after timelock\n /// @param strategy Address of the strategy\n function executeChangePrimaryManager(address strategy) external;\n\n /// @notice Resets the strategy's performance-fee high-water mark to PPS\n /// @dev Only callable by SuperGovernor\n /// @param strategy Address of the strategy\n function resetHighWaterMark(address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n HOOK VALIDATION FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n /// @notice Sets a new hooks root update timelock duration\n /// @param newTimelock The new timelock duration in seconds\n function setHooksRootUpdateTimelock(uint256 newTimelock) external;\n\n /// @notice Proposes an update to the global hooks Merkle root\n /// @dev Only callable by SUPER_GOVERNOR\n /// @param newRoot New Merkle root for global hooks validation\n function proposeGlobalHooksRoot(bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed global hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeGlobalHooksRootUpdate() external;\n\n /// @notice Proposes an update to a strategy-specific hooks Merkle root\n /// @dev Only callable by the main manager for the strategy\n /// @param strategy Address of the strategy\n /// @param newRoot New Merkle root for strategy-specific hooks\n function proposeStrategyHooksRoot(address strategy, bytes32 newRoot) external;\n\n /// @notice Executes a previously proposed strategy hooks root update after timelock period\n /// @dev Can be called by anyone after the timelock period has elapsed\n /// @param strategy Address of the strategy whose root update to execute\n function executeStrategyHooksRootUpdate(address strategy) external;\n\n /// @notice Set veto status for the global hooks root\n /// @dev Only callable by SuperGovernor\n /// @param vetoed Whether to veto (true) or unveto (false) the global hooks root\n function setGlobalHooksRootVetoStatus(bool vetoed) external;\n\n /// @notice Set veto status for a strategy-specific hooks root\n /// @notice Sets the veto status of a strategy's hooks Merkle root\n /// @param strategy Address of the strategy\n /// @param vetoed Whether to veto (true) or unveto (false)\n function setStrategyHooksRootVetoStatus(address strategy, bool vetoed) external;\n\n /// @notice Updates the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @param deviationThreshold_ New deviation threshold (abs diff/current ratio, scaled by 1e18)\n function updateDeviationThreshold(address strategy, uint256 deviationThreshold_) external;\n\n /// @notice Changes the banned status of global leaves for a specific strategy\n /// @dev Only callable by the primary manager of the strategy\n /// @param leaves Array of leaf hashes to change status for\n /// @param statuses Array of banned statuses (true = banned, false = allowed)\n /// @param strategy Address of the strategy to change banned leaves for\n function changeGlobalLeavesStatus(bytes32[] memory leaves, bool[] memory statuses, address strategy) external;\n\n /*//////////////////////////////////////////////////////////////\n MIN UPDATE INTERVAL MANAGEMENT\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Proposes a change to the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @param newMinUpdateInterval The proposed new minimum update interval (in seconds)\n /// @dev Only the main manager can propose. Must be less than maxStaleness\n function proposeMinUpdateIntervalChange(address strategy, uint256 newMinUpdateInterval) external;\n\n /// @notice Executes a previously proposed minUpdateInterval change after timelock\n /// @param strategy Address of the strategy whose minUpdateInterval to update\n /// @dev Can be called by anyone after the timelock period has elapsed\n function executeMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Cancels a pending minUpdateInterval change proposal\n /// @param strategy Address of the strategy\n /// @dev Only the main manager can cancel\n function cancelMinUpdateIntervalChange(address strategy) external;\n\n /// @notice Gets the proposed minUpdateInterval and effective time\n /// @param strategy Address of the strategy\n /// @return proposedInterval The proposed minimum update interval\n /// @return effectiveTime The timestamp when the proposed interval becomes effective\n function getProposedMinUpdateInterval(address strategy)\n external\n view\n returns (uint256 proposedInterval, uint256 effectiveTime);\n\n /*//////////////////////////////////////////////////////////////\n VIEW FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the current vault creation nonce\n /// @dev This nonce is incremented every time a new vault is created\n /// @return Current vault creation nonce\n function getCurrentNonce() external view returns (uint256);\n\n /// @notice Check if the global hooks root is currently vetoed\n /// @return vetoed True if the global hooks root is vetoed\n function isGlobalHooksRootVetoed() external view returns (bool vetoed);\n\n /// @notice Check if a strategy hooks root is currently vetoed\n /// @param strategy Address of the strategy to check\n /// @return vetoed True if the strategy hooks root is vetoed\n function isStrategyHooksRootVetoed(address strategy) external view returns (bool vetoed);\n\n /// @notice Gets the current hooks root update timelock duration\n /// @return The current timelock duration in seconds\n function getHooksRootUpdateTimelock() external view returns (uint256);\n\n /// @notice Gets the current PPS (price-per-share) for a strategy\n /// @param strategy Address of the strategy\n /// @return pps Current price-per-share value\n function getPPS(address strategy) external view returns (uint256 pps);\n\n /// @notice Gets the last update timestamp for a strategy's PPS\n /// @param strategy Address of the strategy\n /// @return timestamp Last update timestamp\n function getLastUpdateTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the minimum update interval for a strategy\n /// @param strategy Address of the strategy\n /// @return interval Minimum time between updates\n function getMinUpdateInterval(address strategy) external view returns (uint256 interval);\n\n /// @notice Gets the maximum staleness period for a strategy\n /// @param strategy Address of the strategy\n /// @return staleness Maximum time allowed between updates\n function getMaxStaleness(address strategy) external view returns (uint256 staleness);\n\n /// @notice Gets the deviation threshold for a strategy\n /// @param strategy Address of the strategy\n /// @return deviationThreshold The current deviation threshold (abs diff/current ratio, scaled by 1e18)\n function getDeviationThreshold(address strategy) external view returns (uint256 deviationThreshold);\n\n /// @notice Checks if a strategy is currently paused\n /// @param strategy Address of the strategy\n /// @return isPaused True if paused, false otherwise\n function isStrategyPaused(address strategy) external view returns (bool isPaused);\n\n /// @notice Checks if a strategy's PPS is stale\n /// @dev PPS is automatically set to stale when the strategy is paused due to\n /// lack of upkeep payment in `SuperVaultAggregator`\n /// @param strategy Address of the strategy\n /// @return isStale True if stale, false otherwise\n function isPPSStale(address strategy) external view returns (bool isStale);\n\n /// @notice Gets the last unpause timestamp for a strategy\n /// @param strategy Address of the strategy\n /// @return timestamp Last unpause timestamp (0 if never unpaused)\n function getLastUnpauseTimestamp(address strategy) external view returns (uint256 timestamp);\n\n /// @notice Gets the current upkeep balance for a strategy\n /// @param strategy Address of the strategy\n /// @return balance Current upkeep balance in upkeep tokens\n function getUpkeepBalance(address strategy) external view returns (uint256 balance);\n\n /// @notice Gets the main manager for a strategy\n /// @param strategy Address of the strategy\n /// @return manager Address of the main manager\n function getMainManager(address strategy) external view returns (address manager);\n\n /// @notice Gets pending primary manager change details\n /// @param strategy Address of the strategy\n /// @return proposedManager Address of the proposed new manager (address(0) if no pending change)\n /// @return effectiveTime Timestamp when the change can be executed (0 if no pending change)\n function getPendingManagerChange(address strategy)\n external\n view\n returns (address proposedManager, uint256 effectiveTime);\n\n /// @notice Checks if an address is the main manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isMainManager True if the address is the main manager, false otherwise\n function isMainManager(address manager, address strategy) external view returns (bool isMainManager);\n\n /// @notice Gets all secondary managers for a strategy\n /// @param strategy Address of the strategy\n /// @return secondaryManagers Array of secondary manager addresses\n function getSecondaryManagers(address strategy) external view returns (address[] memory secondaryManagers);\n\n /// @notice Checks if an address is a secondary manager for a strategy\n /// @param manager Address of the manager\n /// @param strategy Address of the strategy\n /// @return isSecondaryManager True if the address is a secondary manager, false otherwise\n function isSecondaryManager(address manager, address strategy) external view returns (bool isSecondaryManager);\n\n /// @dev Internal helper function to check if an address is any kind of manager (primary or secondary)\n /// @param manager Address to check\n /// @param strategy The strategy to check against\n /// @return True if the address is either the primary manager or a secondary manager\n function isAnyManager(address manager, address strategy) external view returns (bool);\n\n /// @notice Gets all created SuperVaults\n /// @return Array of SuperVault addresses\n function getAllSuperVaults() external view returns (address[] memory);\n\n /// @notice Gets a SuperVault by index\n /// @param index The index of the SuperVault\n /// @return The SuperVault address at the given index\n function superVaults(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultStrategies\n /// @return Array of SuperVaultStrategy addresses\n function getAllSuperVaultStrategies() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultStrategy by index\n /// @param index The index of the SuperVaultStrategy\n /// @return The SuperVaultStrategy address at the given index\n function superVaultStrategies(uint256 index) external view returns (address);\n\n /// @notice Gets all created SuperVaultEscrows\n /// @return Array of SuperVaultEscrow addresses\n function getAllSuperVaultEscrows() external view returns (address[] memory);\n\n /// @notice Gets a SuperVaultEscrow by index\n /// @param index The index of the SuperVaultEscrow\n /// @return The SuperVaultEscrow address at the given index\n function superVaultEscrows(uint256 index) external view returns (address);\n\n /// @notice Validates a hook against both global and strategy-specific Merkle roots\n /// @param strategy Address of the strategy\n /// @param args Arguments for hook validation\n /// @return isValid True if the hook is valid against either root\n function validateHook(address strategy, ValidateHookArgs calldata args) external view returns (bool isValid);\n\n /// @notice Batch validates multiple hooks against Merkle roots\n /// @param strategy Address of the strategy\n /// @param argsArray Array of hook validation arguments\n /// @return validHooks Array of booleans indicating which hooks are valid\n function validateHooks(\n address strategy,\n ValidateHookArgs[] calldata argsArray\n )\n external\n view\n returns (bool[] memory validHooks);\n\n /// @notice Gets the current global hooks Merkle root\n /// @return root The current global hooks Merkle root\n function getGlobalHooksRoot() external view returns (bytes32 root);\n\n /// @notice Gets the proposed global hooks root and effective time\n /// @return root The proposed global hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedGlobalHooksRoot() external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Checks if the global hooks root is active (timelock period has passed)\n /// @return isActive True if the global hooks root is active\n function isGlobalHooksRootActive() external view returns (bool);\n\n /// @notice Gets the hooks Merkle root for a specific strategy\n /// @param strategy Address of the strategy\n /// @return root The strategy-specific hooks Merkle root\n function getStrategyHooksRoot(address strategy) external view returns (bytes32 root);\n\n /// @notice Gets the proposed strategy hooks root and effective time\n /// @param strategy Address of the strategy\n /// @return root The proposed strategy hooks Merkle root\n /// @return effectiveTime The timestamp when the proposed root becomes effective\n function getProposedStrategyHooksRoot(address strategy) external view returns (bytes32 root, uint256 effectiveTime);\n\n /// @notice Gets the total number of SuperVaults\n /// @return count The total number of SuperVaults\n function getSuperVaultsCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultStrategies\n /// @return count The total number of SuperVaultStrategies\n function getSuperVaultStrategiesCount() external view returns (uint256);\n\n /// @notice Gets the total number of SuperVaultEscrows\n /// @return count The total number of SuperVaultEscrows\n function getSuperVaultEscrowsCount() external view returns (uint256);\n}\n"},"src/libraries/SuperVaultAccountingLib.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n/// @title SuperVaultAccountingLib\n/// @author Superform Labs\n/// @notice Stateless library for SuperVault accounting calculations\n/// @dev All functions are pure for easy auditing and testing\nlibrary SuperVaultAccountingLib {\n using Math for uint256;\n\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n error INSUFFICIENT_LIQUIDITY();\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n uint256 private constant BPS_PRECISION = 10_000;\n\n /*//////////////////////////////////////////////////////////////\n ACCOUNTING FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Compute minimum acceptable assets (slippage floor)\n /// @param requestedShares Number of shares being redeemed\n /// @param averageRequestPPS PPS at time of request (slippage anchor)\n /// @param slippageBps User's slippage tolerance in basis points\n /// @param precision Precision constant for PPS calculations\n /// @return minAssetsOut User's minimum acceptable assets\n function computeMinNetOut(\n uint256 requestedShares,\n uint256 averageRequestPPS,\n uint16 slippageBps,\n uint256 precision\n )\n internal\n pure\n returns (uint256 minAssetsOut)\n {\n uint256 expectedAssets = requestedShares.mulDiv(averageRequestPPS, precision, Math.Rounding.Floor);\n minAssetsOut = expectedAssets.mulDiv(BPS_PRECISION - slippageBps, BPS_PRECISION, Math.Rounding.Floor);\n }\n\n /// @notice Calculate updated average withdraw price\n /// @param currentMaxWithdraw Current max withdrawable assets\n /// @param currentAverageWithdrawPrice Current average withdraw price\n /// @param requestedShares New shares being fulfilled\n /// @param fulfilledAssets Assets received from fulfilling the redeem request\n /// @param precision Precision constant\n /// @return newAverageWithdrawPrice Updated average withdraw price\n function calculateAverageWithdrawPrice(\n uint256 currentMaxWithdraw,\n uint256 currentAverageWithdrawPrice,\n uint256 requestedShares,\n uint256 fulfilledAssets,\n uint256 precision\n )\n internal\n pure\n returns (uint256 newAverageWithdrawPrice)\n {\n uint256 existingShares;\n uint256 existingAssets;\n\n if (currentMaxWithdraw > 0 && currentAverageWithdrawPrice > 0) {\n existingShares = currentMaxWithdraw.mulDiv(precision, currentAverageWithdrawPrice, Math.Rounding.Floor);\n existingAssets = currentMaxWithdraw;\n }\n\n uint256 newTotalShares = existingShares + requestedShares;\n uint256 newTotalAssets = existingAssets + fulfilledAssets;\n\n if (newTotalShares > 0) {\n newAverageWithdrawPrice = newTotalAssets.mulDiv(precision, newTotalShares, Math.Rounding.Floor);\n }\n\n return newAverageWithdrawPrice;\n }\n}\n"},"src/libraries/AssetMetadataLib.sol":{"content":"// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.30;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/interfaces/IERC20Metadata.sol\";\n\n/// @title AssetMetadataLib\n/// @author Superform Labs\n/// @notice Library for handling ERC20 metadata operations\nlibrary AssetMetadataLib {\n error INVALID_ASSET();\n\n /**\n * @notice Attempts to fetch an asset's decimals\n * @dev A return value of false indicates that the attempt failed in some way\n * @param asset_ The address of the token to query\n * @return ok Boolean indicating if the operation was successful\n * @return assetDecimals The token's decimals if successful, 0 otherwise\n */\n function tryGetAssetDecimals(address asset_) internal view returns (bool ok, uint8 assetDecimals) {\n if (asset_.code.length == 0) revert INVALID_ASSET();\n\n (bool success, bytes memory encodedDecimals) =\n address(asset_).staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));\n if (success && encodedDecimals.length >= 32) {\n uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n if (returnedDecimals <= type(uint8).max) {\n // casting to 'uint8' is safe because the returned decimals is a valid uint8\n // forge-lint: disable-next-line(unsafe-typecast)\n return (true, uint8(returnedDecimals));\n }\n }\n return (false, 0);\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Panic.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Arrays.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)\n// This file was procedurally generated from scripts/generate/templates/Arrays.js.\n\npragma solidity ^0.8.20;\n\nimport {Comparators} from \"./Comparators.sol\";\nimport {SlotDerivation} from \"./SlotDerivation.sol\";\nimport {StorageSlot} from \"./StorageSlot.sol\";\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Collection of functions related to array types.\n */\nlibrary Arrays {\n using SlotDerivation for bytes32;\n using StorageSlot for bytes32;\n\n /**\n * @dev Sort an array of uint256 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n uint256[] memory array,\n function(uint256, uint256) pure returns (bool) comp\n ) internal pure returns (uint256[] memory) {\n _quickSort(_begin(array), _end(array), comp);\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of uint256 in increasing order.\n */\n function sort(uint256[] memory array) internal pure returns (uint256[] memory) {\n sort(array, Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of address (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n address[] memory array,\n function(address, address) pure returns (bool) comp\n ) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of address in increasing order.\n */\n function sort(address[] memory array) internal pure returns (address[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Sort an array of bytes32 (in memory) following the provided comparator function.\n *\n * This function does the sorting \"in place\", meaning that it overrides the input. The object is returned for\n * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.\n *\n * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the\n * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful\n * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may\n * consume more gas than is available in a block, leading to potential DoS.\n *\n * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.\n */\n function sort(\n bytes32[] memory array,\n function(bytes32, bytes32) pure returns (bool) comp\n ) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), _castToUint256Comp(comp));\n return array;\n }\n\n /**\n * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.\n */\n function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {\n sort(_castToUint256Array(array), Comparators.lt);\n return array;\n }\n\n /**\n * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops\n * at end (exclusive). Sorting follows the `comp` comparator.\n *\n * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.\n *\n * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should\n * be used only if the limits are within a memory array.\n */\n function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {\n unchecked {\n if (end - begin < 0x40) return;\n\n // Use first element as pivot\n uint256 pivot = _mload(begin);\n // Position where the pivot should be at the end of the loop\n uint256 pos = begin;\n\n for (uint256 it = begin + 0x20; it < end; it += 0x20) {\n if (comp(_mload(it), pivot)) {\n // If the value stored at the iterator's position comes before the pivot, we increment the\n // position of the pivot and move the value there.\n pos += 0x20;\n _swap(pos, it);\n }\n }\n\n _swap(begin, pos); // Swap pivot into place\n _quickSort(begin, pos, comp); // Sort the left side of the pivot\n _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first element of `array`.\n */\n function _begin(uint256[] memory array) private pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := add(array, 0x20)\n }\n }\n\n /**\n * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word\n * that comes just after the last element of the array.\n */\n function _end(uint256[] memory array) private pure returns (uint256 ptr) {\n unchecked {\n return _begin(array) + array.length * 0x20;\n }\n }\n\n /**\n * @dev Load memory word (as a uint256) at location `ptr`.\n */\n function _mload(uint256 ptr) private pure returns (uint256 value) {\n assembly {\n value := mload(ptr)\n }\n }\n\n /**\n * @dev Swaps the elements memory location `ptr1` and `ptr2`.\n */\n function _swap(uint256 ptr1, uint256 ptr2) private pure {\n assembly {\n let value1 := mload(ptr1)\n let value2 := mload(ptr2)\n mstore(ptr1, value2)\n mstore(ptr2, value1)\n }\n }\n\n /// @dev Helper: low level cast address memory array to uint256 memory array\n function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 memory array to uint256 memory array\n function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast address comp function to uint256 comp function\n function _castToUint256Comp(\n function(address, address) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /// @dev Helper: low level cast bytes32 comp function to uint256 comp function\n function _castToUint256Comp(\n function(bytes32, bytes32) pure returns (bool) input\n ) private pure returns (function(uint256, uint256) pure returns (bool) output) {\n assembly {\n output := input\n }\n }\n\n /**\n * @dev Searches a sorted `array` and returns the first index that contains\n * a value greater or equal to `element`. If no such index exists (i.e. all\n * values in the array are strictly less than `element`), the array length is\n * returned. Time complexity O(log n).\n *\n * NOTE: The `array` is expected to be sorted in ascending order, and to\n * contain no repeated elements.\n *\n * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks\n * support for repeated elements in the array. The {lowerBound} function should\n * be used instead.\n */\n function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.\n if (low > 0 && unsafeAccess(array, low - 1).value == element) {\n return low - 1;\n } else {\n return low;\n }\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value greater or equal than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].\n */\n function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Searches an `array` sorted in ascending order and returns the first\n * index that contains a value strictly greater than `element`. If no such index\n * exists (i.e. all values in the array are strictly less than `element`), the array\n * length is returned. Time complexity O(log n).\n *\n * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].\n */\n function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeAccess(array, mid).value > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {lowerBound}, but with an array in memory.\n */\n function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) < element) {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n } else {\n high = mid;\n }\n }\n\n return low;\n }\n\n /**\n * @dev Same as {upperBound}, but with an array in memory.\n */\n function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {\n uint256 low = 0;\n uint256 high = array.length;\n\n if (high == 0) {\n return 0;\n }\n\n while (low < high) {\n uint256 mid = Math.average(low, high);\n\n // Note that mid will always be strictly less than high (i.e. it will be a valid array index)\n // because Math.average rounds towards zero (it does integer division with truncation).\n if (unsafeMemoryAccess(array, mid) > element) {\n high = mid;\n } else {\n // this cannot overflow because mid < high\n unchecked {\n low = mid + 1;\n }\n }\n }\n\n return low;\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getAddressSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytes32Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getUint256Slot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getBytesSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {\n bytes32 slot;\n assembly (\"memory-safe\") {\n slot := arr.slot\n }\n return slot.deriveArray().offset(pos).getStringSlot();\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Access an array in an \"unsafe\" way. Skips solidity \"index-out-of-range\" check.\n *\n * WARNING: Only use if you are certain `pos` is lower than the array length.\n */\n function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {\n assembly {\n res := mload(add(add(arr, 0x20), mul(pos, 0x20)))\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(address[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes32[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(uint256[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(bytes[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n\n /**\n * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.\n *\n * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.\n */\n function unsafeSetLength(string[] storage array, uint256 len) internal {\n assembly (\"memory-safe\") {\n sstore(array.slot, len)\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/erc7579/lib/ExecutionLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n// Types\nimport { Execution } from \"../../common/interfaces/IERC7579Account.sol\";\n\n/**\n * Helper Library for decoding Execution calldata\n * malloc for memory allocation is bad for gas. use this assembly instead\n */\nlibrary ExecutionLib {\n error ERC7579DecodingError();\n\n /**\n * @notice Decode a batch of `Execution` executionBatch from a `bytes` calldata.\n * @dev code is copied from solady's LibERC7579.sol\n * https://github.com/Vectorized/solady/blob/740812cedc9a1fc11e17cb3d4569744367dedf19/src/accounts/LibERC7579.sol#L146\n * Credits to Vectorized and the Solady Team\n */\n function decodeBatch(bytes calldata executionCalldata)\n internal\n pure\n returns (Execution[] calldata executionBatch)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let u := calldataload(executionCalldata.offset)\n let s := add(executionCalldata.offset, u)\n let e := sub(add(executionCalldata.offset, executionCalldata.length), 0x20)\n executionBatch.offset := add(s, 0x20)\n executionBatch.length := calldataload(s)\n if or(shr(64, u), gt(add(s, shl(5, executionBatch.length)), e)) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if executionBatch.length {\n // Perform bounds checks on the decoded `executionBatch`.\n // Loop runs out-of-gas if `executionBatch.length` is big enough to cause overflows.\n for { let i := executionBatch.length } 1 { } {\n i := sub(i, 1)\n let p := calldataload(add(executionBatch.offset, shl(5, i)))\n let c := add(executionBatch.offset, p)\n let q := calldataload(add(c, 0x40))\n let o := add(c, q)\n // forgefmt: disable-next-item\n if or(shr(64, or(calldataload(o), or(p, q))),\n or(gt(add(c, 0x40), e), gt(add(o, calldataload(o)), e))) {\n mstore(0x00, 0xba597e7e) // `DecodingError()`.\n revert(0x1c, 0x04)\n }\n if iszero(i) { break }\n }\n }\n }\n }\n\n function encodeBatch(Execution[] memory executions)\n internal\n pure\n returns (bytes memory callData)\n {\n callData = abi.encode(executions);\n }\n\n function decodeSingle(bytes calldata executionCalldata)\n internal\n pure\n returns (address target, uint256 value, bytes calldata callData)\n {\n target = address(bytes20(executionCalldata[0:20]));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n function encodeSingle(\n address target,\n uint256 value,\n bytes memory callData\n )\n internal\n pure\n returns (bytes memory userOpCalldata)\n {\n userOpCalldata = abi.encodePacked(target, value, callData);\n }\n}\n"},"src/vendor/standards/ERC7540/IERC7540Vault.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport { IERC7741 } from \"../ERC7741/IERC7741.sol\";\n\ninterface IERC7540Operator {\n /**\n * @dev The event emitted when an operator is set.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @param approved The approval status.\n */\n event OperatorSet(address indexed controller, address indexed operator, bool approved);\n\n /**\n * @dev Sets or removes an operator for the caller.\n *\n * @param operator The address of the operator.\n * @param approved The approval status.\n * @return Whether the call was executed successfully or not\n */\n function setOperator(address operator, bool approved) external returns (bool);\n\n /**\n * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.\n *\n * @param controller The address of the controller.\n * @param operator The address of the operator.\n * @return status The approval status\n */\n function isOperator(address controller, address operator) external view returns (bool status);\n}\n\ninterface IERC7540Deposit is IERC7540Operator {\n event DepositRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n /**\n * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.\n *\n * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.\n * - MUST revert if all of assets cannot be requested for deposit.\n * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from owner to sender is NOT enough.\n *\n * @param assets the amount of deposit assets to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the deposit assets\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.\n */\n\n function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested assets in Pending state.\n *\n * - MUST NOT include any assets in Claimable state for deposit or mint.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingDepositRequest(uint256 requestId, address controller) external view returns (uint256 pendingAssets);\n\n /**\n * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.\n *\n * - MUST NOT include any assets in Pending state.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.\n *\n * - MUST emit the Deposit event.\n * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.\n */\n function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);\n}\n\ninterface IERC7540Redeem is IERC7540Operator {\n event RedeemRequest(\n address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.\n *\n * - MUST support a redeem Request flow where the control of shares is taken from sender directly\n * where msg.sender has ERC-20 approval over the shares of owner.\n * - MUST revert if all of shares cannot be requested for redeem.\n *\n * @param shares the amount of shares to be redeemed to transfer from owner\n * @param controller the controller of the request who will be able to operate the request\n * @param owner the source of the shares to be redeemed\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.\n */\n function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);\n\n /**\n * @dev Returns the amount of requested shares in Pending state.\n *\n * - MUST NOT include any shares in Claimable state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function pendingRedeemRequest(uint256 requestId, address controller) external view returns (uint256 pendingShares);\n\n /**\n * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.\n *\n * - MUST NOT include any shares in Pending state for redeem or withdraw.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.\n */\n function claimableRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n}\n\ninterface IERC7540CancelDeposit {\n event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelDepositClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 assets\n );\n\n /**\n * @dev Submits a Request for cancelling the pending deposit Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelDepositRequest`\n * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called\n */\n function cancelDepositRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the deposit Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelDepositRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelDepositRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableAssets);\n\n /**\n * @dev Claims the canceled deposit assets, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelDepositRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 assets);\n}\n\n//IERC7887Redeem\ninterface IERC7540CancelRedeem {\n event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);\n event CancelRedeemClaim(\n address indexed receiver, address indexed controller, uint256 indexed requestId, address sender, uint256 shares\n );\n\n /**\n * @dev Submits a Request for cancelling the pending redeem Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request\n * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment\n * - SHOULD be claimable using `claimCancelRedeemRequest`\n * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called\n */\n function cancelRedeemRequest(uint256 requestId, address controller) external;\n\n /**\n * @dev Returns whether the redeem Request is pending cancelation\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);\n\n /**\n * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.\n *\n * - MUST NOT show any variations depending on the caller.\n */\n function claimableCancelRedeemRequest(\n uint256 requestId,\n address controller\n )\n external\n view\n returns (uint256 claimableShares);\n\n /**\n * @dev Claims the canceled redeem shares, and removes the pending cancelation Request\n *\n * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,\n * approval of ERC-20 tokens from controller to sender is NOT enough.\n * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request\n * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment\n */\n function claimCancelRedeemRequest(\n uint256 requestId,\n address receiver,\n address controller\n )\n external\n returns (uint256 shares);\n}\n\n/**\n * @title IERC7540\n * @dev Fully async ERC7540 implementation according to the standard\n * @dev Adapted from Centrifuge's IERC7540 implementation\n */\ninterface IERC7540 is IERC7540Deposit, IERC7540Redeem { }\n\n/**\n * @title IERC7540Vault\n * @dev This is the specific set of interfaces used by the SuperVaults\n */\ninterface IERC7540Vault is IERC7540, IERC7741 {\n event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);\n}\n"},"src/vendor/standards/ERC7741/IERC7741.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\ninterface IERC7741 {\n /**\n * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the\n * `msg.sender`, using an [EIP-712](./eip-712.md) signature.\n */\n function authorizeOperator(\n address controller,\n address operator,\n bool approved,\n bytes32 nonce,\n uint256 deadline,\n bytes memory signature\n )\n external\n returns (bool);\n\n /**\n * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.\n */\n function invalidateNonce(bytes32 nonce) external;\n\n /**\n * @dev Returns whether the given `nonce` has been used for the `controller`.\n */\n function authorizations(address controller, bytes32 nonce) external view returns (bool used);\n\n /**\n * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR\n * should be unique to the contract and chain to prevent replay attacks from other domains,\n * and satisfy the requirements of EIP-712, but is otherwise unconstrained.\n */\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},"lib/v2-core/src/vendor/BytesLib.sol":{"content":"// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity 0.8.30;\n\nlibrary BytesLib {\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for { let cc := add(_postBytes, 0x20) } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(\n sc,\n add(\n and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),\n and(mload(mc), mask)\n )\n )\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } { sstore(sc, mload(mc)) }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } { sstore(sc, mload(mc)) }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {\n // We're using the unchecked block below because otherwise execution ends\n // with the native overflow error code.\n unchecked {\n require(_length + 31 >= _length, \"slice_overflow\");\n }\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } { mstore(mc, mload(cc)) }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint256 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for { let cc := add(_postBytes, 0x20) }\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for { } eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Comparators.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to compare values.\n *\n * _Available since v5.1._\n */\nlibrary Comparators {\n function lt(uint256 a, uint256 b) internal pure returns (bool) {\n return a < b;\n }\n\n function gt(uint256 a, uint256 b) internal pure returns (bool) {\n return a > b;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)\n// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots\n * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by\n * the solidity language / compiler.\n *\n * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].\n *\n * Example usage:\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using StorageSlot for bytes32;\n * using SlotDerivation for bytes32;\n *\n * // Declare a namespace\n * string private constant _NAMESPACE = \"\"; // eg. OpenZeppelin.Slot\n *\n * function setValueInNamespace(uint256 key, address newValue) internal {\n * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;\n * }\n *\n * function getValueInNamespace(uint256 key) internal view returns (address) {\n * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {StorageSlot}.\n *\n * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking\n * upgrade safety will ignore the slots accessed through this library.\n *\n * _Available since v5.1._\n */\nlibrary SlotDerivation {\n /**\n * @dev Derive an ERC-7201 slot from a string (namespace).\n */\n function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {\n assembly (\"memory-safe\") {\n mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))\n slot := and(keccak256(0x00, 0x20), not(0xff))\n }\n }\n\n /**\n * @dev Add an offset to a slot to get the n-th element of a structure or an array.\n */\n function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {\n unchecked {\n return bytes32(uint256(slot) + pos);\n }\n }\n\n /**\n * @dev Derive the location of the first element in an array from the slot where the length is stored.\n */\n function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, slot)\n result := keccak256(0x00, 0x20)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, and(key, shr(96, not(0))))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, iszero(iszero(key)))\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n mstore(0x00, key)\n mstore(0x20, slot)\n result := keccak256(0x00, 0x40)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n\n /**\n * @dev Derive the location of a mapping element from the key.\n */\n function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n let length := mload(key)\n let begin := add(key, 0x20)\n let end := add(begin, length)\n let cache := mload(end)\n mstore(end, slot)\n result := keccak256(begin, add(length, 0x20))\n mstore(end, cache)\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/interfaces/IERC7579Account.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.23 <0.9.0;\n\n/* solhint-disable no-unused-import */\n\n// Types\nimport { CallType, ExecType, ModeCode } from \"../lib/ModeLib.sol\";\n\n// Structs\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\ninterface IERC7579Account {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by ERC-4337 EntryPoint.sol\n * @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @dev Ensure adequate authorization control: i.e. onlyExecutorModule\n *\n * @dev MSA MUST implement this function signature.\n * If a mode is requested that is not supported by the Account, it MUST revert\n * @param mode The encoded execution mode of the transaction. See ModeLib.sol for details\n * @param executionCalldata The encoded execution call data\n */\n function executeFromExecutor(\n ModeCode mode,\n bytes calldata executionCalldata\n )\n external\n payable\n returns (bytes[] memory returnData);\n\n /**\n * @dev ERC-1271 isValidSignature\n * This function is intended to be used to validate a smart account signature\n * and may forward the call to a validator module\n *\n * @param hash The hash of the data that is signed\n * @param data The data that is signed\n */\n function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);\n\n /**\n * @dev installs a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be required on the module during `onInstall`\n * initialization.\n */\n function installModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata initData\n )\n external\n payable;\n\n /**\n * @dev uninstalls a Module of a certain type on the smart account\n * @dev Implement Authorization control of your chosing\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be required on the module during `onUninstall`\n * de-initialization.\n */\n function uninstallModule(\n uint256 moduleTypeId,\n address module,\n bytes calldata deInitData\n )\n external\n payable;\n\n /**\n * Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)\n * @param encodedMode the encoded mode\n */\n function supportsExecutionMode(ModeCode encodedMode) external view returns (bool);\n\n /**\n * Function to check if the account supports installation of a certain module type Id\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n\n /**\n * Function to check if the account has a certain module installed\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * Note: keep in mind that some contracts can be multiple module types at the same time. It\n * thus may be necessary to query multiple module types\n * @param module the module address\n * @param additionalContext additional context data that the smart account may interpret to\n * identifiy conditions under which the module is installed.\n * usually this is not necessary, but for some special hooks that\n * are stored in mappings, this param might be needed\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n )\n external\n view\n returns (bool);\n\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n * the accountId should be structured like so:\n * \"vendorname.accountname.semver\"\n */\n function accountId() external view returns (string memory accountImplementationId);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/v2-core/lib/modulekit/src/accounts/common/lib/ModeLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.0 <0.9.0;\n\n/**\n * @title ModeLib\n * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat)\n * To allow smart accounts to be very simple, but allow for more complex execution, A custom mode\n * encoding is used.\n * Function Signature of execute function:\n * function execute(ModeCode mode, bytes calldata executionCalldata) external payable;\n * This allows for a single bytes32 to be used to encode the execution mode, calltype, execType and\n * context.\n * NOTE: Simple Account implementations only have to scope for the most significant byte. Account that\n * implement\n * more complex execution modes may use the entire bytes32.\n *\n * |--------------------------------------------------------------------|\n * | CALLTYPE | EXECTYPE | UNUSED | ModeSelector | ModePayload |\n * |--------------------------------------------------------------------|\n * | 1 byte | 1 byte | 4 bytes | 4 bytes | 22 bytes |\n * |--------------------------------------------------------------------|\n *\n * CALLTYPE: 1 byte\n * CallType is used to determine how the executeCalldata paramter of the execute function has to be\n * decoded.\n * It can be either single, batch or delegatecall. In the future different calls could be added.\n * CALLTYPE can be used by a validation module to determine how to decode .\n *\n * EXECTYPE: 1 byte\n * ExecType is used to determine how the account should handle the execution.\n * It can indicate if the execution should revert on failure or continue execution.\n * In the future more execution modes may be added.\n * Default Behavior (EXECTYPE = 0x00) is to revert on a single failed execution. If one execution in\n * a batch fails, the entire batch is reverted\n *\n * UNUSED: 4 bytes\n * Unused bytes are reserved for future use.\n *\n * ModeSelector: bytes4\n * The \"optional\" mode selector can be used by account vendors, to implement custom behavior in\n * their accounts.\n * the way a ModeSelector is to be calculated is bytes4(keccak256(\"vendorname.featurename\"))\n * this is to prevent collisions between different vendors, while allowing innovation and the\n * development of new features without coordination between ERC-7579 implementing accounts\n *\n * ModePayload: 22 bytes\n * Mode payload is used to pass additional data to the smart account execution, this may be\n * interpreted depending on the ModeSelector\n *\n * ExecutionCallData: n bytes\n * single, delegatecall or batch exec abi.encoded as bytes\n */\n\n// Custom type for improved developer experience\ntype ModeCode is bytes32;\n\ntype CallType is bytes1;\n\ntype ExecType is bytes1;\n\ntype ModeSelector is bytes4;\n\ntype ModePayload is bytes22;\n\n// Default CallType\nCallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n// Batched CallType\nCallType constant CALLTYPE_BATCH = CallType.wrap(0x01);\nCallType constant CALLTYPE_STATIC = CallType.wrap(0xFE);\n// @dev Implementing delegatecall is OPTIONAL!\n// implement delegatecall with extreme care.\nCallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n// @dev default behavior is to revert on failure\n// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure\n// Since this is value 0x00, no additional encoding is required for simple accounts\nExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n// @dev account may elect to change execution behavior. For example \"try exec\" / \"allow fail\"\nExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\nModeSelector constant MODE_DEFAULT = ModeSelector.wrap(bytes4(0x00000000));\n// Example declaration of a custom mode selector\nModeSelector constant MODE_OFFSET = ModeSelector.wrap(bytes4(keccak256(\"default.mode.offset\")));\n\n/**\n * @dev ModeLib is a helper library to encode/decode ModeCodes\n */\nlibrary ModeLib {\n function decode(ModeCode mode)\n internal\n pure\n returns (\n CallType _calltype,\n ExecType _execType,\n ModeSelector _modeSelector,\n ModePayload _modePayload\n )\n {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n _calltype := mode\n _execType := shl(8, mode)\n _modeSelector := shl(48, mode)\n _modePayload := shl(80, mode)\n }\n }\n\n function encode(\n CallType callType,\n ExecType execType,\n ModeSelector mode,\n ModePayload payload\n )\n internal\n pure\n returns (ModeCode)\n {\n return ModeCode.wrap(\n bytes32(\n abi.encodePacked(callType, execType, bytes4(0), ModeSelector.unwrap(mode), payload)\n )\n );\n }\n\n function encodeSimpleBatch() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function encodeSimpleSingle() internal pure returns (ModeCode mode) {\n mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, MODE_DEFAULT, ModePayload.wrap(0x00));\n }\n\n function getCallType(ModeCode mode) internal pure returns (CallType calltype) {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n calltype := mode\n }\n }\n}\n\nusing { eqModeSelector as == } for ModeSelector global;\nusing { eqCallType as == } for CallType global;\nusing { neqCallType as != } for CallType global;\nusing { eqExecType as == } for ExecType global;\n\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction neqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/SuperformGasOracle.standard-json-input.json b/script/locked-bytecode-dev/SuperformGasOracle.standard-json-input.json new file mode 100644 index 000000000..bb693033e --- /dev/null +++ b/script/locked-bytecode-dev/SuperformGasOracle.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/oracles/SuperformGasOracle.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.30;\n\nimport { AccessControl } from \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport { AggregatorV3Interface } from \"../vendor/chainlink/AggregatorV3Interface.sol\";\n\n/// @title SuperformGasOracle\n/// @notice A Chainlink-compatible oracle that returns gas price in Gwei, updated by a keeper\n/// @dev Used as a gas price oracle on L2s where Chainlink's Fast Gas feed is not available.\n/// Tracks round ID and update timestamp for proper staleness checks.\n/// Returns gas price directly in Gwei with 0 decimals.\n/// Example: 1 = 1 Gwei, 1000000 = 1,000,000 Gwei.\ncontract SuperformGasOracle is AggregatorV3Interface, AccessControl {\n /*//////////////////////////////////////////////////////////////\n ERRORS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Thrown when trying to set a zero gas price\n error INVALID_GAS_PRICE();\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Emitted when the gas price is updated\n /// @param oldGasPrice The previous gas price\n /// @param newGasPrice The new gas price\n event GasPriceUpdated(int256 oldGasPrice, int256 newGasPrice);\n\n /// @notice Emitted when useBlockTimestamp flag is changed\n /// @param enabled Whether block.timestamp is now used for timestamps\n event UseBlockTimestampChanged(bool enabled);\n\n /*//////////////////////////////////////////////////////////////\n ROLES\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Role that can update the gas price\n bytes32 public constant KEEPER_ROLE = keccak256(\"KEEPER_ROLE\");\n\n /*//////////////////////////////////////////////////////////////\n STATE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice The gas price in Gwei (0 decimals)\n int256 private _answer;\n\n /// @notice Timestamp when the price was last updated\n uint256 private _updatedAt;\n\n /// @notice Current round ID (increments with each update)\n uint80 private _roundId;\n\n /// @notice If true, return block.timestamp for startedAt/updatedAt instead of stored timestamp\n bool private _useBlockTimestamp = true;\n\n /// @notice The number of decimals (0 - value is directly in Gwei)\n /// @dev Gwei already has 9 decimals inherently (1 Gwei = 10^9 wei)\n uint8 private constant DECIMALS = 0;\n\n /// @notice Description of the oracle\n string private constant DESCRIPTION = \"Superform Fast Gas / Gwei\";\n\n /// @notice Version of the oracle\n uint256 private constant VERSION = 1;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Initializes the oracle with an initial gas price\n /// @param initialGasPrice The initial gas price in Gwei (must be > 0)\n /// @dev Example: 1 = 1 Gwei, 50 = 50 Gwei\n /// @param admin_ The admin who can grant/revoke roles (receives DEFAULT_ADMIN_ROLE)\n constructor(int256 initialGasPrice, address admin_) {\n if (initialGasPrice <= 0) revert INVALID_GAS_PRICE();\n _answer = initialGasPrice;\n _updatedAt = block.timestamp;\n _roundId = 1;\n\n // Grant admin role (can grant/revoke KEEPER_ROLE)\n _grantRole(DEFAULT_ADMIN_ROLE, admin_);\n // Grant keeper role to admin initially\n _grantRole(KEEPER_ROLE, admin_);\n }\n\n /*//////////////////////////////////////////////////////////////\n ADMIN FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Sets the gas price (called by keeper or admin)\n /// @param newGasPrice The new gas price in Gwei (must be > 0)\n /// @dev Example: 1 = 1 Gwei, 50 = 50 Gwei\n function setGasPrice(int256 newGasPrice) external onlyRole(KEEPER_ROLE) {\n if (newGasPrice <= 0) revert INVALID_GAS_PRICE();\n int256 oldGasPrice = _answer;\n _answer = newGasPrice;\n _updatedAt = block.timestamp;\n unchecked {\n ++_roundId;\n }\n emit GasPriceUpdated(oldGasPrice, newGasPrice);\n }\n\n /// @notice Sets whether to use block.timestamp for startedAt/updatedAt\n /// @param enabled If true, getRoundData and latestRoundData return block.timestamp\n /// @dev When enabled, staleness checks will always pass (timestamp is always fresh)\n function setUseBlockTimestamp(bool enabled) external onlyRole(KEEPER_ROLE) {\n _useBlockTimestamp = enabled;\n emit UseBlockTimestampChanged(enabled);\n }\n\n /// @notice Returns whether block.timestamp is used for startedAt/updatedAt\n function useBlockTimestamp() external view returns (bool) {\n return _useBlockTimestamp;\n }\n\n /*//////////////////////////////////////////////////////////////\n AGGREGATOR V3 INTERFACE\n //////////////////////////////////////////////////////////////*/\n\n /// @inheritdoc AggregatorV3Interface\n function decimals() external pure override returns (uint8) {\n return DECIMALS;\n }\n\n /// @inheritdoc AggregatorV3Interface\n function description() external pure override returns (string memory) {\n return DESCRIPTION;\n }\n\n /// @inheritdoc AggregatorV3Interface\n function version() external pure override returns (uint256) {\n return VERSION;\n }\n\n /// @inheritdoc AggregatorV3Interface\n /// @dev This oracle only stores the latest round, so any roundId returns current data\n function getRoundData(uint80)\n external\n view\n override\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)\n {\n uint256 timestamp = _useBlockTimestamp ? block.timestamp : _updatedAt;\n return (_roundId, _answer, timestamp, timestamp, _roundId);\n }\n\n /// @inheritdoc AggregatorV3Interface\n function latestRoundData()\n external\n view\n override\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)\n {\n uint256 timestamp = _useBlockTimestamp ? block.timestamp : _updatedAt;\n return (_roundId, _answer, timestamp, timestamp, _roundId);\n }\n\n /*//////////////////////////////////////////////////////////////\n LEGACY INTERFACE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns the latest gas price (legacy interface)\n /// @return The gas price in Gwei\n function latestAnswer() external view returns (int256) {\n return _answer;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/AccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {IERC165, ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account => bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n"},"src/vendor/chainlink/AggregatorV3Interface.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function latestRoundData()\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/UpOFT.standard-json-input.json b/script/locked-bytecode-dev/UpOFT.standard-json-input.json new file mode 100644 index 000000000..4e7ac3296 --- /dev/null +++ b/script/locked-bytecode-dev/UpOFT.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/UP/UpOFT.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { OFT } from \"@layerzerolabs/oft-evm/contracts/OFT.sol\";\n\n/**\n * @title UpOFT\n * @author Superform Foundation\n * @notice Native OFT representation of the UP token on non-Ethereum chains.\n * @dev Mints UP tokens when bridging in, burns when bridging out.\n * Deploy this on chains (e.g., Base) where UP is not natively deployed.\n */\ncontract UpOFT is OFT {\n error NATIVE_TRANSFER_FAILED();\n error ADDRESS_NOT_VALID();\n\n /**\n * @notice Initializes the OFT with the LayerZero endpoint.\n * @param _lzEndpoint The LayerZero v2 endpoint address for this chain\n * @param _delegate The delegate capable of making OApp configurations (typically the owner)\n */\n constructor(\n address _lzEndpoint,\n address _delegate\n ) OFT(\"Superform\", \"UP\", _lzEndpoint, _delegate) Ownable(_delegate) {\n\n if (_lzEndpoint == address(0) || _lzEndpoint.code.length == 0) {\n revert ADDRESS_NOT_VALID();\n }\n }\n\n function sweepNative(address payable to) external onlyOwner {\n (bool s, ) = to.call{value: address(this).balance}(\"\");\n if(!s) revert NATIVE_TRANSFER_FAILED();\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"lib/devtools/packages/oft-evm/contracts/OFT.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IOFT, OFTCore } from \"./OFTCore.sol\";\n\n/**\n * @title OFT Contract\n * @dev OFT is an ERC-20 token that extends the functionality of the OFTCore contract.\n */\nabstract contract OFT is OFTCore, ERC20 {\n /**\n * @dev Constructor for the OFT contract.\n * @param _name The name of the OFT.\n * @param _symbol The symbol of the OFT.\n * @param _lzEndpoint The LayerZero endpoint address.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n address _lzEndpoint,\n address _delegate\n ) ERC20(_name, _symbol) OFTCore(decimals(), _lzEndpoint, _delegate) {}\n\n /**\n * @dev Retrieves the address of the underlying ERC20 implementation.\n * @return The address of the OFT token.\n *\n * @dev In the case of OFT, address(this) and erc20 are the same contract.\n */\n function token() public view returns (address) {\n return address(this);\n }\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev In the case of OFT where the contract IS the token, approval is NOT required.\n */\n function approvalRequired() external pure virtual returns (bool) {\n return false;\n }\n\n /**\n * @dev Burns tokens from the sender's specified balance.\n * @param _from The address to debit the tokens from.\n * @param _amountLD The amount of tokens to send in local decimals.\n * @param _minAmountLD The minimum amount to send in local decimals.\n * @param _dstEid The destination chain ID.\n * @return amountSentLD The amount sent in local decimals.\n * @return amountReceivedLD The amount received in local decimals on the remote.\n */\n function _debit(\n address _from,\n uint256 _amountLD,\n uint256 _minAmountLD,\n uint32 _dstEid\n ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {\n (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);\n\n // @dev In NON-default OFT, amountSentLD could be 100, with a 10% fee, the amountReceivedLD amount is 90,\n // therefore amountSentLD CAN differ from amountReceivedLD.\n\n // @dev Default OFT burns on src.\n _burn(_from, amountSentLD);\n }\n\n /**\n * @dev Credits tokens to the specified address.\n * @param _to The address to credit the tokens to.\n * @param _amountLD The amount of tokens to credit in local decimals.\n * @dev _srcEid The source chain ID.\n * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.\n */\n function _credit(\n address _to,\n uint256 _amountLD,\n uint32 /*_srcEid*/\n ) internal virtual override returns (uint256 amountReceivedLD) {\n if (_to == address(0x0)) _to = address(0xdead); // _mint(...) does not support address(0x0)\n // @dev Default OFT mints on dst.\n _mint(_to, _amountLD);\n // @dev In the case of NON-default OFT, the _amountLD MIGHT not be == amountReceivedLD.\n return _amountLD;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC20Metadata} from \"./extensions/IERC20Metadata.sol\";\nimport {Context} from \"../../utils/Context.sol\";\nimport {IERC20Errors} from \"../../interfaces/draft-IERC6093.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC-20\n * applications.\n */\nabstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {\n mapping(address account => uint256) private _balances;\n\n mapping(address account => mapping(address spender => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * Both values are immutable: they can only be set once during construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual returns (uint8) {\n return 18;\n }\n\n /// @inheritdoc IERC20\n function totalSupply() public view virtual returns (uint256) {\n return _totalSupply;\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address account) public view virtual returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `value`.\n */\n function transfer(address to, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, value);\n return true;\n }\n\n /// @inheritdoc IERC20\n function allowance(address owner, address spender) public view virtual returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Skips emitting an {Approval} event indicating an allowance update. This is not\n * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `value`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `value`.\n */\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, value);\n _transfer(from, to, value);\n return true;\n }\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _transfer(address from, address to, uint256 value) internal {\n if (from == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n if (to == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(from, to, value);\n }\n\n /**\n * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n * this function.\n *\n * Emits a {Transfer} event.\n */\n function _update(address from, address to, uint256 value) internal virtual {\n if (from == address(0)) {\n // Overflow check required: The rest of the code assumes that totalSupply never overflows\n _totalSupply += value;\n } else {\n uint256 fromBalance = _balances[from];\n if (fromBalance < value) {\n revert ERC20InsufficientBalance(from, fromBalance, value);\n }\n unchecked {\n // Overflow not possible: value <= fromBalance <= totalSupply.\n _balances[from] = fromBalance - value;\n }\n }\n\n if (to == address(0)) {\n unchecked {\n // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n _totalSupply -= value;\n }\n } else {\n unchecked {\n // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n _balances[to] += value;\n }\n }\n\n emit Transfer(from, to, value);\n }\n\n /**\n * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n * Relies on the `_update` mechanism\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _mint(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(address(0), account, value);\n }\n\n /**\n * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n * Relies on the `_update` mechanism.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead\n */\n function _burn(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n _update(account, address(0), value);\n }\n\n /**\n * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n *\n * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n */\n function _approve(address owner, address spender, uint256 value) internal {\n _approve(owner, spender, value, true);\n }\n\n /**\n * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n *\n * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n * `Approval` event during `transferFrom` operations.\n *\n * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n * true using the following override:\n *\n * ```solidity\n * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n * super._approve(owner, spender, value, true);\n * }\n * ```\n *\n * Requirements are the same as {_approve}.\n */\n function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n if (owner == address(0)) {\n revert ERC20InvalidApprover(address(0));\n }\n if (spender == address(0)) {\n revert ERC20InvalidSpender(address(0));\n }\n _allowances[owner][spender] = value;\n if (emitEvent) {\n emit Approval(owner, spender, value);\n }\n }\n\n /**\n * @dev Updates `owner`'s allowance for `spender` based on spent `value`.\n *\n * Does not update the allowance value in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Does not emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance < type(uint256).max) {\n if (currentAllowance < value) {\n revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n }\n unchecked {\n _approve(owner, spender, currentAllowance - value, false);\n }\n }\n }\n}\n"},"lib/devtools/packages/oft-evm/contracts/OFTCore.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { OApp, Origin } from \"@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol\";\nimport { OAppOptionsType3 } from \"@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol\";\nimport { IOAppMsgInspector } from \"@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppMsgInspector.sol\";\n\nimport { OAppPreCrimeSimulator } from \"@layerzerolabs/oapp-evm/contracts/precrime/OAppPreCrimeSimulator.sol\";\n\nimport { IOFT, SendParam, OFTLimit, OFTReceipt, OFTFeeDetail, MessagingReceipt, MessagingFee } from \"./interfaces/IOFT.sol\";\nimport { OFTMsgCodec } from \"./libs/OFTMsgCodec.sol\";\nimport { OFTComposeMsgCodec } from \"./libs/OFTComposeMsgCodec.sol\";\n\n/**\n * @title OFTCore\n * @dev Abstract contract for the OftChain (OFT) token.\n */\nabstract contract OFTCore is IOFT, OApp, OAppPreCrimeSimulator, OAppOptionsType3 {\n using OFTMsgCodec for bytes;\n using OFTMsgCodec for bytes32;\n\n // @notice Provides a conversion rate when swapping between denominations of SD and LD\n // - shareDecimals == SD == shared Decimals\n // - localDecimals == LD == local decimals\n // @dev Considers that tokens have different decimal amounts on various chains.\n // @dev eg.\n // For a token\n // - locally with 4 decimals --> 1.2345 => uint(12345)\n // - remotely with 2 decimals --> 1.23 => uint(123)\n // - The conversion rate would be 10 ** (4 - 2) = 100\n // @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote,\n // you can only display 1.23 -> uint(123).\n // @dev To preserve the dust that would otherwise be lost on that conversion,\n // we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh\n uint256 public immutable decimalConversionRate;\n\n // @notice Msg types that are used to identify the various OFT operations.\n // @dev This can be extended in child contracts for non-default oft operations\n // @dev These values are used in things like combineOptions() in OAppOptionsType3.sol.\n uint16 public constant SEND = 1;\n uint16 public constant SEND_AND_CALL = 2;\n\n // Address of an optional contract to inspect both 'message' and 'options'\n address public msgInspector;\n event MsgInspectorSet(address inspector);\n\n /**\n * @dev Constructor.\n * @param _localDecimals The decimals of the token on the local chain (this chain).\n * @param _endpoint The address of the LayerZero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n */\n constructor(uint8 _localDecimals, address _endpoint, address _delegate) OApp(_endpoint, _delegate) {\n if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals();\n decimalConversionRate = 10 ** (_localDecimals - sharedDecimals());\n }\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) {\n return (type(IOFT).interfaceId, 1);\n }\n\n /**\n * @dev Retrieves the shared decimals of the OFT.\n * @return The shared decimals of the OFT.\n *\n * @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap\n * Lowest common decimal denominator between chains.\n * Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).\n * For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.\n * ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615\n */\n function sharedDecimals() public view virtual returns (uint8) {\n return 6;\n }\n\n /**\n * @dev Sets the message inspector address for the OFT.\n * @param _msgInspector The address of the message inspector.\n *\n * @dev This is an optional contract that can be used to inspect both 'message' and 'options'.\n * @dev Set it to address(0) to disable it, or set it to a contract address to enable it.\n */\n function setMsgInspector(address _msgInspector) public virtual onlyOwner {\n msgInspector = _msgInspector;\n emit MsgInspectorSet(_msgInspector);\n }\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return oftLimit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return oftReceipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n )\n external\n view\n virtual\n returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt)\n {\n uint256 minAmountLD = 0; // Unused in the default implementation.\n uint256 maxAmountLD = IERC20(this.token()).totalSupply(); // Unused in the default implementation.\n oftLimit = OFTLimit(minAmountLD, maxAmountLD);\n\n // Unused in the default implementation; reserved for future complex fee details.\n oftFeeDetails = new OFTFeeDetail[](0);\n\n // @dev This is the same as the send() operation, but without the actual send.\n // - amountSentLD is the amount in local decimals that would be sent from the sender.\n // - amountReceivedLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.\n // @dev The amountSentLD MIGHT not equal the amount the user actually receives. HOWEVER, the default does.\n (uint256 amountSentLD, uint256 amountReceivedLD) = _debitView(\n _sendParam.amountLD,\n _sendParam.minAmountLD,\n _sendParam.dstEid\n );\n oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);\n }\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return msgFee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(\n SendParam calldata _sendParam,\n bool _payInLzToken\n ) external view virtual returns (MessagingFee memory msgFee) {\n // @dev mock the amount to receive, this is the same operation used in the send().\n // The quote is as similar as possible to the actual send() operation.\n (, uint256 amountReceivedLD) = _debitView(_sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid);\n\n // @dev Builds the options and OFT message to quote in the endpoint.\n (bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);\n\n // @dev Calculates the LayerZero fee for the send() operation.\n return _quote(_sendParam.dstEid, message, options, _payInLzToken);\n }\n\n /**\n * @dev Executes the send operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The calculated fee for the send() operation.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds.\n * @return msgReceipt The receipt for the send operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {\n return _send(_sendParam, _fee, _refundAddress);\n }\n\n /**\n * @dev Internal function to execute the send operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The calculated fee for the send() operation.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds.\n * @return msgReceipt The receipt for the send operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {\n // @dev Applies the token transfers regarding this send() operation.\n // - amountSentLD is the amount in local decimals that was ACTUALLY sent/debited from the sender.\n // - amountReceivedLD is the amount in local decimals that will be received/credited to the recipient on the remote OFT instance.\n (uint256 amountSentLD, uint256 amountReceivedLD) = _debit(\n msg.sender,\n _sendParam.amountLD,\n _sendParam.minAmountLD,\n _sendParam.dstEid\n );\n\n // @dev Builds the options and OFT message to quote in the endpoint.\n (bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);\n\n // @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.\n msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);\n // @dev Formulate the OFT receipt.\n oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);\n\n emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD);\n }\n\n /**\n * @dev Internal function to build the message and options.\n * @param _sendParam The parameters for the send() operation.\n * @param _amountLD The amount in local decimals.\n * @return message The encoded message.\n * @return options The encoded options.\n */\n function _buildMsgAndOptions(\n SendParam calldata _sendParam,\n uint256 _amountLD\n ) internal view virtual returns (bytes memory message, bytes memory options) {\n bool hasCompose;\n // @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is.\n (message, hasCompose) = OFTMsgCodec.encode(\n _sendParam.to,\n _toSD(_amountLD),\n // @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote.\n // EVEN if you dont require an arbitrary payload to be sent... eg. '0x01'\n _sendParam.composeMsg\n );\n // @dev Change the msg type depending if its composed or not.\n uint16 msgType = hasCompose ? SEND_AND_CALL : SEND;\n // @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3.\n options = combineOptions(_sendParam.dstEid, msgType, _sendParam.extraOptions);\n\n // @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector.\n // @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean\n address inspector = msgInspector; // caches the msgInspector to avoid potential double storage read\n if (inspector != address(0)) IOAppMsgInspector(inspector).inspect(message, options);\n }\n\n /**\n * @dev Internal function to handle the receive on the LayerZero endpoint.\n * @param _origin The origin information.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address from the src chain.\n * - nonce: The nonce of the LayerZero message.\n * @param _guid The unique identifier for the received LayerZero message.\n * @param _message The encoded message.\n * @dev _executor The address of the executor.\n * @dev _extraData Additional data.\n */\n function _lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address /*_executor*/, // @dev unused in the default implementation.\n bytes calldata /*_extraData*/ // @dev unused in the default implementation.\n ) internal virtual override {\n // @dev The src sending chain doesnt know the address length on this chain (potentially non-evm)\n // Thus everything is bytes32() encoded in flight.\n address toAddress = _message.sendTo().bytes32ToAddress();\n // @dev Credit the amountLD to the recipient and return the ACTUAL amount the recipient received in local decimals\n uint256 amountReceivedLD = _credit(toAddress, _toLD(_message.amountSD()), _origin.srcEid);\n\n if (_message.isComposed()) {\n // @dev Proprietary composeMsg format for the OFT.\n bytes memory composeMsg = OFTComposeMsgCodec.encode(\n _origin.nonce,\n _origin.srcEid,\n amountReceivedLD,\n _message.composeMsg()\n );\n\n // @dev Stores the lzCompose payload that will be executed in a separate tx.\n // Standardizes functionality for executing arbitrary contract invocation on some non-evm chains.\n // @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed.\n // @dev The index is used when a OApp needs to compose multiple msgs on lzReceive.\n // For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0.\n endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg);\n }\n\n emit OFTReceived(_guid, _origin.srcEid, toAddress, amountReceivedLD);\n }\n\n /**\n * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.\n * @param _origin The origin information.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address from the src chain.\n * - nonce: The nonce of the LayerZero message.\n * @param _guid The unique identifier for the received LayerZero message.\n * @param _message The LayerZero message.\n * @param _executor The address of the off-chain executor.\n * @param _extraData Arbitrary data passed by the msg executor.\n *\n * @dev Enables the preCrime simulator to mock sending lzReceive() messages,\n * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.\n */\n function _lzReceiveSimulate(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) internal virtual override {\n _lzReceive(_origin, _guid, _message, _executor, _extraData);\n }\n\n /**\n * @dev Check if the peer is considered 'trusted' by the OApp.\n * @param _eid The endpoint ID to check.\n * @param _peer The peer to check.\n * @return Whether the peer passed is considered 'trusted' by the OApp.\n *\n * @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source.\n */\n function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) {\n return peers[_eid] == _peer;\n }\n\n /**\n * @dev Internal function to remove dust from the given local decimal amount.\n * @param _amountLD The amount in local decimals.\n * @return amountLD The amount after removing dust.\n *\n * @dev Prevents the loss of dust when moving amounts between chains with different decimals.\n * @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).\n */\n function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) {\n return (_amountLD / decimalConversionRate) * decimalConversionRate;\n }\n\n /**\n * @dev Internal function to convert an amount from shared decimals into local decimals.\n * @param _amountSD The amount in shared decimals.\n * @return amountLD The amount in local decimals.\n */\n function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) {\n return _amountSD * decimalConversionRate;\n }\n\n /**\n * @dev Internal function to convert an amount from local decimals into shared decimals.\n * @param _amountLD The amount in local decimals.\n * @return amountSD The amount in shared decimals.\n *\n * @dev Reverts if the _amountLD in shared decimals overflows uint64.\n * @dev eg. uint(2**64 + 123) with a conversion rate of 1 wraps around 2**64 to uint(123).\n */\n function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) {\n uint256 _amountSD = _amountLD / decimalConversionRate;\n if (_amountSD > type(uint64).max) revert AmountSDOverflowed(_amountSD);\n return uint64(_amountSD);\n }\n\n /**\n * @dev Internal function to mock the amount mutation from a OFT debit() operation.\n * @param _amountLD The amount to send in local decimals.\n * @param _minAmountLD The minimum amount to send in local decimals.\n * @dev _dstEid The destination endpoint ID.\n * @return amountSentLD The amount sent, in local decimals.\n * @return amountReceivedLD The amount to be received on the remote chain, in local decimals.\n *\n * @dev This is where things like fees would be calculated and deducted from the amount to be received on the remote.\n */\n function _debitView(\n uint256 _amountLD,\n uint256 _minAmountLD,\n uint32 /*_dstEid*/\n ) internal view virtual returns (uint256 amountSentLD, uint256 amountReceivedLD) {\n // @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token.\n amountSentLD = _removeDust(_amountLD);\n // @dev The amount to send is the same as amount received in the default implementation.\n amountReceivedLD = amountSentLD;\n\n // @dev Check for slippage.\n if (amountReceivedLD < _minAmountLD) {\n revert SlippageExceeded(amountReceivedLD, _minAmountLD);\n }\n }\n\n /**\n * @dev Internal function to perform a debit operation.\n * @param _from The address to debit.\n * @param _amountLD The amount to send in local decimals.\n * @param _minAmountLD The minimum amount to send in local decimals.\n * @param _dstEid The destination endpoint ID.\n * @return amountSentLD The amount sent in local decimals.\n * @return amountReceivedLD The amount received in local decimals on the remote.\n *\n * @dev Defined here but are intended to be overriden depending on the OFT implementation.\n * @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.\n */\n function _debit(\n address _from,\n uint256 _amountLD,\n uint256 _minAmountLD,\n uint32 _dstEid\n ) internal virtual returns (uint256 amountSentLD, uint256 amountReceivedLD);\n\n /**\n * @dev Internal function to perform a credit operation.\n * @param _to The address to credit.\n * @param _amountLD The amount to credit in local decimals.\n * @param _srcEid The source endpoint ID.\n * @return amountReceivedLD The amount ACTUALLY received in local decimals.\n *\n * @dev Defined here but are intended to be overriden depending on the OFT implementation.\n * @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.\n */\n function _credit(\n address _to,\n uint256 _amountLD,\n uint32 _srcEid\n ) internal virtual returns (uint256 amountReceivedLD);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)\npragma solidity >=0.8.4;\n\n/**\n * @dev Standard ERC-20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.\n */\ninterface IERC20Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC20InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC20InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n * @param allowance Amount of tokens a `spender` is allowed to operate with.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC20InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC-721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.\n */\ninterface IERC721Errors {\n /**\n * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.\n * Used in balance queries.\n * @param owner Address of the current owner of a token.\n */\n error ERC721InvalidOwner(address owner);\n\n /**\n * @dev Indicates a `tokenId` whose `owner` is the zero address.\n * @param tokenId Identifier number of a token.\n */\n error ERC721NonexistentToken(uint256 tokenId);\n\n /**\n * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param tokenId Identifier number of a token.\n * @param owner Address of the current owner of a token.\n */\n error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC721InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC721InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param tokenId Identifier number of a token.\n */\n error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC721InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC-1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.\n */\ninterface IERC1155Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n * @param tokenId Identifier number of a token.\n */\n error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC1155InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC1155InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param owner Address of the current owner of a token.\n */\n error ERC1155MissingApprovalForAll(address operator, address owner);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC1155InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC1155InvalidOperator(address operator);\n\n /**\n * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n * Used in batch transfers.\n * @param idsLength Length of the array of token identifiers\n * @param valuesLength Length of the array of token amounts\n */\n error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OApp.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n// @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers\n// solhint-disable-next-line no-unused-import\nimport { OAppSender, MessagingFee, MessagingReceipt } from \"./OAppSender.sol\";\n// @dev Import the 'Origin' so it's exposed to OApp implementers\n// solhint-disable-next-line no-unused-import\nimport { OAppReceiver, Origin } from \"./OAppReceiver.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OApp\n * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.\n */\nabstract contract OApp is OAppSender, OAppReceiver {\n /**\n * @dev Constructor to initialize the OApp with the provided endpoint and owner.\n * @param _endpoint The address of the LOCAL LayerZero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n */\n constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {}\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol implementation.\n * @return receiverVersion The version of the OAppReceiver.sol implementation.\n */\n function oAppVersion()\n public\n pure\n virtual\n override(OAppSender, OAppReceiver)\n returns (uint64 senderVersion, uint64 receiverVersion)\n {\n return (SENDER_VERSION, RECEIVER_VERSION);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppOptionsType3, EnforcedOptionParam } from \"../interfaces/IOAppOptionsType3.sol\";\n\n/**\n * @title OAppOptionsType3\n * @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options.\n */\nabstract contract OAppOptionsType3 is IOAppOptionsType3, Ownable {\n uint16 internal constant OPTION_TYPE_3 = 3;\n\n // @dev The \"msgType\" should be defined in the child contract.\n mapping(uint32 eid => mapping(uint16 msgType => bytes enforcedOption)) public enforcedOptions;\n\n /**\n * @dev Sets the enforced options for specific endpoint and message type combinations.\n * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.\n * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.\n * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay\n * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().\n */\n function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner {\n _setEnforcedOptions(_enforcedOptions);\n }\n\n /**\n * @dev Sets the enforced options for specific endpoint and message type combinations.\n * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.\n *\n * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.\n * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.\n * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay\n * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().\n */\n function _setEnforcedOptions(EnforcedOptionParam[] memory _enforcedOptions) internal virtual {\n for (uint256 i = 0; i < _enforcedOptions.length; i++) {\n // @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining.\n _assertOptionsType3(_enforcedOptions[i].options);\n enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options;\n }\n\n emit EnforcedOptionSet(_enforcedOptions);\n }\n\n /**\n * @notice Combines options for a given endpoint and message type.\n * @param _eid The endpoint ID.\n * @param _msgType The OAPP message type.\n * @param _extraOptions Additional options passed by the caller.\n * @return options The combination of caller specified options AND enforced options.\n *\n * @dev If there is an enforced lzReceive option:\n * - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether}\n * - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function.\n * @dev This presence of duplicated options is handled off-chain in the verifier/executor.\n */\n function combineOptions(\n uint32 _eid,\n uint16 _msgType,\n bytes calldata _extraOptions\n ) public view virtual returns (bytes memory) {\n bytes memory enforced = enforcedOptions[_eid][_msgType];\n\n // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options.\n if (enforced.length == 0) return _extraOptions;\n\n // No caller options, return enforced\n if (_extraOptions.length == 0) return enforced;\n\n // @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined.\n if (_extraOptions.length >= 2) {\n _assertOptionsType3(_extraOptions);\n // @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced.\n return bytes.concat(enforced, _extraOptions[2:]);\n }\n\n // No valid set of options was found.\n revert InvalidOptions(_extraOptions);\n }\n\n /**\n * @dev Internal function to assert that options are of type 3.\n * @param _options The options to be checked.\n */\n function _assertOptionsType3(bytes memory _options) internal pure virtual {\n uint16 optionsType;\n assembly {\n optionsType := mload(add(_options, 2))\n }\n if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppMsgInspector.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n/**\n * @title IOAppMsgInspector\n * @dev Interface for the OApp Message Inspector, allowing examination of message and options contents.\n */\ninterface IOAppMsgInspector {\n // Custom error message for inspection failure\n error InspectionFailed(bytes message, bytes options);\n\n /**\n * @notice Allows the inspector to examine LayerZero message contents and optionally throw a revert if invalid.\n * @param _message The message payload to be inspected.\n * @param _options Additional options or parameters for inspection.\n * @return valid A boolean indicating whether the inspection passed (true) or failed (false).\n *\n * @dev Optionally done as a revert, OR use the boolean provided to handle the failure.\n */\n function inspect(bytes calldata _message, bytes calldata _options) external view returns (bool valid);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/OAppPreCrimeSimulator.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IPreCrime } from \"./interfaces/IPreCrime.sol\";\nimport { IOAppPreCrimeSimulator, InboundPacket, Origin } from \"./interfaces/IOAppPreCrimeSimulator.sol\";\n\n/**\n * @title OAppPreCrimeSimulator\n * @dev Abstract contract serving as the base for preCrime simulation functionality in an OApp.\n */\nabstract contract OAppPreCrimeSimulator is IOAppPreCrimeSimulator, Ownable {\n // The address of the preCrime implementation.\n address public preCrime;\n\n /**\n * @dev Retrieves the address of the OApp contract.\n * @return The address of the OApp contract.\n *\n * @dev The simulator contract is the base contract for the OApp by default.\n * @dev If the simulator is a separate contract, override this function.\n */\n function oApp() external view virtual returns (address) {\n return address(this);\n }\n\n /**\n * @dev Sets the preCrime contract address.\n * @param _preCrime The address of the preCrime contract.\n */\n function setPreCrime(address _preCrime) public virtual onlyOwner {\n preCrime = _preCrime;\n emit PreCrimeSet(_preCrime);\n }\n\n /**\n * @dev Interface for pre-crime simulations. Always reverts at the end with the simulation results.\n * @param _packets An array of InboundPacket objects representing received packets to be delivered.\n *\n * @dev WARNING: MUST revert at the end with the simulation results.\n * @dev Gives the preCrime implementation the ability to mock sending packets to the lzReceive function,\n * WITHOUT actually executing them.\n */\n function lzReceiveAndRevert(InboundPacket[] calldata _packets) public payable virtual {\n for (uint256 i = 0; i < _packets.length; i++) {\n InboundPacket calldata packet = _packets[i];\n\n // Ignore packets that are not from trusted peers.\n if (!isPeer(packet.origin.srcEid, packet.origin.sender)) continue;\n\n // @dev Because a verifier is calling this function, it doesnt have access to executor params:\n // - address _executor\n // - bytes calldata _extraData\n // preCrime will NOT work for OApps that rely on these two parameters inside of their _lzReceive().\n // They are instead stubbed to default values, address(0) and bytes(\"\")\n // @dev Calling this.lzReceiveSimulate removes ability for assembly return 0 callstack exit,\n // which would cause the revert to be ignored.\n this.lzReceiveSimulate{ value: packet.value }(\n packet.origin,\n packet.guid,\n packet.message,\n packet.executor,\n packet.extraData\n );\n }\n\n // @dev Revert with the simulation results. msg.sender must implement IPreCrime.buildSimulationResult().\n revert SimulationResult(IPreCrime(msg.sender).buildSimulationResult());\n }\n\n /**\n * @dev Is effectively an internal function because msg.sender must be address(this).\n * Allows resetting the call stack for 'internal' calls.\n * @param _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @param _guid The unique identifier of the packet.\n * @param _message The message payload of the packet.\n * @param _executor The executor address for the packet.\n * @param _extraData Additional data for the packet.\n */\n function lzReceiveSimulate(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) external payable virtual {\n // @dev Ensure ONLY can be called 'internally'.\n if (msg.sender != address(this)) revert OnlySelf();\n _lzReceiveSimulate(_origin, _guid, _message, _executor, _extraData);\n }\n\n /**\n * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.\n * @param _origin The origin information.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address from the src chain.\n * - nonce: The nonce of the LayerZero message.\n * @param _guid The GUID of the LayerZero message.\n * @param _message The LayerZero message.\n * @param _executor The address of the off-chain executor.\n * @param _extraData Arbitrary data passed by the msg executor.\n *\n * @dev Enables the preCrime simulator to mock sending lzReceive() messages,\n * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.\n */\n function _lzReceiveSimulate(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) internal virtual;\n\n /**\n * @dev checks if the specified peer is considered 'trusted' by the OApp.\n * @param _eid The endpoint Id to check.\n * @param _peer The peer to check.\n * @return Whether the peer passed is considered 'trusted' by the OApp.\n */\n function isPeer(uint32 _eid, bytes32 _peer) public view virtual returns (bool);\n}\n"},"lib/devtools/packages/oft-evm/contracts/interfaces/IOFT.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { MessagingReceipt, MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\n\n/**\n * @dev Struct representing token parameters for the OFT send() operation.\n */\nstruct SendParam {\n uint32 dstEid; // Destination endpoint ID.\n bytes32 to; // Recipient address.\n uint256 amountLD; // Amount to send in local decimals.\n uint256 minAmountLD; // Minimum amount to send in local decimals.\n bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.\n bytes composeMsg; // The composed message for the send() operation.\n bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.\n}\n\n/**\n * @dev Struct representing OFT limit information.\n * @dev These amounts can change dynamically and are up the specific oft implementation.\n */\nstruct OFTLimit {\n uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.\n uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.\n}\n\n/**\n * @dev Struct representing OFT receipt information.\n */\nstruct OFTReceipt {\n uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.\n // @dev In non-default implementations, the amountReceivedLD COULD differ from this value.\n uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.\n}\n\n/**\n * @dev Struct representing OFT fee details.\n * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.\n */\nstruct OFTFeeDetail {\n int256 feeAmountLD; // Amount of the fee in local decimals.\n string description; // Description of the fee.\n}\n\n/**\n * @title IOFT\n * @dev Interface for the OftChain (OFT) token.\n * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.\n * @dev This specific interface ID is '0x02e49c2c'.\n */\ninterface IOFT {\n // Custom error messages\n error InvalidLocalDecimals();\n error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);\n error AmountSDOverflowed(uint256 amountSD);\n\n // Events\n event OFTSent(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 dstEid, // Destination Endpoint ID.\n address indexed fromAddress, // Address of the sender on the src chain.\n uint256 amountSentLD, // Amount of tokens sent in local decimals.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n event OFTReceived(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 srcEid, // Source Endpoint ID.\n address indexed toAddress, // Address of the recipient on the dst chain.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external view returns (bytes4 interfaceId, uint64 version);\n\n /**\n * @notice Retrieves the address of the token associated with the OFT.\n * @return token The address of the ERC20 token implementation.\n */\n function token() external view returns (address);\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev Allows things like wallet implementers to determine integration requirements,\n * without understanding the underlying token implementation.\n */\n function approvalRequired() external view returns (bool);\n\n /**\n * @notice Retrieves the shared decimals of the OFT.\n * @return sharedDecimals The shared decimals of the OFT.\n */\n function sharedDecimals() external view returns (uint8);\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return limit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return receipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return fee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);\n\n /**\n * @notice Executes the send() operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The fee information supplied by the caller.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds from fees etc. on the src.\n * @return receipt The LayerZero messaging receipt from the send() operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory, OFTReceipt memory);\n}\n"},"lib/devtools/packages/oft-evm/contracts/libs/OFTMsgCodec.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nlibrary OFTMsgCodec {\n // Offset constants for encoding and decoding OFT messages\n uint8 private constant SEND_TO_OFFSET = 32;\n uint8 private constant SEND_AMOUNT_SD_OFFSET = 40;\n\n /**\n * @dev Encodes an OFT LayerZero message.\n * @param _sendTo The recipient address.\n * @param _amountShared The amount in shared decimals.\n * @param _composeMsg The composed message.\n * @return _msg The encoded message.\n * @return hasCompose A boolean indicating whether the message has a composed payload.\n */\n function encode(\n bytes32 _sendTo,\n uint64 _amountShared,\n bytes memory _composeMsg\n ) internal view returns (bytes memory _msg, bool hasCompose) {\n hasCompose = _composeMsg.length > 0;\n // @dev Remote chains will want to know the composed function caller ie. msg.sender on the src.\n _msg = hasCompose\n ? abi.encodePacked(_sendTo, _amountShared, addressToBytes32(msg.sender), _composeMsg)\n : abi.encodePacked(_sendTo, _amountShared);\n }\n\n /**\n * @dev Checks if the OFT message is composed.\n * @param _msg The OFT message.\n * @return A boolean indicating whether the message is composed.\n */\n function isComposed(bytes calldata _msg) internal pure returns (bool) {\n return _msg.length > SEND_AMOUNT_SD_OFFSET;\n }\n\n /**\n * @dev Retrieves the recipient address from the OFT message.\n * @param _msg The OFT message.\n * @return The recipient address.\n */\n function sendTo(bytes calldata _msg) internal pure returns (bytes32) {\n return bytes32(_msg[:SEND_TO_OFFSET]);\n }\n\n /**\n * @dev Retrieves the amount in shared decimals from the OFT message.\n * @param _msg The OFT message.\n * @return The amount in shared decimals.\n */\n function amountSD(bytes calldata _msg) internal pure returns (uint64) {\n return uint64(bytes8(_msg[SEND_TO_OFFSET:SEND_AMOUNT_SD_OFFSET]));\n }\n\n /**\n * @dev Retrieves the composed message from the OFT message.\n * @param _msg The OFT message.\n * @return The composed message.\n */\n function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {\n return _msg[SEND_AMOUNT_SD_OFFSET:];\n }\n\n /**\n * @dev Converts an address to bytes32.\n * @param _addr The address to convert.\n * @return The bytes32 representation of the address.\n */\n function addressToBytes32(address _addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(_addr)));\n }\n\n /**\n * @dev Converts bytes32 to an address.\n * @param _b The bytes32 value to convert.\n * @return The address representation of bytes32.\n */\n function bytes32ToAddress(bytes32 _b) internal pure returns (address) {\n return address(uint160(uint256(_b)));\n }\n}\n"},"lib/devtools/packages/oft-evm/contracts/libs/OFTComposeMsgCodec.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nlibrary OFTComposeMsgCodec {\n // Offset constants for decoding composed messages\n uint8 private constant NONCE_OFFSET = 8;\n uint8 private constant SRC_EID_OFFSET = 12;\n uint8 private constant AMOUNT_LD_OFFSET = 44;\n uint8 private constant COMPOSE_FROM_OFFSET = 76;\n\n /**\n * @dev Encodes a OFT composed message.\n * @param _nonce The nonce value.\n * @param _srcEid The source endpoint ID.\n * @param _amountLD The amount in local decimals.\n * @param _composeMsg The composed message.\n * @return _msg The encoded Composed message.\n */\n function encode(\n uint64 _nonce,\n uint32 _srcEid,\n uint256 _amountLD,\n bytes memory _composeMsg // 0x[composeFrom][composeMsg]\n ) internal pure returns (bytes memory _msg) {\n _msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg);\n }\n\n /**\n * @dev Retrieves the nonce for the composed message.\n * @param _msg The message.\n * @return The nonce value.\n */\n function nonce(bytes calldata _msg) internal pure returns (uint64) {\n return uint64(bytes8(_msg[:NONCE_OFFSET]));\n }\n\n /**\n * @dev Retrieves the source endpoint ID for the composed message.\n * @param _msg The message.\n * @return The source endpoint ID.\n */\n function srcEid(bytes calldata _msg) internal pure returns (uint32) {\n return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET]));\n }\n\n /**\n * @dev Retrieves the amount in local decimals from the composed message.\n * @param _msg The message.\n * @return The amount in local decimals.\n */\n function amountLD(bytes calldata _msg) internal pure returns (uint256) {\n return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET]));\n }\n\n /**\n * @dev Retrieves the composeFrom value from the composed message.\n * @param _msg The message.\n * @return The composeFrom value.\n */\n function composeFrom(bytes calldata _msg) internal pure returns (bytes32) {\n return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]);\n }\n\n /**\n * @dev Retrieves the composed message.\n * @param _msg The message.\n * @return The composed message.\n */\n function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {\n return _msg[COMPOSE_FROM_OFFSET:];\n }\n\n /**\n * @dev Converts an address to bytes32.\n * @param _addr The address to convert.\n * @return The bytes32 representation of the address.\n */\n function addressToBytes32(address _addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(_addr)));\n }\n\n /**\n * @dev Converts bytes32 to an address.\n * @param _b The bytes32 value to convert.\n * @return The address representation of bytes32.\n */\n function bytes32ToAddress(bytes32 _b) internal pure returns (address) {\n return address(uint160(uint256(_b)));\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OAppSender.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { MessagingParams, MessagingFee, MessagingReceipt } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppSender\n * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.\n */\nabstract contract OAppSender is OAppCore {\n using SafeERC20 for IERC20;\n\n // Custom error messages\n error NotEnoughNative(uint256 msgValue);\n error LzTokenUnavailable();\n\n // @dev The version of the OAppSender implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant SENDER_VERSION = 1;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.\n * ie. this is a SEND only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (SENDER_VERSION, 0);\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.\n * @return fee The calculated MessagingFee for the message.\n * - nativeFee: The native fee for the message.\n * - lzTokenFee: The LZ token fee for the message.\n */\n function _quote(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n bool _payInLzToken\n ) internal view virtual returns (MessagingFee memory fee) {\n return\n endpoint.quote(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),\n address(this)\n );\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _fee The calculated LayerZero fee for the message.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess fee values sent to the endpoint.\n * @return receipt The receipt for the sent message.\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _lzSend(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n MessagingFee memory _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory receipt) {\n // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.\n uint256 messageValue = _payNative(_fee.nativeFee);\n if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);\n\n return\n // solhint-disable-next-line check-send-result\n endpoint.send{ value: messageValue }(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),\n _refundAddress\n );\n }\n\n /**\n * @dev Internal function to pay the native fee associated with the message.\n * @param _nativeFee The native fee to be paid.\n * @return nativeFee The amount of native currency paid.\n *\n * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,\n * this will need to be overridden because msg.value would contain multiple lzFees.\n * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.\n * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.\n * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.\n */\n function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {\n if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);\n return _nativeFee;\n }\n\n /**\n * @dev Internal function to pay the LZ token fee associated with the message.\n * @param _lzTokenFee The LZ token fee to be paid.\n *\n * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.\n * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().\n */\n function _payLzToken(uint256 _lzTokenFee) internal virtual {\n // @dev Cannot cache the token because it is not immutable in the endpoint.\n address lzToken = endpoint.lzToken();\n if (lzToken == address(0)) revert LzTokenUnavailable();\n\n // Pay LZ token fee by sending tokens to the endpoint.\n IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OAppReceiver.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IOAppReceiver, Origin } from \"./interfaces/IOAppReceiver.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppReceiver\n * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.\n */\nabstract contract OAppReceiver is IOAppReceiver, OAppCore {\n // Custom error message for when the caller is not the registered endpoint/\n error OnlyEndpoint(address addr);\n\n // @dev The version of the OAppReceiver implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant RECEIVER_VERSION = 2;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.\n * ie. this is a RECEIVE only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (0, RECEIVER_VERSION);\n }\n\n /**\n * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.\n * @dev _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @dev _message The lzReceive payload.\n * @param _sender The sender address.\n * @return isSender Is a valid sender.\n *\n * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer.\n * @dev The default sender IS the OAppReceiver implementer.\n */\n function isComposeMsgSender(\n Origin calldata /*_origin*/,\n bytes calldata /*_message*/,\n address _sender\n ) public view virtual returns (bool) {\n return _sender == address(this);\n }\n\n /**\n * @notice Checks if the path initialization is allowed based on the provided origin.\n * @param origin The origin information containing the source endpoint and sender address.\n * @return Whether the path has been initialized.\n *\n * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.\n * @dev This defaults to assuming if a peer has been set, its initialized.\n * Can be overridden by the OApp if there is other logic to determine this.\n */\n function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {\n return peers[origin.srcEid] == origin.sender;\n }\n\n /**\n * @notice Retrieves the next nonce for a given source endpoint and sender address.\n * @dev _srcEid The source endpoint ID.\n * @dev _sender The sender address.\n * @return nonce The next nonce.\n *\n * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.\n * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.\n * @dev This is also enforced by the OApp.\n * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.\n */\n function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {\n return 0;\n }\n\n /**\n * @dev Entry point for receiving messages or packets from the endpoint.\n * @param _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @param _guid The unique identifier for the received LayerZero message.\n * @param _message The payload of the received message.\n * @param _executor The address of the executor for the received message.\n * @param _extraData Additional arbitrary data provided by the corresponding executor.\n *\n * @dev Entry point for receiving msg/packet from the LayerZero endpoint.\n */\n function lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) public payable virtual {\n // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.\n if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);\n\n // Ensure that the sender matches the expected peer for the source endpoint.\n if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);\n\n // Call the internal OApp implementation of lzReceive.\n _lzReceive(_origin, _guid, _message, _executor, _extraData);\n }\n\n /**\n * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.\n */\n function _lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) internal virtual;\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OAppCore.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppCore, ILayerZeroEndpointV2 } from \"./interfaces/IOAppCore.sol\";\n\n/**\n * @title OAppCore\n * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.\n */\nabstract contract OAppCore is IOAppCore, Ownable {\n // The LayerZero endpoint associated with the given OApp\n ILayerZeroEndpointV2 public immutable endpoint;\n\n // Mapping to store peers associated with corresponding endpoints\n mapping(uint32 eid => bytes32 peer) public peers;\n\n /**\n * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.\n * @param _endpoint The address of the LOCAL Layer Zero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n *\n * @dev The delegate typically should be set as the owner of the contract.\n */\n constructor(address _endpoint, address _delegate) {\n endpoint = ILayerZeroEndpointV2(_endpoint);\n\n if (_delegate == address(0)) revert InvalidDelegate();\n endpoint.setDelegate(_delegate);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {\n _setPeer(_eid, _peer);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {\n peers[_eid] = _peer;\n emit PeerSet(_eid, _peer);\n }\n\n /**\n * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.\n * ie. the peer is set to bytes32(0).\n * @param _eid The endpoint ID.\n * @return peer The address of the peer associated with the specified endpoint.\n */\n function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {\n bytes32 peer = peers[_eid];\n if (peer == bytes32(0)) revert NoPeer(_eid);\n return peer;\n }\n\n /**\n * @notice Sets the delegate address for the OApp.\n * @param _delegate The address of the delegate to be set.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.\n */\n function setDelegate(address _delegate) public onlyOwner {\n endpoint.setDelegate(_delegate);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppOptionsType3.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Struct representing enforced option parameters.\n */\nstruct EnforcedOptionParam {\n uint32 eid; // Endpoint ID\n uint16 msgType; // Message Type\n bytes options; // Additional options\n}\n\n/**\n * @title IOAppOptionsType3\n * @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options.\n */\ninterface IOAppOptionsType3 {\n // Custom error message for invalid options\n error InvalidOptions(bytes options);\n\n // Event emitted when enforced options are set\n event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions);\n\n /**\n * @notice Sets enforced options for specific endpoint and message type combinations.\n * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.\n */\n function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external;\n\n /**\n * @notice Combines options for a given endpoint and message type.\n * @param _eid The endpoint ID.\n * @param _msgType The OApp message type.\n * @param _extraOptions Additional options passed by the caller.\n * @return options The combination of caller specified options AND enforced options.\n */\n function combineOptions(\n uint32 _eid,\n uint16 _msgType,\n bytes calldata _extraOptions\n ) external view returns (bytes memory options);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/interfaces/IPreCrime.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\nstruct PreCrimePeer {\n uint32 eid;\n bytes32 preCrime;\n bytes32 oApp;\n}\n\n// TODO not done yet\ninterface IPreCrime {\n error OnlyOffChain();\n\n // for simulate()\n error PacketOversize(uint256 max, uint256 actual);\n error PacketUnsorted();\n error SimulationFailed(bytes reason);\n\n // for preCrime()\n error SimulationResultNotFound(uint32 eid);\n error InvalidSimulationResult(uint32 eid, bytes reason);\n error CrimeFound(bytes crime);\n\n function getConfig(bytes[] calldata _packets, uint256[] calldata _packetMsgValues) external returns (bytes memory);\n\n function simulate(\n bytes[] calldata _packets,\n uint256[] calldata _packetMsgValues\n ) external payable returns (bytes memory);\n\n function buildSimulationResult() external view returns (bytes memory);\n\n function preCrime(\n bytes[] calldata _packets,\n uint256[] calldata _packetMsgValues,\n bytes[] calldata _simulations\n ) external;\n\n function version() external view returns (uint64 major, uint8 minor);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n// @dev Import the Origin so it's exposed to OAppPreCrimeSimulator implementers.\n// solhint-disable-next-line no-unused-import\nimport { InboundPacket, Origin } from \"../libs/Packet.sol\";\n\n/**\n * @title IOAppPreCrimeSimulator Interface\n * @dev Interface for the preCrime simulation functionality in an OApp.\n */\ninterface IOAppPreCrimeSimulator {\n // @dev simulation result used in PreCrime implementation\n error SimulationResult(bytes result);\n error OnlySelf();\n\n /**\n * @dev Emitted when the preCrime contract address is set.\n * @param preCrimeAddress The address of the preCrime contract.\n */\n event PreCrimeSet(address preCrimeAddress);\n\n /**\n * @dev Retrieves the address of the preCrime contract implementation.\n * @return The address of the preCrime contract.\n */\n function preCrime() external view returns (address);\n\n /**\n * @dev Retrieves the address of the OApp contract.\n * @return The address of the OApp contract.\n */\n function oApp() external view returns (address);\n\n /**\n * @dev Sets the preCrime contract address.\n * @param _preCrime The address of the preCrime contract.\n */\n function setPreCrime(address _preCrime) external;\n\n /**\n * @dev Mocks receiving a packet, then reverts with a series of data to infer the state/result.\n * @param _packets An array of LayerZero InboundPacket objects representing received packets.\n */\n function lzReceiveAndRevert(InboundPacket[] calldata _packets) external payable;\n\n /**\n * @dev checks if the specified peer is considered 'trusted' by the OApp.\n * @param _eid The endpoint Id to check.\n * @param _peer The peer to check.\n * @return Whether the peer passed is considered 'trusted' by the OApp.\n */\n function isPeer(uint32 _eid, bytes32 _peer) external view returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IMessageLibManager } from \"./IMessageLibManager.sol\";\nimport { IMessagingComposer } from \"./IMessagingComposer.sol\";\nimport { IMessagingChannel } from \"./IMessagingChannel.sol\";\nimport { IMessagingContext } from \"./IMessagingContext.sol\";\n\nstruct MessagingParams {\n uint32 dstEid;\n bytes32 receiver;\n bytes message;\n bytes options;\n bool payInLzToken;\n}\n\nstruct MessagingReceipt {\n bytes32 guid;\n uint64 nonce;\n MessagingFee fee;\n}\n\nstruct MessagingFee {\n uint256 nativeFee;\n uint256 lzTokenFee;\n}\n\nstruct Origin {\n uint32 srcEid;\n bytes32 sender;\n uint64 nonce;\n}\n\ninterface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {\n event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);\n\n event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);\n\n event PacketDelivered(Origin origin, address receiver);\n\n event LzReceiveAlert(\n address indexed receiver,\n address indexed executor,\n Origin origin,\n bytes32 guid,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n event LzTokenSet(address token);\n\n event DelegateSet(address sender, address delegate);\n\n function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);\n\n function send(\n MessagingParams calldata _params,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory);\n\n function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;\n\n function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function initializable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function lzReceive(\n Origin calldata _origin,\n address _receiver,\n bytes32 _guid,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n\n // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order\n function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;\n\n function setLzToken(address _lzToken) external;\n\n function lzToken() external view returns (address);\n\n function nativeToken() external view returns (address);\n\n function setDelegate(address _delegate) external;\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppReceiver.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport { ILayerZeroReceiver, Origin } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol\";\n\ninterface IOAppReceiver is ILayerZeroReceiver {\n /**\n * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.\n * @param _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @param _message The lzReceive payload.\n * @param _sender The sender address.\n * @return isSender Is a valid sender.\n *\n * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.\n * @dev The default sender IS the OAppReceiver implementer.\n */\n function isComposeMsgSender(\n Origin calldata _origin,\n bytes calldata _message,\n address _sender\n ) external view returns (bool isSender);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ILayerZeroEndpointV2 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\n\n/**\n * @title IOAppCore\n */\ninterface IOAppCore {\n // Custom error messages\n error OnlyPeer(uint32 eid, bytes32 sender);\n error NoPeer(uint32 eid);\n error InvalidEndpointCall();\n error InvalidDelegate();\n\n // Event emitted when a peer (OApp) is set for a corresponding endpoint\n event PeerSet(uint32 eid, bytes32 peer);\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n */\n function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);\n\n /**\n * @notice Retrieves the LayerZero endpoint associated with the OApp.\n * @return iEndpoint The LayerZero endpoint as an interface.\n */\n function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);\n\n /**\n * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @return peer The peer address (OApp instance) associated with the corresponding endpoint.\n */\n function peers(uint32 _eid) external view returns (bytes32 peer);\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n */\n function setPeer(uint32 _eid, bytes32 _peer) external;\n\n /**\n * @notice Sets the delegate address for the OApp Core.\n * @param _delegate The address of the delegate to be set.\n */\n function setDelegate(address _delegate) external;\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/libs/Packet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Origin } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { PacketV1Codec } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol\";\n\n/**\n * @title InboundPacket\n * @dev Structure representing an inbound packet received by the contract.\n */\nstruct InboundPacket {\n Origin origin; // Origin information of the packet.\n uint32 dstEid; // Destination endpointId of the packet.\n address receiver; // Receiver address for the packet.\n bytes32 guid; // Unique identifier of the packet.\n uint256 value; // msg.value of the packet.\n address executor; // Executor address for the packet.\n bytes message; // Message payload of the packet.\n bytes extraData; // Additional arbitrary data for the packet.\n}\n\n/**\n * @title PacketDecoder\n * @dev Library for decoding LayerZero packets.\n */\nlibrary PacketDecoder {\n using PacketV1Codec for bytes;\n\n /**\n * @dev Decode an inbound packet from the given packet data.\n * @param _packet The packet data to decode.\n * @return packet An InboundPacket struct representing the decoded packet.\n */\n function decode(bytes calldata _packet) internal pure returns (InboundPacket memory packet) {\n packet.origin = Origin(_packet.srcEid(), _packet.sender(), _packet.nonce());\n packet.dstEid = _packet.dstEid();\n packet.receiver = _packet.receiverB20();\n packet.guid = _packet.guid();\n packet.message = _packet.message();\n }\n\n /**\n * @dev Decode multiple inbound packets from the given packet data and associated message values.\n * @param _packets An array of packet data to decode.\n * @param _packetMsgValues An array of associated message values for each packet.\n * @return packets An array of InboundPacket structs representing the decoded packets.\n */\n function decode(\n bytes[] calldata _packets,\n uint256[] memory _packetMsgValues\n ) internal pure returns (InboundPacket[] memory packets) {\n packets = new InboundPacket[](_packets.length);\n for (uint256 i = 0; i < _packets.length; i++) {\n bytes calldata packet = _packets[i];\n packets[i] = PacketDecoder.decode(packet);\n // @dev Allows the verifier to specify the msg.value that gets passed in lzReceive.\n packets[i].value = _packetMsgValues[i];\n }\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessageLibManager.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nstruct SetConfigParam {\n uint32 eid;\n uint32 configType;\n bytes config;\n}\n\ninterface IMessageLibManager {\n struct Timeout {\n address lib;\n uint256 expiry;\n }\n\n event LibraryRegistered(address newLib);\n event DefaultSendLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);\n event SendLibrarySet(address sender, uint32 eid, address newLib);\n event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);\n event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);\n\n function registerLibrary(address _lib) external;\n\n function isRegisteredLibrary(address _lib) external view returns (bool);\n\n function getRegisteredLibraries() external view returns (address[] memory);\n\n function setDefaultSendLibrary(uint32 _eid, address _newLib) external;\n\n function defaultSendLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _timeout) external;\n\n function defaultReceiveLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;\n\n function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);\n\n /// ------------------- OApp interfaces -------------------\n function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;\n\n function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);\n\n function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);\n\n function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);\n\n function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _gracePeriod) external;\n\n function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;\n\n function getConfig(\n address _oapp,\n address _lib,\n uint32 _eid,\n uint32 _configType\n ) external view returns (bytes memory config);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessagingComposer.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingComposer {\n event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);\n event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);\n event LzComposeAlert(\n address indexed from,\n address indexed to,\n address indexed executor,\n bytes32 guid,\n uint16 index,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n function composeQueue(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index\n ) external view returns (bytes32 messageHash);\n\n function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;\n\n function lzCompose(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessagingChannel.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingChannel {\n event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);\n event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n\n function eid() external view returns (uint32);\n\n // this is an emergency function if a message cannot be verified for some reasons\n // required to provide _nextNonce to avoid race condition\n function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;\n\n function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);\n\n function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n\n function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);\n\n function inboundPayloadHash(\n address _receiver,\n uint32 _srcEid,\n bytes32 _sender,\n uint64 _nonce\n ) external view returns (bytes32);\n\n function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessagingContext.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingContext {\n function isSendingMessage() external view returns (bool);\n\n function getSendContext() external view returns (uint32 dstEid, address sender);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/ILayerZeroReceiver.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { Origin } from \"./ILayerZeroEndpointV2.sol\";\n\ninterface ILayerZeroReceiver {\n function allowInitializePath(Origin calldata _origin) external view returns (bool);\n\n function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64);\n\n function lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) external payable;\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/messagelib/libs/PacketV1Codec.sol":{"content":"// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport { Packet } from \"../../interfaces/ISendLib.sol\";\nimport { AddressCast } from \"../../libs/AddressCast.sol\";\n\nlibrary PacketV1Codec {\n using AddressCast for address;\n using AddressCast for bytes32;\n\n uint8 internal constant PACKET_VERSION = 1;\n\n // header (version + nonce + path)\n // version\n uint256 private constant PACKET_VERSION_OFFSET = 0;\n // nonce\n uint256 private constant NONCE_OFFSET = 1;\n // path\n uint256 private constant SRC_EID_OFFSET = 9;\n uint256 private constant SENDER_OFFSET = 13;\n uint256 private constant DST_EID_OFFSET = 45;\n uint256 private constant RECEIVER_OFFSET = 49;\n // payload (guid + message)\n uint256 private constant GUID_OFFSET = 81; // keccak256(nonce + path)\n uint256 private constant MESSAGE_OFFSET = 113;\n\n function encode(Packet memory _packet) internal pure returns (bytes memory encodedPacket) {\n encodedPacket = abi.encodePacked(\n PACKET_VERSION,\n _packet.nonce,\n _packet.srcEid,\n _packet.sender.toBytes32(),\n _packet.dstEid,\n _packet.receiver,\n _packet.guid,\n _packet.message\n );\n }\n\n function encodePacketHeader(Packet memory _packet) internal pure returns (bytes memory) {\n return\n abi.encodePacked(\n PACKET_VERSION,\n _packet.nonce,\n _packet.srcEid,\n _packet.sender.toBytes32(),\n _packet.dstEid,\n _packet.receiver\n );\n }\n\n function encodePayload(Packet memory _packet) internal pure returns (bytes memory) {\n return abi.encodePacked(_packet.guid, _packet.message);\n }\n\n function header(bytes calldata _packet) internal pure returns (bytes calldata) {\n return _packet[0:GUID_OFFSET];\n }\n\n function version(bytes calldata _packet) internal pure returns (uint8) {\n return uint8(bytes1(_packet[PACKET_VERSION_OFFSET:NONCE_OFFSET]));\n }\n\n function nonce(bytes calldata _packet) internal pure returns (uint64) {\n return uint64(bytes8(_packet[NONCE_OFFSET:SRC_EID_OFFSET]));\n }\n\n function srcEid(bytes calldata _packet) internal pure returns (uint32) {\n return uint32(bytes4(_packet[SRC_EID_OFFSET:SENDER_OFFSET]));\n }\n\n function sender(bytes calldata _packet) internal pure returns (bytes32) {\n return bytes32(_packet[SENDER_OFFSET:DST_EID_OFFSET]);\n }\n\n function senderAddressB20(bytes calldata _packet) internal pure returns (address) {\n return sender(_packet).toAddress();\n }\n\n function dstEid(bytes calldata _packet) internal pure returns (uint32) {\n return uint32(bytes4(_packet[DST_EID_OFFSET:RECEIVER_OFFSET]));\n }\n\n function receiver(bytes calldata _packet) internal pure returns (bytes32) {\n return bytes32(_packet[RECEIVER_OFFSET:GUID_OFFSET]);\n }\n\n function receiverB20(bytes calldata _packet) internal pure returns (address) {\n return receiver(_packet).toAddress();\n }\n\n function guid(bytes calldata _packet) internal pure returns (bytes32) {\n return bytes32(_packet[GUID_OFFSET:MESSAGE_OFFSET]);\n }\n\n function message(bytes calldata _packet) internal pure returns (bytes calldata) {\n return bytes(_packet[MESSAGE_OFFSET:]);\n }\n\n function payload(bytes calldata _packet) internal pure returns (bytes calldata) {\n return bytes(_packet[GUID_OFFSET:]);\n }\n\n function payloadHash(bytes calldata _packet) internal pure returns (bytes32) {\n return keccak256(payload(_packet));\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/ISendLib.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { MessagingFee } from \"./ILayerZeroEndpointV2.sol\";\nimport { IMessageLib } from \"./IMessageLib.sol\";\n\nstruct Packet {\n uint64 nonce;\n uint32 srcEid;\n address sender;\n uint32 dstEid;\n bytes32 receiver;\n bytes32 guid;\n bytes message;\n}\n\ninterface ISendLib is IMessageLib {\n function send(\n Packet calldata _packet,\n bytes calldata _options,\n bool _payInLzToken\n ) external returns (MessagingFee memory, bytes memory encodedPacket);\n\n function quote(\n Packet calldata _packet,\n bytes calldata _options,\n bool _payInLzToken\n ) external view returns (MessagingFee memory);\n\n function setTreasury(address _treasury) external;\n\n function withdrawFee(address _to, uint256 _amount) external;\n\n function withdrawLzTokenFee(address _lzToken, address _to, uint256 _amount) external;\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/libs/AddressCast.sol":{"content":"// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nlibrary AddressCast {\n error AddressCast_InvalidSizeForAddress();\n error AddressCast_InvalidAddress();\n\n function toBytes32(bytes calldata _addressBytes) internal pure returns (bytes32 result) {\n if (_addressBytes.length > 32) revert AddressCast_InvalidAddress();\n result = bytes32(_addressBytes);\n unchecked {\n uint256 offset = 32 - _addressBytes.length;\n result = result >> (offset * 8);\n }\n }\n\n function toBytes32(address _address) internal pure returns (bytes32 result) {\n result = bytes32(uint256(uint160(_address)));\n }\n\n function toBytes(bytes32 _addressBytes32, uint256 _size) internal pure returns (bytes memory result) {\n if (_size == 0 || _size > 32) revert AddressCast_InvalidSizeForAddress();\n result = new bytes(_size);\n unchecked {\n uint256 offset = 256 - _size * 8;\n assembly {\n mstore(add(result, 32), shl(offset, _addressBytes32))\n }\n }\n }\n\n function toAddress(bytes32 _addressBytes32) internal pure returns (address result) {\n result = address(uint160(uint256(_addressBytes32)));\n }\n\n function toAddress(bytes calldata _addressBytes) internal pure returns (address result) {\n if (_addressBytes.length != 20) revert AddressCast_InvalidAddress();\n result = address(bytes20(_addressBytes));\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessageLib.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\nimport { SetConfigParam } from \"./IMessageLibManager.sol\";\n\nenum MessageLibType {\n Send,\n Receive,\n SendAndReceive\n}\n\ninterface IMessageLib is IERC165 {\n function setConfig(address _oapp, SetConfigParam[] calldata _config) external;\n\n function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view returns (bytes memory config);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n // message libs of same major version are compatible\n function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion);\n\n function messageLibType() external view returns (MessageLibType);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/locked-bytecode-dev/UpOFTAdapter.standard-json-input.json b/script/locked-bytecode-dev/UpOFTAdapter.standard-json-input.json new file mode 100644 index 000000000..18274b1da --- /dev/null +++ b/script/locked-bytecode-dev/UpOFTAdapter.standard-json-input.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/UP/UpOFTAdapter.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { OFTAdapter } from \"@layerzerolabs/oft-evm/contracts/OFTAdapter.sol\";\n\n/**\n * @title UpOFTAdapter\n * @author Superform Foundation\n * @notice OFT Adapter for the UP token on Ethereum mainnet.\n * @dev Locks UP tokens on Ethereum when bridging out, unlocks when bridging in.\n * Deploy this ONLY on Ethereum where the canonical UP token exists.\n */\ncontract UpOFTAdapter is OFTAdapter {\n address public constant UP_TOKEN = 0x1D926bbE67425C9F507b9A0E8030eEdc7880BF33;\n\n error NATIVE_TRANSFER_FAILED();\n error UP_TOKEN_NOT_VALID();\n error ADDRESS_NOT_VALID();\n\n /**\n * @notice Initializes the OFT Adapter with the UP token address and LayerZero endpoint.\n * @param _token The address of the existing UP token (0x1D926bbE67425C9F507b9A0E8030eEdc7880BF33 on Ethereum mainnet)\n * @param _lzEndpoint The LayerZero v2 endpoint address\n * @param _delegate The delegate capable of making OApp configurations (typically the owner)\n */\n constructor(\n address _token,\n address _lzEndpoint,\n address _delegate\n ) OFTAdapter(_token, _lzEndpoint, _delegate) Ownable(_delegate) { \n // Enforce canonical UP token on Ethereum mainnet to prevent misconfiguration\n if (block.chainid == 1 && _token != UP_TOKEN) {\n revert UP_TOKEN_NOT_VALID();\n }\n\n if (_lzEndpoint == address(0) || _lzEndpoint.code.length == 0) {\n revert ADDRESS_NOT_VALID();\n }\n }\n\n function sweepNative(address payable to) external onlyOwner {\n (bool s, ) = to.call{value: address(this).balance}(\"\");\n if(!s) revert NATIVE_TRANSFER_FAILED();\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"lib/devtools/packages/oft-evm/contracts/OFTAdapter.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20Metadata, IERC20 } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IOFT, OFTCore } from \"./OFTCore.sol\";\n\n/**\n * @title OFTAdapter Contract\n * @dev OFTAdapter is a contract that adapts an ERC-20 token to the OFT functionality.\n *\n * @dev For existing ERC20 tokens, this can be used to convert the token to crosschain compatibility.\n * @dev WARNING: ONLY 1 of these should exist for a given global mesh,\n * unless you make a NON-default implementation of OFT and needs to be done very carefully.\n * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.\n * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...\n * a pre/post balance check will need to be done to calculate the amountSentLD/amountReceivedLD.\n */\nabstract contract OFTAdapter is OFTCore {\n using SafeERC20 for IERC20;\n\n IERC20 internal immutable innerToken;\n\n /**\n * @dev Constructor for the OFTAdapter contract.\n * @param _token The address of the ERC-20 token to be adapted.\n * @param _lzEndpoint The LayerZero endpoint address.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n */\n constructor(\n address _token,\n address _lzEndpoint,\n address _delegate\n ) OFTCore(IERC20Metadata(_token).decimals(), _lzEndpoint, _delegate) {\n innerToken = IERC20(_token);\n }\n\n /**\n * @dev Retrieves the address of the underlying ERC20 implementation.\n * @return The address of the adapted ERC-20 token.\n *\n * @dev In the case of OFTAdapter, address(this) and erc20 are NOT the same contract.\n */\n function token() public view returns (address) {\n return address(innerToken);\n }\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev In the case of default OFTAdapter, approval is required.\n * @dev In non-default OFTAdapter contracts with something like mint and burn privileges, it would NOT need approval.\n */\n function approvalRequired() external pure virtual returns (bool) {\n return true;\n }\n\n /**\n * @dev Locks tokens from the sender's specified balance in this contract.\n * @param _from The address to debit from.\n * @param _amountLD The amount of tokens to send in local decimals.\n * @param _minAmountLD The minimum amount to send in local decimals.\n * @param _dstEid The destination chain ID.\n * @return amountSentLD The amount sent in local decimals.\n * @return amountReceivedLD The amount received in local decimals on the remote.\n *\n * @dev msg.sender will need to approve this _amountLD of tokens to be locked inside of the contract.\n * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.\n * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...\n * a pre/post balance check will need to be done to calculate the amountReceivedLD.\n */\n function _debit(\n address _from,\n uint256 _amountLD,\n uint256 _minAmountLD,\n uint32 _dstEid\n ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {\n (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);\n // @dev Lock tokens by moving them into this contract from the caller.\n innerToken.safeTransferFrom(_from, address(this), amountSentLD);\n }\n\n /**\n * @dev Credits tokens to the specified address.\n * @param _to The address to credit the tokens to.\n * @param _amountLD The amount of tokens to credit in local decimals.\n * @dev _srcEid The source chain ID.\n * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.\n *\n * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.\n * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...\n * a pre/post balance check will need to be done to calculate the amountReceivedLD.\n */\n function _credit(\n address _to,\n uint256 _amountLD,\n uint32 /*_srcEid*/\n ) internal virtual override returns (uint256 amountReceivedLD) {\n // @dev Unlock the tokens and transfer to the recipient.\n innerToken.safeTransfer(_to, _amountLD);\n // @dev In the case of NON-default OFTAdapter, the amountLD MIGHT not be == amountReceivedLD.\n return _amountLD;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"},"lib/devtools/packages/oft-evm/contracts/OFTCore.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { OApp, Origin } from \"@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol\";\nimport { OAppOptionsType3 } from \"@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol\";\nimport { IOAppMsgInspector } from \"@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppMsgInspector.sol\";\n\nimport { OAppPreCrimeSimulator } from \"@layerzerolabs/oapp-evm/contracts/precrime/OAppPreCrimeSimulator.sol\";\n\nimport { IOFT, SendParam, OFTLimit, OFTReceipt, OFTFeeDetail, MessagingReceipt, MessagingFee } from \"./interfaces/IOFT.sol\";\nimport { OFTMsgCodec } from \"./libs/OFTMsgCodec.sol\";\nimport { OFTComposeMsgCodec } from \"./libs/OFTComposeMsgCodec.sol\";\n\n/**\n * @title OFTCore\n * @dev Abstract contract for the OftChain (OFT) token.\n */\nabstract contract OFTCore is IOFT, OApp, OAppPreCrimeSimulator, OAppOptionsType3 {\n using OFTMsgCodec for bytes;\n using OFTMsgCodec for bytes32;\n\n // @notice Provides a conversion rate when swapping between denominations of SD and LD\n // - shareDecimals == SD == shared Decimals\n // - localDecimals == LD == local decimals\n // @dev Considers that tokens have different decimal amounts on various chains.\n // @dev eg.\n // For a token\n // - locally with 4 decimals --> 1.2345 => uint(12345)\n // - remotely with 2 decimals --> 1.23 => uint(123)\n // - The conversion rate would be 10 ** (4 - 2) = 100\n // @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote,\n // you can only display 1.23 -> uint(123).\n // @dev To preserve the dust that would otherwise be lost on that conversion,\n // we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh\n uint256 public immutable decimalConversionRate;\n\n // @notice Msg types that are used to identify the various OFT operations.\n // @dev This can be extended in child contracts for non-default oft operations\n // @dev These values are used in things like combineOptions() in OAppOptionsType3.sol.\n uint16 public constant SEND = 1;\n uint16 public constant SEND_AND_CALL = 2;\n\n // Address of an optional contract to inspect both 'message' and 'options'\n address public msgInspector;\n event MsgInspectorSet(address inspector);\n\n /**\n * @dev Constructor.\n * @param _localDecimals The decimals of the token on the local chain (this chain).\n * @param _endpoint The address of the LayerZero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n */\n constructor(uint8 _localDecimals, address _endpoint, address _delegate) OApp(_endpoint, _delegate) {\n if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals();\n decimalConversionRate = 10 ** (_localDecimals - sharedDecimals());\n }\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) {\n return (type(IOFT).interfaceId, 1);\n }\n\n /**\n * @dev Retrieves the shared decimals of the OFT.\n * @return The shared decimals of the OFT.\n *\n * @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap\n * Lowest common decimal denominator between chains.\n * Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).\n * For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.\n * ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615\n */\n function sharedDecimals() public view virtual returns (uint8) {\n return 6;\n }\n\n /**\n * @dev Sets the message inspector address for the OFT.\n * @param _msgInspector The address of the message inspector.\n *\n * @dev This is an optional contract that can be used to inspect both 'message' and 'options'.\n * @dev Set it to address(0) to disable it, or set it to a contract address to enable it.\n */\n function setMsgInspector(address _msgInspector) public virtual onlyOwner {\n msgInspector = _msgInspector;\n emit MsgInspectorSet(_msgInspector);\n }\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return oftLimit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return oftReceipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n )\n external\n view\n virtual\n returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt)\n {\n uint256 minAmountLD = 0; // Unused in the default implementation.\n uint256 maxAmountLD = IERC20(this.token()).totalSupply(); // Unused in the default implementation.\n oftLimit = OFTLimit(minAmountLD, maxAmountLD);\n\n // Unused in the default implementation; reserved for future complex fee details.\n oftFeeDetails = new OFTFeeDetail[](0);\n\n // @dev This is the same as the send() operation, but without the actual send.\n // - amountSentLD is the amount in local decimals that would be sent from the sender.\n // - amountReceivedLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.\n // @dev The amountSentLD MIGHT not equal the amount the user actually receives. HOWEVER, the default does.\n (uint256 amountSentLD, uint256 amountReceivedLD) = _debitView(\n _sendParam.amountLD,\n _sendParam.minAmountLD,\n _sendParam.dstEid\n );\n oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);\n }\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return msgFee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(\n SendParam calldata _sendParam,\n bool _payInLzToken\n ) external view virtual returns (MessagingFee memory msgFee) {\n // @dev mock the amount to receive, this is the same operation used in the send().\n // The quote is as similar as possible to the actual send() operation.\n (, uint256 amountReceivedLD) = _debitView(_sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid);\n\n // @dev Builds the options and OFT message to quote in the endpoint.\n (bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);\n\n // @dev Calculates the LayerZero fee for the send() operation.\n return _quote(_sendParam.dstEid, message, options, _payInLzToken);\n }\n\n /**\n * @dev Executes the send operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The calculated fee for the send() operation.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds.\n * @return msgReceipt The receipt for the send operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {\n return _send(_sendParam, _fee, _refundAddress);\n }\n\n /**\n * @dev Internal function to execute the send operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The calculated fee for the send() operation.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds.\n * @return msgReceipt The receipt for the send operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {\n // @dev Applies the token transfers regarding this send() operation.\n // - amountSentLD is the amount in local decimals that was ACTUALLY sent/debited from the sender.\n // - amountReceivedLD is the amount in local decimals that will be received/credited to the recipient on the remote OFT instance.\n (uint256 amountSentLD, uint256 amountReceivedLD) = _debit(\n msg.sender,\n _sendParam.amountLD,\n _sendParam.minAmountLD,\n _sendParam.dstEid\n );\n\n // @dev Builds the options and OFT message to quote in the endpoint.\n (bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);\n\n // @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.\n msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);\n // @dev Formulate the OFT receipt.\n oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);\n\n emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD);\n }\n\n /**\n * @dev Internal function to build the message and options.\n * @param _sendParam The parameters for the send() operation.\n * @param _amountLD The amount in local decimals.\n * @return message The encoded message.\n * @return options The encoded options.\n */\n function _buildMsgAndOptions(\n SendParam calldata _sendParam,\n uint256 _amountLD\n ) internal view virtual returns (bytes memory message, bytes memory options) {\n bool hasCompose;\n // @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is.\n (message, hasCompose) = OFTMsgCodec.encode(\n _sendParam.to,\n _toSD(_amountLD),\n // @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote.\n // EVEN if you dont require an arbitrary payload to be sent... eg. '0x01'\n _sendParam.composeMsg\n );\n // @dev Change the msg type depending if its composed or not.\n uint16 msgType = hasCompose ? SEND_AND_CALL : SEND;\n // @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3.\n options = combineOptions(_sendParam.dstEid, msgType, _sendParam.extraOptions);\n\n // @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector.\n // @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean\n address inspector = msgInspector; // caches the msgInspector to avoid potential double storage read\n if (inspector != address(0)) IOAppMsgInspector(inspector).inspect(message, options);\n }\n\n /**\n * @dev Internal function to handle the receive on the LayerZero endpoint.\n * @param _origin The origin information.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address from the src chain.\n * - nonce: The nonce of the LayerZero message.\n * @param _guid The unique identifier for the received LayerZero message.\n * @param _message The encoded message.\n * @dev _executor The address of the executor.\n * @dev _extraData Additional data.\n */\n function _lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address /*_executor*/, // @dev unused in the default implementation.\n bytes calldata /*_extraData*/ // @dev unused in the default implementation.\n ) internal virtual override {\n // @dev The src sending chain doesnt know the address length on this chain (potentially non-evm)\n // Thus everything is bytes32() encoded in flight.\n address toAddress = _message.sendTo().bytes32ToAddress();\n // @dev Credit the amountLD to the recipient and return the ACTUAL amount the recipient received in local decimals\n uint256 amountReceivedLD = _credit(toAddress, _toLD(_message.amountSD()), _origin.srcEid);\n\n if (_message.isComposed()) {\n // @dev Proprietary composeMsg format for the OFT.\n bytes memory composeMsg = OFTComposeMsgCodec.encode(\n _origin.nonce,\n _origin.srcEid,\n amountReceivedLD,\n _message.composeMsg()\n );\n\n // @dev Stores the lzCompose payload that will be executed in a separate tx.\n // Standardizes functionality for executing arbitrary contract invocation on some non-evm chains.\n // @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed.\n // @dev The index is used when a OApp needs to compose multiple msgs on lzReceive.\n // For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0.\n endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg);\n }\n\n emit OFTReceived(_guid, _origin.srcEid, toAddress, amountReceivedLD);\n }\n\n /**\n * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.\n * @param _origin The origin information.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address from the src chain.\n * - nonce: The nonce of the LayerZero message.\n * @param _guid The unique identifier for the received LayerZero message.\n * @param _message The LayerZero message.\n * @param _executor The address of the off-chain executor.\n * @param _extraData Arbitrary data passed by the msg executor.\n *\n * @dev Enables the preCrime simulator to mock sending lzReceive() messages,\n * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.\n */\n function _lzReceiveSimulate(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) internal virtual override {\n _lzReceive(_origin, _guid, _message, _executor, _extraData);\n }\n\n /**\n * @dev Check if the peer is considered 'trusted' by the OApp.\n * @param _eid The endpoint ID to check.\n * @param _peer The peer to check.\n * @return Whether the peer passed is considered 'trusted' by the OApp.\n *\n * @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source.\n */\n function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) {\n return peers[_eid] == _peer;\n }\n\n /**\n * @dev Internal function to remove dust from the given local decimal amount.\n * @param _amountLD The amount in local decimals.\n * @return amountLD The amount after removing dust.\n *\n * @dev Prevents the loss of dust when moving amounts between chains with different decimals.\n * @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).\n */\n function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) {\n return (_amountLD / decimalConversionRate) * decimalConversionRate;\n }\n\n /**\n * @dev Internal function to convert an amount from shared decimals into local decimals.\n * @param _amountSD The amount in shared decimals.\n * @return amountLD The amount in local decimals.\n */\n function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) {\n return _amountSD * decimalConversionRate;\n }\n\n /**\n * @dev Internal function to convert an amount from local decimals into shared decimals.\n * @param _amountLD The amount in local decimals.\n * @return amountSD The amount in shared decimals.\n *\n * @dev Reverts if the _amountLD in shared decimals overflows uint64.\n * @dev eg. uint(2**64 + 123) with a conversion rate of 1 wraps around 2**64 to uint(123).\n */\n function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) {\n uint256 _amountSD = _amountLD / decimalConversionRate;\n if (_amountSD > type(uint64).max) revert AmountSDOverflowed(_amountSD);\n return uint64(_amountSD);\n }\n\n /**\n * @dev Internal function to mock the amount mutation from a OFT debit() operation.\n * @param _amountLD The amount to send in local decimals.\n * @param _minAmountLD The minimum amount to send in local decimals.\n * @dev _dstEid The destination endpoint ID.\n * @return amountSentLD The amount sent, in local decimals.\n * @return amountReceivedLD The amount to be received on the remote chain, in local decimals.\n *\n * @dev This is where things like fees would be calculated and deducted from the amount to be received on the remote.\n */\n function _debitView(\n uint256 _amountLD,\n uint256 _minAmountLD,\n uint32 /*_dstEid*/\n ) internal view virtual returns (uint256 amountSentLD, uint256 amountReceivedLD) {\n // @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token.\n amountSentLD = _removeDust(_amountLD);\n // @dev The amount to send is the same as amount received in the default implementation.\n amountReceivedLD = amountSentLD;\n\n // @dev Check for slippage.\n if (amountReceivedLD < _minAmountLD) {\n revert SlippageExceeded(amountReceivedLD, _minAmountLD);\n }\n }\n\n /**\n * @dev Internal function to perform a debit operation.\n * @param _from The address to debit.\n * @param _amountLD The amount to send in local decimals.\n * @param _minAmountLD The minimum amount to send in local decimals.\n * @param _dstEid The destination endpoint ID.\n * @return amountSentLD The amount sent in local decimals.\n * @return amountReceivedLD The amount received in local decimals on the remote.\n *\n * @dev Defined here but are intended to be overriden depending on the OFT implementation.\n * @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.\n */\n function _debit(\n address _from,\n uint256 _amountLD,\n uint256 _minAmountLD,\n uint32 _dstEid\n ) internal virtual returns (uint256 amountSentLD, uint256 amountReceivedLD);\n\n /**\n * @dev Internal function to perform a credit operation.\n * @param _to The address to credit.\n * @param _amountLD The amount to credit in local decimals.\n * @param _srcEid The source endpoint ID.\n * @return amountReceivedLD The amount ACTUALLY received in local decimals.\n *\n * @dev Defined here but are intended to be overriden depending on the OFT implementation.\n * @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.\n */\n function _credit(\n address _to,\n uint256 _amountLD,\n uint32 _srcEid\n ) internal virtual returns (uint256 amountReceivedLD);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OApp.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n// @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers\n// solhint-disable-next-line no-unused-import\nimport { OAppSender, MessagingFee, MessagingReceipt } from \"./OAppSender.sol\";\n// @dev Import the 'Origin' so it's exposed to OApp implementers\n// solhint-disable-next-line no-unused-import\nimport { OAppReceiver, Origin } from \"./OAppReceiver.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OApp\n * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.\n */\nabstract contract OApp is OAppSender, OAppReceiver {\n /**\n * @dev Constructor to initialize the OApp with the provided endpoint and owner.\n * @param _endpoint The address of the LOCAL LayerZero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n */\n constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {}\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol implementation.\n * @return receiverVersion The version of the OAppReceiver.sol implementation.\n */\n function oAppVersion()\n public\n pure\n virtual\n override(OAppSender, OAppReceiver)\n returns (uint64 senderVersion, uint64 receiverVersion)\n {\n return (SENDER_VERSION, RECEIVER_VERSION);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppOptionsType3, EnforcedOptionParam } from \"../interfaces/IOAppOptionsType3.sol\";\n\n/**\n * @title OAppOptionsType3\n * @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options.\n */\nabstract contract OAppOptionsType3 is IOAppOptionsType3, Ownable {\n uint16 internal constant OPTION_TYPE_3 = 3;\n\n // @dev The \"msgType\" should be defined in the child contract.\n mapping(uint32 eid => mapping(uint16 msgType => bytes enforcedOption)) public enforcedOptions;\n\n /**\n * @dev Sets the enforced options for specific endpoint and message type combinations.\n * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.\n * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.\n * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay\n * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().\n */\n function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner {\n _setEnforcedOptions(_enforcedOptions);\n }\n\n /**\n * @dev Sets the enforced options for specific endpoint and message type combinations.\n * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.\n *\n * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.\n * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.\n * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay\n * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().\n */\n function _setEnforcedOptions(EnforcedOptionParam[] memory _enforcedOptions) internal virtual {\n for (uint256 i = 0; i < _enforcedOptions.length; i++) {\n // @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining.\n _assertOptionsType3(_enforcedOptions[i].options);\n enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options;\n }\n\n emit EnforcedOptionSet(_enforcedOptions);\n }\n\n /**\n * @notice Combines options for a given endpoint and message type.\n * @param _eid The endpoint ID.\n * @param _msgType The OAPP message type.\n * @param _extraOptions Additional options passed by the caller.\n * @return options The combination of caller specified options AND enforced options.\n *\n * @dev If there is an enforced lzReceive option:\n * - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether}\n * - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function.\n * @dev This presence of duplicated options is handled off-chain in the verifier/executor.\n */\n function combineOptions(\n uint32 _eid,\n uint16 _msgType,\n bytes calldata _extraOptions\n ) public view virtual returns (bytes memory) {\n bytes memory enforced = enforcedOptions[_eid][_msgType];\n\n // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options.\n if (enforced.length == 0) return _extraOptions;\n\n // No caller options, return enforced\n if (_extraOptions.length == 0) return enforced;\n\n // @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined.\n if (_extraOptions.length >= 2) {\n _assertOptionsType3(_extraOptions);\n // @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced.\n return bytes.concat(enforced, _extraOptions[2:]);\n }\n\n // No valid set of options was found.\n revert InvalidOptions(_extraOptions);\n }\n\n /**\n * @dev Internal function to assert that options are of type 3.\n * @param _options The options to be checked.\n */\n function _assertOptionsType3(bytes memory _options) internal pure virtual {\n uint16 optionsType;\n assembly {\n optionsType := mload(add(_options, 2))\n }\n if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppMsgInspector.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n/**\n * @title IOAppMsgInspector\n * @dev Interface for the OApp Message Inspector, allowing examination of message and options contents.\n */\ninterface IOAppMsgInspector {\n // Custom error message for inspection failure\n error InspectionFailed(bytes message, bytes options);\n\n /**\n * @notice Allows the inspector to examine LayerZero message contents and optionally throw a revert if invalid.\n * @param _message The message payload to be inspected.\n * @param _options Additional options or parameters for inspection.\n * @return valid A boolean indicating whether the inspection passed (true) or failed (false).\n *\n * @dev Optionally done as a revert, OR use the boolean provided to handle the failure.\n */\n function inspect(bytes calldata _message, bytes calldata _options) external view returns (bool valid);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/OAppPreCrimeSimulator.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IPreCrime } from \"./interfaces/IPreCrime.sol\";\nimport { IOAppPreCrimeSimulator, InboundPacket, Origin } from \"./interfaces/IOAppPreCrimeSimulator.sol\";\n\n/**\n * @title OAppPreCrimeSimulator\n * @dev Abstract contract serving as the base for preCrime simulation functionality in an OApp.\n */\nabstract contract OAppPreCrimeSimulator is IOAppPreCrimeSimulator, Ownable {\n // The address of the preCrime implementation.\n address public preCrime;\n\n /**\n * @dev Retrieves the address of the OApp contract.\n * @return The address of the OApp contract.\n *\n * @dev The simulator contract is the base contract for the OApp by default.\n * @dev If the simulator is a separate contract, override this function.\n */\n function oApp() external view virtual returns (address) {\n return address(this);\n }\n\n /**\n * @dev Sets the preCrime contract address.\n * @param _preCrime The address of the preCrime contract.\n */\n function setPreCrime(address _preCrime) public virtual onlyOwner {\n preCrime = _preCrime;\n emit PreCrimeSet(_preCrime);\n }\n\n /**\n * @dev Interface for pre-crime simulations. Always reverts at the end with the simulation results.\n * @param _packets An array of InboundPacket objects representing received packets to be delivered.\n *\n * @dev WARNING: MUST revert at the end with the simulation results.\n * @dev Gives the preCrime implementation the ability to mock sending packets to the lzReceive function,\n * WITHOUT actually executing them.\n */\n function lzReceiveAndRevert(InboundPacket[] calldata _packets) public payable virtual {\n for (uint256 i = 0; i < _packets.length; i++) {\n InboundPacket calldata packet = _packets[i];\n\n // Ignore packets that are not from trusted peers.\n if (!isPeer(packet.origin.srcEid, packet.origin.sender)) continue;\n\n // @dev Because a verifier is calling this function, it doesnt have access to executor params:\n // - address _executor\n // - bytes calldata _extraData\n // preCrime will NOT work for OApps that rely on these two parameters inside of their _lzReceive().\n // They are instead stubbed to default values, address(0) and bytes(\"\")\n // @dev Calling this.lzReceiveSimulate removes ability for assembly return 0 callstack exit,\n // which would cause the revert to be ignored.\n this.lzReceiveSimulate{ value: packet.value }(\n packet.origin,\n packet.guid,\n packet.message,\n packet.executor,\n packet.extraData\n );\n }\n\n // @dev Revert with the simulation results. msg.sender must implement IPreCrime.buildSimulationResult().\n revert SimulationResult(IPreCrime(msg.sender).buildSimulationResult());\n }\n\n /**\n * @dev Is effectively an internal function because msg.sender must be address(this).\n * Allows resetting the call stack for 'internal' calls.\n * @param _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @param _guid The unique identifier of the packet.\n * @param _message The message payload of the packet.\n * @param _executor The executor address for the packet.\n * @param _extraData Additional data for the packet.\n */\n function lzReceiveSimulate(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) external payable virtual {\n // @dev Ensure ONLY can be called 'internally'.\n if (msg.sender != address(this)) revert OnlySelf();\n _lzReceiveSimulate(_origin, _guid, _message, _executor, _extraData);\n }\n\n /**\n * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.\n * @param _origin The origin information.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address from the src chain.\n * - nonce: The nonce of the LayerZero message.\n * @param _guid The GUID of the LayerZero message.\n * @param _message The LayerZero message.\n * @param _executor The address of the off-chain executor.\n * @param _extraData Arbitrary data passed by the msg executor.\n *\n * @dev Enables the preCrime simulator to mock sending lzReceive() messages,\n * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.\n */\n function _lzReceiveSimulate(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) internal virtual;\n\n /**\n * @dev checks if the specified peer is considered 'trusted' by the OApp.\n * @param _eid The endpoint Id to check.\n * @param _peer The peer to check.\n * @return Whether the peer passed is considered 'trusted' by the OApp.\n */\n function isPeer(uint32 _eid, bytes32 _peer) public view virtual returns (bool);\n}\n"},"lib/devtools/packages/oft-evm/contracts/interfaces/IOFT.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { MessagingReceipt, MessagingFee } from \"@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol\";\n\n/**\n * @dev Struct representing token parameters for the OFT send() operation.\n */\nstruct SendParam {\n uint32 dstEid; // Destination endpoint ID.\n bytes32 to; // Recipient address.\n uint256 amountLD; // Amount to send in local decimals.\n uint256 minAmountLD; // Minimum amount to send in local decimals.\n bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.\n bytes composeMsg; // The composed message for the send() operation.\n bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.\n}\n\n/**\n * @dev Struct representing OFT limit information.\n * @dev These amounts can change dynamically and are up the specific oft implementation.\n */\nstruct OFTLimit {\n uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.\n uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.\n}\n\n/**\n * @dev Struct representing OFT receipt information.\n */\nstruct OFTReceipt {\n uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.\n // @dev In non-default implementations, the amountReceivedLD COULD differ from this value.\n uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.\n}\n\n/**\n * @dev Struct representing OFT fee details.\n * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.\n */\nstruct OFTFeeDetail {\n int256 feeAmountLD; // Amount of the fee in local decimals.\n string description; // Description of the fee.\n}\n\n/**\n * @title IOFT\n * @dev Interface for the OftChain (OFT) token.\n * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.\n * @dev This specific interface ID is '0x02e49c2c'.\n */\ninterface IOFT {\n // Custom error messages\n error InvalidLocalDecimals();\n error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);\n error AmountSDOverflowed(uint256 amountSD);\n\n // Events\n event OFTSent(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 dstEid, // Destination Endpoint ID.\n address indexed fromAddress, // Address of the sender on the src chain.\n uint256 amountSentLD, // Amount of tokens sent in local decimals.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n event OFTReceived(\n bytes32 indexed guid, // GUID of the OFT message.\n uint32 srcEid, // Source Endpoint ID.\n address indexed toAddress, // Address of the recipient on the dst chain.\n uint256 amountReceivedLD // Amount of tokens received in local decimals.\n );\n\n /**\n * @notice Retrieves interfaceID and the version of the OFT.\n * @return interfaceId The interface ID.\n * @return version The version.\n *\n * @dev interfaceId: This specific interface ID is '0x02e49c2c'.\n * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.\n * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.\n * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)\n */\n function oftVersion() external view returns (bytes4 interfaceId, uint64 version);\n\n /**\n * @notice Retrieves the address of the token associated with the OFT.\n * @return token The address of the ERC20 token implementation.\n */\n function token() external view returns (address);\n\n /**\n * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.\n * @return requiresApproval Needs approval of the underlying token implementation.\n *\n * @dev Allows things like wallet implementers to determine integration requirements,\n * without understanding the underlying token implementation.\n */\n function approvalRequired() external view returns (bool);\n\n /**\n * @notice Retrieves the shared decimals of the OFT.\n * @return sharedDecimals The shared decimals of the OFT.\n */\n function sharedDecimals() external view returns (uint8);\n\n /**\n * @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.\n * @param _sendParam The parameters for the send operation.\n * @return limit The OFT limit information.\n * @return oftFeeDetails The details of OFT fees.\n * @return receipt The OFT receipt information.\n */\n function quoteOFT(\n SendParam calldata _sendParam\n ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);\n\n /**\n * @notice Provides a quote for the send() operation.\n * @param _sendParam The parameters for the send() operation.\n * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.\n * @return fee The calculated LayerZero messaging fee from the send() operation.\n *\n * @dev MessagingFee: LayerZero msg fee\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n */\n function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);\n\n /**\n * @notice Executes the send() operation.\n * @param _sendParam The parameters for the send operation.\n * @param _fee The fee information supplied by the caller.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess funds from fees etc. on the src.\n * @return receipt The LayerZero messaging receipt from the send() operation.\n * @return oftReceipt The OFT receipt information.\n *\n * @dev MessagingReceipt: LayerZero msg receipt\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function send(\n SendParam calldata _sendParam,\n MessagingFee calldata _fee,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory, OFTReceipt memory);\n}\n"},"lib/devtools/packages/oft-evm/contracts/libs/OFTMsgCodec.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nlibrary OFTMsgCodec {\n // Offset constants for encoding and decoding OFT messages\n uint8 private constant SEND_TO_OFFSET = 32;\n uint8 private constant SEND_AMOUNT_SD_OFFSET = 40;\n\n /**\n * @dev Encodes an OFT LayerZero message.\n * @param _sendTo The recipient address.\n * @param _amountShared The amount in shared decimals.\n * @param _composeMsg The composed message.\n * @return _msg The encoded message.\n * @return hasCompose A boolean indicating whether the message has a composed payload.\n */\n function encode(\n bytes32 _sendTo,\n uint64 _amountShared,\n bytes memory _composeMsg\n ) internal view returns (bytes memory _msg, bool hasCompose) {\n hasCompose = _composeMsg.length > 0;\n // @dev Remote chains will want to know the composed function caller ie. msg.sender on the src.\n _msg = hasCompose\n ? abi.encodePacked(_sendTo, _amountShared, addressToBytes32(msg.sender), _composeMsg)\n : abi.encodePacked(_sendTo, _amountShared);\n }\n\n /**\n * @dev Checks if the OFT message is composed.\n * @param _msg The OFT message.\n * @return A boolean indicating whether the message is composed.\n */\n function isComposed(bytes calldata _msg) internal pure returns (bool) {\n return _msg.length > SEND_AMOUNT_SD_OFFSET;\n }\n\n /**\n * @dev Retrieves the recipient address from the OFT message.\n * @param _msg The OFT message.\n * @return The recipient address.\n */\n function sendTo(bytes calldata _msg) internal pure returns (bytes32) {\n return bytes32(_msg[:SEND_TO_OFFSET]);\n }\n\n /**\n * @dev Retrieves the amount in shared decimals from the OFT message.\n * @param _msg The OFT message.\n * @return The amount in shared decimals.\n */\n function amountSD(bytes calldata _msg) internal pure returns (uint64) {\n return uint64(bytes8(_msg[SEND_TO_OFFSET:SEND_AMOUNT_SD_OFFSET]));\n }\n\n /**\n * @dev Retrieves the composed message from the OFT message.\n * @param _msg The OFT message.\n * @return The composed message.\n */\n function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {\n return _msg[SEND_AMOUNT_SD_OFFSET:];\n }\n\n /**\n * @dev Converts an address to bytes32.\n * @param _addr The address to convert.\n * @return The bytes32 representation of the address.\n */\n function addressToBytes32(address _addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(_addr)));\n }\n\n /**\n * @dev Converts bytes32 to an address.\n * @param _b The bytes32 value to convert.\n * @return The address representation of bytes32.\n */\n function bytes32ToAddress(bytes32 _b) internal pure returns (address) {\n return address(uint160(uint256(_b)));\n }\n}\n"},"lib/devtools/packages/oft-evm/contracts/libs/OFTComposeMsgCodec.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nlibrary OFTComposeMsgCodec {\n // Offset constants for decoding composed messages\n uint8 private constant NONCE_OFFSET = 8;\n uint8 private constant SRC_EID_OFFSET = 12;\n uint8 private constant AMOUNT_LD_OFFSET = 44;\n uint8 private constant COMPOSE_FROM_OFFSET = 76;\n\n /**\n * @dev Encodes a OFT composed message.\n * @param _nonce The nonce value.\n * @param _srcEid The source endpoint ID.\n * @param _amountLD The amount in local decimals.\n * @param _composeMsg The composed message.\n * @return _msg The encoded Composed message.\n */\n function encode(\n uint64 _nonce,\n uint32 _srcEid,\n uint256 _amountLD,\n bytes memory _composeMsg // 0x[composeFrom][composeMsg]\n ) internal pure returns (bytes memory _msg) {\n _msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg);\n }\n\n /**\n * @dev Retrieves the nonce for the composed message.\n * @param _msg The message.\n * @return The nonce value.\n */\n function nonce(bytes calldata _msg) internal pure returns (uint64) {\n return uint64(bytes8(_msg[:NONCE_OFFSET]));\n }\n\n /**\n * @dev Retrieves the source endpoint ID for the composed message.\n * @param _msg The message.\n * @return The source endpoint ID.\n */\n function srcEid(bytes calldata _msg) internal pure returns (uint32) {\n return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET]));\n }\n\n /**\n * @dev Retrieves the amount in local decimals from the composed message.\n * @param _msg The message.\n * @return The amount in local decimals.\n */\n function amountLD(bytes calldata _msg) internal pure returns (uint256) {\n return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET]));\n }\n\n /**\n * @dev Retrieves the composeFrom value from the composed message.\n * @param _msg The message.\n * @return The composeFrom value.\n */\n function composeFrom(bytes calldata _msg) internal pure returns (bytes32) {\n return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]);\n }\n\n /**\n * @dev Retrieves the composed message.\n * @param _msg The message.\n * @return The composed message.\n */\n function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {\n return _msg[COMPOSE_FROM_OFFSET:];\n }\n\n /**\n * @dev Converts an address to bytes32.\n * @param _addr The address to convert.\n * @return The bytes32 representation of the address.\n */\n function addressToBytes32(address _addr) internal pure returns (bytes32) {\n return bytes32(uint256(uint160(_addr)));\n }\n\n /**\n * @dev Converts bytes32 to an address.\n * @param _b The bytes32 value to convert.\n * @return The address representation of bytes32.\n */\n function bytes32ToAddress(bytes32 _b) internal pure returns (address) {\n return address(uint160(uint256(_b)));\n }\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OAppSender.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { MessagingParams, MessagingFee, MessagingReceipt } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppSender\n * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.\n */\nabstract contract OAppSender is OAppCore {\n using SafeERC20 for IERC20;\n\n // Custom error messages\n error NotEnoughNative(uint256 msgValue);\n error LzTokenUnavailable();\n\n // @dev The version of the OAppSender implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant SENDER_VERSION = 1;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.\n * ie. this is a SEND only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (SENDER_VERSION, 0);\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.\n * @return fee The calculated MessagingFee for the message.\n * - nativeFee: The native fee for the message.\n * - lzTokenFee: The LZ token fee for the message.\n */\n function _quote(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n bool _payInLzToken\n ) internal view virtual returns (MessagingFee memory fee) {\n return\n endpoint.quote(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),\n address(this)\n );\n }\n\n /**\n * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.\n * @param _dstEid The destination endpoint ID.\n * @param _message The message payload.\n * @param _options Additional options for the message.\n * @param _fee The calculated LayerZero fee for the message.\n * - nativeFee: The native fee.\n * - lzTokenFee: The lzToken fee.\n * @param _refundAddress The address to receive any excess fee values sent to the endpoint.\n * @return receipt The receipt for the sent message.\n * - guid: The unique identifier for the sent message.\n * - nonce: The nonce of the sent message.\n * - fee: The LayerZero fee incurred for the message.\n */\n function _lzSend(\n uint32 _dstEid,\n bytes memory _message,\n bytes memory _options,\n MessagingFee memory _fee,\n address _refundAddress\n ) internal virtual returns (MessagingReceipt memory receipt) {\n // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.\n uint256 messageValue = _payNative(_fee.nativeFee);\n if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);\n\n return\n // solhint-disable-next-line check-send-result\n endpoint.send{ value: messageValue }(\n MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),\n _refundAddress\n );\n }\n\n /**\n * @dev Internal function to pay the native fee associated with the message.\n * @param _nativeFee The native fee to be paid.\n * @return nativeFee The amount of native currency paid.\n *\n * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,\n * this will need to be overridden because msg.value would contain multiple lzFees.\n * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.\n * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.\n * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.\n */\n function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {\n if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);\n return _nativeFee;\n }\n\n /**\n * @dev Internal function to pay the LZ token fee associated with the message.\n * @param _lzTokenFee The LZ token fee to be paid.\n *\n * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.\n * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().\n */\n function _payLzToken(uint256 _lzTokenFee) internal virtual {\n // @dev Cannot cache the token because it is not immutable in the endpoint.\n address lzToken = endpoint.lzToken();\n if (lzToken == address(0)) revert LzTokenUnavailable();\n\n // Pay LZ token fee by sending tokens to the endpoint.\n IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OAppReceiver.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IOAppReceiver, Origin } from \"./interfaces/IOAppReceiver.sol\";\nimport { OAppCore } from \"./OAppCore.sol\";\n\n/**\n * @title OAppReceiver\n * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.\n */\nabstract contract OAppReceiver is IOAppReceiver, OAppCore {\n // Custom error message for when the caller is not the registered endpoint/\n error OnlyEndpoint(address addr);\n\n // @dev The version of the OAppReceiver implementation.\n // @dev Version is bumped when changes are made to this contract.\n uint64 internal constant RECEIVER_VERSION = 2;\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n *\n * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.\n * ie. this is a RECEIVE only OApp.\n * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.\n */\n function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {\n return (0, RECEIVER_VERSION);\n }\n\n /**\n * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.\n * @dev _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @dev _message The lzReceive payload.\n * @param _sender The sender address.\n * @return isSender Is a valid sender.\n *\n * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer.\n * @dev The default sender IS the OAppReceiver implementer.\n */\n function isComposeMsgSender(\n Origin calldata /*_origin*/,\n bytes calldata /*_message*/,\n address _sender\n ) public view virtual returns (bool) {\n return _sender == address(this);\n }\n\n /**\n * @notice Checks if the path initialization is allowed based on the provided origin.\n * @param origin The origin information containing the source endpoint and sender address.\n * @return Whether the path has been initialized.\n *\n * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.\n * @dev This defaults to assuming if a peer has been set, its initialized.\n * Can be overridden by the OApp if there is other logic to determine this.\n */\n function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {\n return peers[origin.srcEid] == origin.sender;\n }\n\n /**\n * @notice Retrieves the next nonce for a given source endpoint and sender address.\n * @dev _srcEid The source endpoint ID.\n * @dev _sender The sender address.\n * @return nonce The next nonce.\n *\n * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.\n * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.\n * @dev This is also enforced by the OApp.\n * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.\n */\n function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {\n return 0;\n }\n\n /**\n * @dev Entry point for receiving messages or packets from the endpoint.\n * @param _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @param _guid The unique identifier for the received LayerZero message.\n * @param _message The payload of the received message.\n * @param _executor The address of the executor for the received message.\n * @param _extraData Additional arbitrary data provided by the corresponding executor.\n *\n * @dev Entry point for receiving msg/packet from the LayerZero endpoint.\n */\n function lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) public payable virtual {\n // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.\n if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);\n\n // Ensure that the sender matches the expected peer for the source endpoint.\n if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);\n\n // Call the internal OApp implementation of lzReceive.\n _lzReceive(_origin, _guid, _message, _executor, _extraData);\n }\n\n /**\n * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.\n */\n function _lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) internal virtual;\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/OAppCore.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { IOAppCore, ILayerZeroEndpointV2 } from \"./interfaces/IOAppCore.sol\";\n\n/**\n * @title OAppCore\n * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.\n */\nabstract contract OAppCore is IOAppCore, Ownable {\n // The LayerZero endpoint associated with the given OApp\n ILayerZeroEndpointV2 public immutable endpoint;\n\n // Mapping to store peers associated with corresponding endpoints\n mapping(uint32 eid => bytes32 peer) public peers;\n\n /**\n * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.\n * @param _endpoint The address of the LOCAL Layer Zero endpoint.\n * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.\n *\n * @dev The delegate typically should be set as the owner of the contract.\n */\n constructor(address _endpoint, address _delegate) {\n endpoint = ILayerZeroEndpointV2(_endpoint);\n\n if (_delegate == address(0)) revert InvalidDelegate();\n endpoint.setDelegate(_delegate);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {\n _setPeer(_eid, _peer);\n }\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n *\n * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.\n * @dev Set this to bytes32(0) to remove the peer address.\n * @dev Peer is a bytes32 to accommodate non-evm chains.\n */\n function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {\n peers[_eid] = _peer;\n emit PeerSet(_eid, _peer);\n }\n\n /**\n * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.\n * ie. the peer is set to bytes32(0).\n * @param _eid The endpoint ID.\n * @return peer The address of the peer associated with the specified endpoint.\n */\n function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {\n bytes32 peer = peers[_eid];\n if (peer == bytes32(0)) revert NoPeer(_eid);\n return peer;\n }\n\n /**\n * @notice Sets the delegate address for the OApp.\n * @param _delegate The address of the delegate to be set.\n *\n * @dev Only the owner/admin of the OApp can call this function.\n * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.\n */\n function setDelegate(address _delegate) public onlyOwner {\n endpoint.setDelegate(_delegate);\n }\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppOptionsType3.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Struct representing enforced option parameters.\n */\nstruct EnforcedOptionParam {\n uint32 eid; // Endpoint ID\n uint16 msgType; // Message Type\n bytes options; // Additional options\n}\n\n/**\n * @title IOAppOptionsType3\n * @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options.\n */\ninterface IOAppOptionsType3 {\n // Custom error message for invalid options\n error InvalidOptions(bytes options);\n\n // Event emitted when enforced options are set\n event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions);\n\n /**\n * @notice Sets enforced options for specific endpoint and message type combinations.\n * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.\n */\n function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external;\n\n /**\n * @notice Combines options for a given endpoint and message type.\n * @param _eid The endpoint ID.\n * @param _msgType The OApp message type.\n * @param _extraOptions Additional options passed by the caller.\n * @return options The combination of caller specified options AND enforced options.\n */\n function combineOptions(\n uint32 _eid,\n uint16 _msgType,\n bytes calldata _extraOptions\n ) external view returns (bytes memory options);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/interfaces/IPreCrime.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\nstruct PreCrimePeer {\n uint32 eid;\n bytes32 preCrime;\n bytes32 oApp;\n}\n\n// TODO not done yet\ninterface IPreCrime {\n error OnlyOffChain();\n\n // for simulate()\n error PacketOversize(uint256 max, uint256 actual);\n error PacketUnsorted();\n error SimulationFailed(bytes reason);\n\n // for preCrime()\n error SimulationResultNotFound(uint32 eid);\n error InvalidSimulationResult(uint32 eid, bytes reason);\n error CrimeFound(bytes crime);\n\n function getConfig(bytes[] calldata _packets, uint256[] calldata _packetMsgValues) external returns (bytes memory);\n\n function simulate(\n bytes[] calldata _packets,\n uint256[] calldata _packetMsgValues\n ) external payable returns (bytes memory);\n\n function buildSimulationResult() external view returns (bytes memory);\n\n function preCrime(\n bytes[] calldata _packets,\n uint256[] calldata _packetMsgValues,\n bytes[] calldata _simulations\n ) external;\n\n function version() external view returns (uint64 major, uint8 minor);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\n// @dev Import the Origin so it's exposed to OAppPreCrimeSimulator implementers.\n// solhint-disable-next-line no-unused-import\nimport { InboundPacket, Origin } from \"../libs/Packet.sol\";\n\n/**\n * @title IOAppPreCrimeSimulator Interface\n * @dev Interface for the preCrime simulation functionality in an OApp.\n */\ninterface IOAppPreCrimeSimulator {\n // @dev simulation result used in PreCrime implementation\n error SimulationResult(bytes result);\n error OnlySelf();\n\n /**\n * @dev Emitted when the preCrime contract address is set.\n * @param preCrimeAddress The address of the preCrime contract.\n */\n event PreCrimeSet(address preCrimeAddress);\n\n /**\n * @dev Retrieves the address of the preCrime contract implementation.\n * @return The address of the preCrime contract.\n */\n function preCrime() external view returns (address);\n\n /**\n * @dev Retrieves the address of the OApp contract.\n * @return The address of the OApp contract.\n */\n function oApp() external view returns (address);\n\n /**\n * @dev Sets the preCrime contract address.\n * @param _preCrime The address of the preCrime contract.\n */\n function setPreCrime(address _preCrime) external;\n\n /**\n * @dev Mocks receiving a packet, then reverts with a series of data to infer the state/result.\n * @param _packets An array of LayerZero InboundPacket objects representing received packets.\n */\n function lzReceiveAndRevert(InboundPacket[] calldata _packets) external payable;\n\n /**\n * @dev checks if the specified peer is considered 'trusted' by the OApp.\n * @param _eid The endpoint Id to check.\n * @param _peer The peer to check.\n * @return Whether the peer passed is considered 'trusted' by the OApp.\n */\n function isPeer(uint32 _eid, bytes32 _peer) external view returns (bool);\n}\n"},"lib/v2-core/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IMessageLibManager } from \"./IMessageLibManager.sol\";\nimport { IMessagingComposer } from \"./IMessagingComposer.sol\";\nimport { IMessagingChannel } from \"./IMessagingChannel.sol\";\nimport { IMessagingContext } from \"./IMessagingContext.sol\";\n\nstruct MessagingParams {\n uint32 dstEid;\n bytes32 receiver;\n bytes message;\n bytes options;\n bool payInLzToken;\n}\n\nstruct MessagingReceipt {\n bytes32 guid;\n uint64 nonce;\n MessagingFee fee;\n}\n\nstruct MessagingFee {\n uint256 nativeFee;\n uint256 lzTokenFee;\n}\n\nstruct Origin {\n uint32 srcEid;\n bytes32 sender;\n uint64 nonce;\n}\n\ninterface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {\n event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);\n\n event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);\n\n event PacketDelivered(Origin origin, address receiver);\n\n event LzReceiveAlert(\n address indexed receiver,\n address indexed executor,\n Origin origin,\n bytes32 guid,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n event LzTokenSet(address token);\n\n event DelegateSet(address sender, address delegate);\n\n function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);\n\n function send(\n MessagingParams calldata _params,\n address _refundAddress\n ) external payable returns (MessagingReceipt memory);\n\n function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;\n\n function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function initializable(Origin calldata _origin, address _receiver) external view returns (bool);\n\n function lzReceive(\n Origin calldata _origin,\n address _receiver,\n bytes32 _guid,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n\n // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order\n function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;\n\n function setLzToken(address _lzToken) external;\n\n function lzToken() external view returns (address);\n\n function nativeToken() external view returns (address);\n\n function setDelegate(address _delegate) external;\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppReceiver.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport { ILayerZeroReceiver, Origin } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol\";\n\ninterface IOAppReceiver is ILayerZeroReceiver {\n /**\n * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.\n * @param _origin The origin information containing the source endpoint and sender address.\n * - srcEid: The source chain endpoint ID.\n * - sender: The sender address on the src chain.\n * - nonce: The nonce of the message.\n * @param _message The lzReceive payload.\n * @param _sender The sender address.\n * @return isSender Is a valid sender.\n *\n * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.\n * @dev The default sender IS the OAppReceiver implementer.\n */\n function isComposeMsgSender(\n Origin calldata _origin,\n bytes calldata _message,\n address _sender\n ) external view returns (bool isSender);\n}\n"},"lib/devtools/packages/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ILayerZeroEndpointV2 } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\n\n/**\n * @title IOAppCore\n */\ninterface IOAppCore {\n // Custom error messages\n error OnlyPeer(uint32 eid, bytes32 sender);\n error NoPeer(uint32 eid);\n error InvalidEndpointCall();\n error InvalidDelegate();\n\n // Event emitted when a peer (OApp) is set for a corresponding endpoint\n event PeerSet(uint32 eid, bytes32 peer);\n\n /**\n * @notice Retrieves the OApp version information.\n * @return senderVersion The version of the OAppSender.sol contract.\n * @return receiverVersion The version of the OAppReceiver.sol contract.\n */\n function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);\n\n /**\n * @notice Retrieves the LayerZero endpoint associated with the OApp.\n * @return iEndpoint The LayerZero endpoint as an interface.\n */\n function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);\n\n /**\n * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @return peer The peer address (OApp instance) associated with the corresponding endpoint.\n */\n function peers(uint32 _eid) external view returns (bytes32 peer);\n\n /**\n * @notice Sets the peer address (OApp instance) for a corresponding endpoint.\n * @param _eid The endpoint ID.\n * @param _peer The address of the peer to be associated with the corresponding endpoint.\n */\n function setPeer(uint32 _eid, bytes32 _peer) external;\n\n /**\n * @notice Sets the delegate address for the OApp Core.\n * @param _delegate The address of the delegate to be set.\n */\n function setDelegate(address _delegate) external;\n}\n"},"lib/devtools/packages/oapp-evm/contracts/precrime/libs/Packet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Origin } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol\";\nimport { PacketV1Codec } from \"@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol\";\n\n/**\n * @title InboundPacket\n * @dev Structure representing an inbound packet received by the contract.\n */\nstruct InboundPacket {\n Origin origin; // Origin information of the packet.\n uint32 dstEid; // Destination endpointId of the packet.\n address receiver; // Receiver address for the packet.\n bytes32 guid; // Unique identifier of the packet.\n uint256 value; // msg.value of the packet.\n address executor; // Executor address for the packet.\n bytes message; // Message payload of the packet.\n bytes extraData; // Additional arbitrary data for the packet.\n}\n\n/**\n * @title PacketDecoder\n * @dev Library for decoding LayerZero packets.\n */\nlibrary PacketDecoder {\n using PacketV1Codec for bytes;\n\n /**\n * @dev Decode an inbound packet from the given packet data.\n * @param _packet The packet data to decode.\n * @return packet An InboundPacket struct representing the decoded packet.\n */\n function decode(bytes calldata _packet) internal pure returns (InboundPacket memory packet) {\n packet.origin = Origin(_packet.srcEid(), _packet.sender(), _packet.nonce());\n packet.dstEid = _packet.dstEid();\n packet.receiver = _packet.receiverB20();\n packet.guid = _packet.guid();\n packet.message = _packet.message();\n }\n\n /**\n * @dev Decode multiple inbound packets from the given packet data and associated message values.\n * @param _packets An array of packet data to decode.\n * @param _packetMsgValues An array of associated message values for each packet.\n * @return packets An array of InboundPacket structs representing the decoded packets.\n */\n function decode(\n bytes[] calldata _packets,\n uint256[] memory _packetMsgValues\n ) internal pure returns (InboundPacket[] memory packets) {\n packets = new InboundPacket[](_packets.length);\n for (uint256 i = 0; i < _packets.length; i++) {\n bytes calldata packet = _packets[i];\n packets[i] = PacketDecoder.decode(packet);\n // @dev Allows the verifier to specify the msg.value that gets passed in lzReceive.\n packets[i].value = _packetMsgValues[i];\n }\n }\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessageLibManager.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nstruct SetConfigParam {\n uint32 eid;\n uint32 configType;\n bytes config;\n}\n\ninterface IMessageLibManager {\n struct Timeout {\n address lib;\n uint256 expiry;\n }\n\n event LibraryRegistered(address newLib);\n event DefaultSendLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibrarySet(uint32 eid, address newLib);\n event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);\n event SendLibrarySet(address sender, uint32 eid, address newLib);\n event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);\n event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);\n\n function registerLibrary(address _lib) external;\n\n function isRegisteredLibrary(address _lib) external view returns (bool);\n\n function getRegisteredLibraries() external view returns (address[] memory);\n\n function setDefaultSendLibrary(uint32 _eid, address _newLib) external;\n\n function defaultSendLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _timeout) external;\n\n function defaultReceiveLibrary(uint32 _eid) external view returns (address);\n\n function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;\n\n function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);\n\n /// ------------------- OApp interfaces -------------------\n function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;\n\n function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);\n\n function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);\n\n function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;\n\n function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);\n\n function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _gracePeriod) external;\n\n function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);\n\n function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;\n\n function getConfig(\n address _oapp,\n address _lib,\n uint32 _eid,\n uint32 _configType\n ) external view returns (bytes memory config);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessagingComposer.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingComposer {\n event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);\n event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);\n event LzComposeAlert(\n address indexed from,\n address indexed to,\n address indexed executor,\n bytes32 guid,\n uint16 index,\n uint256 gas,\n uint256 value,\n bytes message,\n bytes extraData,\n bytes reason\n );\n\n function composeQueue(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index\n ) external view returns (bytes32 messageHash);\n\n function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;\n\n function lzCompose(\n address _from,\n address _to,\n bytes32 _guid,\n uint16 _index,\n bytes calldata _message,\n bytes calldata _extraData\n ) external payable;\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessagingChannel.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingChannel {\n event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);\n event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);\n\n function eid() external view returns (uint32);\n\n // this is an emergency function if a message cannot be verified for some reasons\n // required to provide _nextNonce to avoid race condition\n function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;\n\n function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;\n\n function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);\n\n function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n\n function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);\n\n function inboundPayloadHash(\n address _receiver,\n uint32 _srcEid,\n bytes32 _sender,\n uint64 _nonce\n ) external view returns (bytes32);\n\n function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessagingContext.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\ninterface IMessagingContext {\n function isSendingMessage() external view returns (bool);\n\n function getSendContext() external view returns (uint32 dstEid, address sender);\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/ILayerZeroReceiver.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { Origin } from \"./ILayerZeroEndpointV2.sol\";\n\ninterface ILayerZeroReceiver {\n function allowInitializePath(Origin calldata _origin) external view returns (bool);\n\n function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64);\n\n function lzReceive(\n Origin calldata _origin,\n bytes32 _guid,\n bytes calldata _message,\n address _executor,\n bytes calldata _extraData\n ) external payable;\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/messagelib/libs/PacketV1Codec.sol":{"content":"// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nimport { Packet } from \"../../interfaces/ISendLib.sol\";\nimport { AddressCast } from \"../../libs/AddressCast.sol\";\n\nlibrary PacketV1Codec {\n using AddressCast for address;\n using AddressCast for bytes32;\n\n uint8 internal constant PACKET_VERSION = 1;\n\n // header (version + nonce + path)\n // version\n uint256 private constant PACKET_VERSION_OFFSET = 0;\n // nonce\n uint256 private constant NONCE_OFFSET = 1;\n // path\n uint256 private constant SRC_EID_OFFSET = 9;\n uint256 private constant SENDER_OFFSET = 13;\n uint256 private constant DST_EID_OFFSET = 45;\n uint256 private constant RECEIVER_OFFSET = 49;\n // payload (guid + message)\n uint256 private constant GUID_OFFSET = 81; // keccak256(nonce + path)\n uint256 private constant MESSAGE_OFFSET = 113;\n\n function encode(Packet memory _packet) internal pure returns (bytes memory encodedPacket) {\n encodedPacket = abi.encodePacked(\n PACKET_VERSION,\n _packet.nonce,\n _packet.srcEid,\n _packet.sender.toBytes32(),\n _packet.dstEid,\n _packet.receiver,\n _packet.guid,\n _packet.message\n );\n }\n\n function encodePacketHeader(Packet memory _packet) internal pure returns (bytes memory) {\n return\n abi.encodePacked(\n PACKET_VERSION,\n _packet.nonce,\n _packet.srcEid,\n _packet.sender.toBytes32(),\n _packet.dstEid,\n _packet.receiver\n );\n }\n\n function encodePayload(Packet memory _packet) internal pure returns (bytes memory) {\n return abi.encodePacked(_packet.guid, _packet.message);\n }\n\n function header(bytes calldata _packet) internal pure returns (bytes calldata) {\n return _packet[0:GUID_OFFSET];\n }\n\n function version(bytes calldata _packet) internal pure returns (uint8) {\n return uint8(bytes1(_packet[PACKET_VERSION_OFFSET:NONCE_OFFSET]));\n }\n\n function nonce(bytes calldata _packet) internal pure returns (uint64) {\n return uint64(bytes8(_packet[NONCE_OFFSET:SRC_EID_OFFSET]));\n }\n\n function srcEid(bytes calldata _packet) internal pure returns (uint32) {\n return uint32(bytes4(_packet[SRC_EID_OFFSET:SENDER_OFFSET]));\n }\n\n function sender(bytes calldata _packet) internal pure returns (bytes32) {\n return bytes32(_packet[SENDER_OFFSET:DST_EID_OFFSET]);\n }\n\n function senderAddressB20(bytes calldata _packet) internal pure returns (address) {\n return sender(_packet).toAddress();\n }\n\n function dstEid(bytes calldata _packet) internal pure returns (uint32) {\n return uint32(bytes4(_packet[DST_EID_OFFSET:RECEIVER_OFFSET]));\n }\n\n function receiver(bytes calldata _packet) internal pure returns (bytes32) {\n return bytes32(_packet[RECEIVER_OFFSET:GUID_OFFSET]);\n }\n\n function receiverB20(bytes calldata _packet) internal pure returns (address) {\n return receiver(_packet).toAddress();\n }\n\n function guid(bytes calldata _packet) internal pure returns (bytes32) {\n return bytes32(_packet[GUID_OFFSET:MESSAGE_OFFSET]);\n }\n\n function message(bytes calldata _packet) internal pure returns (bytes calldata) {\n return bytes(_packet[MESSAGE_OFFSET:]);\n }\n\n function payload(bytes calldata _packet) internal pure returns (bytes calldata) {\n return bytes(_packet[GUID_OFFSET:]);\n }\n\n function payloadHash(bytes calldata _packet) internal pure returns (bytes32) {\n return keccak256(payload(_packet));\n }\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/ISendLib.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { MessagingFee } from \"./ILayerZeroEndpointV2.sol\";\nimport { IMessageLib } from \"./IMessageLib.sol\";\n\nstruct Packet {\n uint64 nonce;\n uint32 srcEid;\n address sender;\n uint32 dstEid;\n bytes32 receiver;\n bytes32 guid;\n bytes message;\n}\n\ninterface ISendLib is IMessageLib {\n function send(\n Packet calldata _packet,\n bytes calldata _options,\n bool _payInLzToken\n ) external returns (MessagingFee memory, bytes memory encodedPacket);\n\n function quote(\n Packet calldata _packet,\n bytes calldata _options,\n bool _payInLzToken\n ) external view returns (MessagingFee memory);\n\n function setTreasury(address _treasury) external;\n\n function withdrawFee(address _to, uint256 _amount) external;\n\n function withdrawLzTokenFee(address _lzToken, address _to, uint256 _amount) external;\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/libs/AddressCast.sol":{"content":"// SPDX-License-Identifier: LZBL-1.2\n\npragma solidity ^0.8.20;\n\nlibrary AddressCast {\n error AddressCast_InvalidSizeForAddress();\n error AddressCast_InvalidAddress();\n\n function toBytes32(bytes calldata _addressBytes) internal pure returns (bytes32 result) {\n if (_addressBytes.length > 32) revert AddressCast_InvalidAddress();\n result = bytes32(_addressBytes);\n unchecked {\n uint256 offset = 32 - _addressBytes.length;\n result = result >> (offset * 8);\n }\n }\n\n function toBytes32(address _address) internal pure returns (bytes32 result) {\n result = bytes32(uint256(uint160(_address)));\n }\n\n function toBytes(bytes32 _addressBytes32, uint256 _size) internal pure returns (bytes memory result) {\n if (_size == 0 || _size > 32) revert AddressCast_InvalidSizeForAddress();\n result = new bytes(_size);\n unchecked {\n uint256 offset = 256 - _size * 8;\n assembly {\n mstore(add(result, 32), shl(offset, _addressBytes32))\n }\n }\n }\n\n function toAddress(bytes32 _addressBytes32) internal pure returns (address result) {\n result = address(uint160(uint256(_addressBytes32)));\n }\n\n function toAddress(bytes calldata _addressBytes) internal pure returns (address result) {\n if (_addressBytes.length != 20) revert AddressCast_InvalidAddress();\n result = address(bytes20(_addressBytes));\n }\n}\n"},"lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/contracts/interfaces/IMessageLib.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\nimport { SetConfigParam } from \"./IMessageLibManager.sol\";\n\nenum MessageLibType {\n Send,\n Receive,\n SendAndReceive\n}\n\ninterface IMessageLib is IERC165 {\n function setConfig(address _oapp, SetConfigParam[] calldata _config) external;\n\n function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view returns (bytes memory config);\n\n function isSupportedEid(uint32 _eid) external view returns (bool);\n\n // message libs of same major version are compatible\n function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion);\n\n function messageLibType() external view returns (MessageLibType);\n}\n"}},"settings":{"remappings":["@superform-v2-core/=lib/v2-core/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@chimera/=lib/setup-helpers/lib/chimera/src/","@recon/=lib/setup-helpers/src/","excessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","modulekit/=lib/v2-core/lib/modulekit/src/","@prb/math/=lib/v2-core/lib/modulekit/node_modules/@prb/math/src/","@solady/=lib/v2-core/lib/solady/","@account-abstraction/=lib/v2-core/lib/modulekit/node_modules/account-abstraction/contracts/","@ERC4337/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/","@pigeon/=lib/v2-core/lib/pigeon/src/","@surl/=lib/v2-core/lib/surl/src/","@stringutils/=lib/v2-core/lib/solidity-stringutils/src/","@pendle/=lib/v2-core/lib/pendle-core-v2-public/contracts/","@safe/=lib/v2-core/lib/safe-smart-account/contracts/","@safe7579/=lib/v2-core/lib/safe7579/src/","@nexus/=lib/v2-core/lib/nexus/contracts/","@properties-7540/=lib/erc7540-reusable-properties/src/","sentinellist/=lib/v2-core/lib/nexus/node_modules/sentinellist/src/","solady/=lib/v2-core/lib/solady/src/","solarray/=lib/v2-core/lib/nexus/node_modules/solarray/src/","account-abstraction/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction/contracts/","account-abstraction-v0.6/=lib/v2-core/lib/modulekit/node_modules/@ERC4337/account-abstraction-v0.6/contracts/","excessively-safe-call/=lib/v2-core/lib/ExcessivelySafeCall/src/","composability/=lib/v2-core/lib/nexus/node_modules/@biconomy/composability/contracts/","erc7739Validator/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/src/","test/mock_fiattoken/=lib/v2-core/lib/evm-gateway-contracts/test/mock_fiattoken/","@rhinestone/erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/","erc4337-validation/=lib/v2-core/lib/modulekit/node_modules/@rhinestone/erc4337-validation/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/","@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/","@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/protocol/","@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/packages/layerzero-v2/evm/messagelib/","solidity-bytes-utils/=lib/solidity-bytes-utils/","@biconomy/=lib/v2-core/lib/nexus/node_modules/@biconomy/","@ensdomains/=lib/v2-core/lib/v4-core/node_modules/@ensdomains/","@erc7579/=lib/v2-core/lib/nexus/node_modules/@erc7579/","@gnosis.pm/=lib/v2-core/lib/nexus/node_modules/@gnosis.pm/","@memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","@safe-global/=lib/v2-core/lib/nexus/node_modules/@safe-global/","@zerodev/=lib/v2-core/lib/nexus/node_modules/@zerodev/","ExcessivelySafeCall/=lib/v2-core/lib/ExcessivelySafeCall/src/","LayerZero-v2/=lib/LayerZero-v2/","chimera/=lib/chimera/src/","devtools/=lib/devtools/packages/toolbox-foundry/src/","ds-test/=lib/v2-core/lib/nexus/node_modules/ds-test/","enumerableset4337/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@erc7579/enumerablemap4337/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","erc7540-reusable-properties/=lib/erc7540-reusable-properties/src/","erc7579/=lib/v2-core/lib/nexus/node_modules/erc7579/","erc7739-validator-base/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/","eth-gas-reporter/=lib/v2-core/lib/nexus/node_modules/eth-gas-reporter/","evm-gateway-contracts/=lib/v2-core/lib/evm-gateway-contracts/","evm-gateway/=lib/v2-core/lib/evm-gateway-contracts/src/","hardhat-deploy/=lib/v2-core/lib/nexus/node_modules/hardhat-deploy/","hardhat/=lib/v2-core/lib/v4-core/node_modules/hardhat/","kernel/=lib/v2-core/lib/nexus/node_modules/erc7739-validator-base/node_modules/@zerodev/kernel/src/","memview-sol/=lib/v2-core/lib/evm-gateway-contracts/lib/memview-sol/contracts/","module-bases/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/module-bases/src/","nexus/=lib/v2-core/lib/nexus/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","pendle-core-v2-public/=lib/v2-core/lib/pendle-core-v2-public/contracts/","pigeon/=lib/v2-core/lib/pigeon/src/","prep/=lib/v2-core/lib/nexus/node_modules/prep/","rhinestone/checknsignatures/=lib/v2-core/lib/safe7579/node_modules/@rhinestone/checknsignatures/","safe-smart-account/=lib/v2-core/lib/safe-smart-account/","safe7579/=lib/v2-core/lib/safe7579/","setup-helpers/=lib/setup-helpers/src/","solidity-stringutils/=lib/v2-core/lib/solidity-stringutils/","solmate/=lib/v2-core/lib/v4-core/lib/solmate/","surl/=lib/v2-core/lib/surl/","v2-core/=lib/v2-core/","v4-core/=lib/v2-core/lib/v4-core/src/","lib/evm-gateway-contracts:src/=lib/v2-core/lib/evm-gateway-contracts/src/","lib/evm-gateway-contracts:test/=lib/v2-core/lib/evm-gateway-contracts/test/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"none","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"prague","viaIR":false,"libraries":{}}} diff --git a/script/output/prod/1/Ethereum-latest.json b/script/output/prod/1/Ethereum-latest.json index 5160b847a..6e12a74d5 100644 --- a/script/output/prod/1/Ethereum-latest.json +++ b/script/output/prod/1/Ethereum-latest.json @@ -8,5 +8,7 @@ "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", - "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B" -} \ No newline at end of file + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" +} diff --git a/script/output/prod/1/UpOFT-latest.json b/script/output/prod/1/UpOFT-latest.json new file mode 100644 index 000000000..4c99f4e64 --- /dev/null +++ b/script/output/prod/1/UpOFT-latest.json @@ -0,0 +1,3 @@ +{ + "UpOFTAdapter": "0x722ff7C0665F4b1823c9C4cFcDF73A43de5865BD" +} \ No newline at end of file diff --git a/script/output/prod/8453/Base-latest.json b/script/output/prod/8453/Base-latest.json index b970decec..f5b29e64a 100644 --- a/script/output/prod/8453/Base-latest.json +++ b/script/output/prod/8453/Base-latest.json @@ -8,5 +8,7 @@ "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", - "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B" -} \ No newline at end of file + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" +} diff --git a/script/output/prod/8453/UpOFT-latest.json b/script/output/prod/8453/UpOFT-latest.json new file mode 100644 index 000000000..c19c0b793 --- /dev/null +++ b/script/output/prod/8453/UpOFT-latest.json @@ -0,0 +1,3 @@ +{ + "UpOFT": "0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B" +} \ No newline at end of file diff --git a/script/output/prod/999/HyperEVM-latest.json b/script/output/prod/999/HyperEVM-latest.json new file mode 100644 index 000000000..ab18acbed --- /dev/null +++ b/script/output/prod/999/HyperEVM-latest.json @@ -0,0 +1,14 @@ +{ + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperOracle": "0x40c72A5667572641Ca428a2DFa8456EBD4623c10", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" +} \ No newline at end of file diff --git a/script/output/prod/999/SuperformGasOracle-latest.json b/script/output/prod/999/SuperformGasOracle-latest.json new file mode 100644 index 000000000..b92a64542 --- /dev/null +++ b/script/output/prod/999/SuperformGasOracle-latest.json @@ -0,0 +1,7 @@ +{ + "address": "0x473b88f017dE39d85a102DA01A35a1b3507eBcFc", + "chainId": 999, + "decimals": 0, + "description": "Superform Fast Gas / Gwei", + "owner": "0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" +} \ No newline at end of file diff --git a/script/output/prod/999/UpOFT-latest.json b/script/output/prod/999/UpOFT-latest.json new file mode 100644 index 000000000..9bc09a435 --- /dev/null +++ b/script/output/prod/999/UpOFT-latest.json @@ -0,0 +1,3 @@ +{ + "UpOFT": "0x642fFC3496AcA19106BAB7A42F1F221a329654fe" +} \ No newline at end of file diff --git a/script/output/prod/historical/latest_2026-01-28T17-37-06Z.json b/script/output/prod/historical/latest_2026-01-28T17-37-06Z.json new file mode 100644 index 000000000..340aaea3b --- /dev/null +++ b/script/output/prod/historical/latest_2026-01-28T17-37-06Z.json @@ -0,0 +1,785 @@ +{ + "networks": { + "Ethereum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x39962bE24192d0d6B6e3a19f332e3c825604d16A", + "AcrossV3Adapter": "0x4dC34c4Eb23973F3551526C2AFE8ffb7f70F0fD7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xe138e0750a1311580A2c842FF10a9824Fc2C5217", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x10E1a5587036E62c19F172DD0259984D81f558c0", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15" + } + }, + "Base": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x8211082177F01eEd24B73491f8eD79eE535BD980", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xED10D4407b7e59B04A40F4E36Df4583c68C5334F", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracleL2": "0xDd004b9F749014cD7bd73dC0818345c66bc641c8", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15" + } + }, + "BNB": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x03c551601e099C62812cBC3d5741ebECe1A58476", + "AcrossV3Adapter": "0x6DAfED46E7250A2653A5d4ed16F793d19B501ff7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA47265CAF50a939dB95eB3237851d467265c20C3", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x3C5fBfBEb5606b5c67A2C6f65BE4A38149f48a90", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Arbitrum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x424d9552825aeE50b0bF34d2Bd8B6f3eEFA46A7f", + "AcrossV3Adapter": "0x4858bD9a13EeEc482d440bF1FcAE2100D37AD315", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x5F3ECd5b9209F718470e42cE50778f64e563A7A7", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xf09106eAA87a5d81DAcFC91F6F564131c57495bE", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Optimism": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x70c371683Cc5aB1eE60Da0aC3C7166E49BFf8336", + "AcrossV3Adapter": "0x946Df68ca1284D02cAe4F634d0f150E7fD88e29D", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xcCe79E3E4c7ADD7a25DfcAfe69d0d78991AcCB96", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xB712038062bBd8b45445Bc4aD7DcE8f829c02154", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Polygon": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xc2FB04Dcd5d2dB4e6d4f67F48604fc554bADa60B", + "AcrossV3Adapter": "0x8D58754A88bD1F1Ccf8dd22860d913e9933463e5", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x034208a8d1D204952db69376B2921A278C00204a", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x77d80BAEFfc379d44b5E5CD86c3968CDa27612aa", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x94A5Aaa604bBf85A6d8983f2959D50e0637Ce6C6", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x96Ac7B20398bC776c6Bf20Fe46749F2955705Cd9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Unichain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xaE9E9C5f15C213b84a366581972425b790c11c2e", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x7F9c924B2FDb19F45903210b54E7615df8E6bB13", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Avalanche": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x2D677F4F2fD22d8271c97D86fA17a580cBeBfe9C", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xB1B5E159C3Be62e72ad1D052F08eE13a94216c81", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Berachain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Sonic": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA357Dd134ccB087401f562be8158969D9e85104f", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x96fFac7BB5cAcEf9244Fe1aA00C167129afd9527", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Gnosis": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Worldchain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + } + }, + "updated_at": "2025-12-19T17:52:40Z" +} diff --git a/script/output/prod/historical/latest_2026-01-29T15-23-09Z.json b/script/output/prod/historical/latest_2026-01-29T15-23-09Z.json new file mode 100644 index 000000000..2ed196d7b --- /dev/null +++ b/script/output/prod/historical/latest_2026-01-29T15-23-09Z.json @@ -0,0 +1,787 @@ +{ + "networks": { + "Ethereum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x39962bE24192d0d6B6e3a19f332e3c825604d16A", + "AcrossV3Adapter": "0x4dC34c4Eb23973F3551526C2AFE8ffb7f70F0fD7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xe138e0750a1311580A2c842FF10a9824Fc2C5217", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x10E1a5587036E62c19F172DD0259984D81f558c0", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0x5BDdD529B8ef20406371c3b864e0a78241d1dE0F" + } + }, + "Base": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x8211082177F01eEd24B73491f8eD79eE535BD980", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xED10D4407b7e59B04A40F4E36Df4583c68C5334F", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracleL2": "0xDd004b9F749014cD7bd73dC0818345c66bc641c8", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0x5BDdD529B8ef20406371c3b864e0a78241d1dE0F" + } + }, + "BNB": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x03c551601e099C62812cBC3d5741ebECe1A58476", + "AcrossV3Adapter": "0x6DAfED46E7250A2653A5d4ed16F793d19B501ff7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA47265CAF50a939dB95eB3237851d467265c20C3", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x3C5fBfBEb5606b5c67A2C6f65BE4A38149f48a90", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Arbitrum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x424d9552825aeE50b0bF34d2Bd8B6f3eEFA46A7f", + "AcrossV3Adapter": "0x4858bD9a13EeEc482d440bF1FcAE2100D37AD315", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x5F3ECd5b9209F718470e42cE50778f64e563A7A7", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xf09106eAA87a5d81DAcFC91F6F564131c57495bE", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Optimism": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x70c371683Cc5aB1eE60Da0aC3C7166E49BFf8336", + "AcrossV3Adapter": "0x946Df68ca1284D02cAe4F634d0f150E7fD88e29D", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xcCe79E3E4c7ADD7a25DfcAfe69d0d78991AcCB96", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xB712038062bBd8b45445Bc4aD7DcE8f829c02154", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Polygon": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xc2FB04Dcd5d2dB4e6d4f67F48604fc554bADa60B", + "AcrossV3Adapter": "0x8D58754A88bD1F1Ccf8dd22860d913e9933463e5", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x034208a8d1D204952db69376B2921A278C00204a", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x77d80BAEFfc379d44b5E5CD86c3968CDa27612aa", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x94A5Aaa604bBf85A6d8983f2959D50e0637Ce6C6", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x96Ac7B20398bC776c6Bf20Fe46749F2955705Cd9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Unichain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xaE9E9C5f15C213b84a366581972425b790c11c2e", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x7F9c924B2FDb19F45903210b54E7615df8E6bB13", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Avalanche": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x2D677F4F2fD22d8271c97D86fA17a580cBeBfe9C", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xB1B5E159C3Be62e72ad1D052F08eE13a94216c81", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Berachain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Sonic": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA357Dd134ccB087401f562be8158969D9e85104f", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x96fFac7BB5cAcEf9244Fe1aA00C167129afd9527", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Gnosis": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Worldchain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + } + }, + "updated_at": "2026-01-28T17:36:54Z" +} diff --git a/script/output/prod/historical/latest_2026-02-17T09-34-24Z.json b/script/output/prod/historical/latest_2026-02-17T09-34-24Z.json new file mode 100644 index 000000000..d337e715b --- /dev/null +++ b/script/output/prod/historical/latest_2026-02-17T09-34-24Z.json @@ -0,0 +1,787 @@ +{ + "networks": { + "Ethereum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x39962bE24192d0d6B6e3a19f332e3c825604d16A", + "AcrossV3Adapter": "0x4dC34c4Eb23973F3551526C2AFE8ffb7f70F0fD7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xe138e0750a1311580A2c842FF10a9824Fc2C5217", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x10E1a5587036E62c19F172DD0259984D81f558c0", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62" + } + }, + "Base": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x8211082177F01eEd24B73491f8eD79eE535BD980", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xED10D4407b7e59B04A40F4E36Df4583c68C5334F", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracleL2": "0xDd004b9F749014cD7bd73dC0818345c66bc641c8", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62" + } + }, + "BNB": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x03c551601e099C62812cBC3d5741ebECe1A58476", + "AcrossV3Adapter": "0x6DAfED46E7250A2653A5d4ed16F793d19B501ff7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA47265CAF50a939dB95eB3237851d467265c20C3", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x3C5fBfBEb5606b5c67A2C6f65BE4A38149f48a90", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Arbitrum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x424d9552825aeE50b0bF34d2Bd8B6f3eEFA46A7f", + "AcrossV3Adapter": "0x4858bD9a13EeEc482d440bF1FcAE2100D37AD315", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x5F3ECd5b9209F718470e42cE50778f64e563A7A7", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xf09106eAA87a5d81DAcFC91F6F564131c57495bE", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Optimism": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x70c371683Cc5aB1eE60Da0aC3C7166E49BFf8336", + "AcrossV3Adapter": "0x946Df68ca1284D02cAe4F634d0f150E7fD88e29D", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xcCe79E3E4c7ADD7a25DfcAfe69d0d78991AcCB96", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xB712038062bBd8b45445Bc4aD7DcE8f829c02154", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Polygon": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xc2FB04Dcd5d2dB4e6d4f67F48604fc554bADa60B", + "AcrossV3Adapter": "0x8D58754A88bD1F1Ccf8dd22860d913e9933463e5", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x034208a8d1D204952db69376B2921A278C00204a", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x77d80BAEFfc379d44b5E5CD86c3968CDa27612aa", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x94A5Aaa604bBf85A6d8983f2959D50e0637Ce6C6", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x96Ac7B20398bC776c6Bf20Fe46749F2955705Cd9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Unichain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xaE9E9C5f15C213b84a366581972425b790c11c2e", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x7F9c924B2FDb19F45903210b54E7615df8E6bB13", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Avalanche": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x2D677F4F2fD22d8271c97D86fA17a580cBeBfe9C", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xB1B5E159C3Be62e72ad1D052F08eE13a94216c81", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Berachain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Sonic": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA357Dd134ccB087401f562be8158969D9e85104f", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x96fFac7BB5cAcEf9244Fe1aA00C167129afd9527", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Gnosis": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Worldchain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + } + }, + "updated_at": "2026-01-29T15:22:53Z" +} diff --git a/script/output/prod/historical/latest_2026-02-17T12-17-59Z.json b/script/output/prod/historical/latest_2026-02-17T12-17-59Z.json new file mode 100644 index 000000000..83bb5f5c3 --- /dev/null +++ b/script/output/prod/historical/latest_2026-02-17T12-17-59Z.json @@ -0,0 +1,875 @@ +{ + "networks": { + "Ethereum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x39962bE24192d0d6B6e3a19f332e3c825604d16A", + "AcrossV3Adapter": "0x4dC34c4Eb23973F3551526C2AFE8ffb7f70F0fD7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xe138e0750a1311580A2c842FF10a9824Fc2C5217", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "RecordPurchasePendlePTAmortizedOracleHook": "0x5023a26bc05266d85F7398C22647fD191e0345A2", + "RecordRedemptionPendlePTAmortizedOracleHook": "0xCA09f3B3441E39aC8B2f474A312c956ce6F749A4", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x98313d15797048F60B1bFd41AE7A2B9877056079", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62" + } + }, + "Base": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x8211082177F01eEd24B73491f8eD79eE535BD980", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "RecordPurchasePendlePTAmortizedOracleHook": "0x5023a26bc05266d85F7398C22647fD191e0345A2", + "RecordRedemptionPendlePTAmortizedOracleHook": "0xCA09f3B3441E39aC8B2f474A312c956ce6F749A4", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x074F9973EBfB050D7abc75a5cB03491d675DA843", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62" + } + }, + "BNB": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x03c551601e099C62812cBC3d5741ebECe1A58476", + "AcrossV3Adapter": "0x6DAfED46E7250A2653A5d4ed16F793d19B501ff7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA47265CAF50a939dB95eB3237851d467265c20C3", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x6AADDD4047E7e9723c3446eb2E538cE88C12A12c", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Arbitrum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x424d9552825aeE50b0bF34d2Bd8B6f3eEFA46A7f", + "AcrossV3Adapter": "0x4858bD9a13EeEc482d440bF1FcAE2100D37AD315", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x5F3ECd5b9209F718470e42cE50778f64e563A7A7", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xCCB88A83190257681BC0925e933A19c7Ca0b6d94", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Optimism": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x70c371683Cc5aB1eE60Da0aC3C7166E49BFf8336", + "AcrossV3Adapter": "0x946Df68ca1284D02cAe4F634d0f150E7fD88e29D", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xcCe79E3E4c7ADD7a25DfcAfe69d0d78991AcCB96", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xF65319b5D299a3B0c29cfAC7579b27845d3461E4", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Polygon": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xc2FB04Dcd5d2dB4e6d4f67F48604fc554bADa60B", + "AcrossV3Adapter": "0x8D58754A88bD1F1Ccf8dd22860d913e9933463e5", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x034208a8d1D204952db69376B2921A278C00204a", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x36B84691d3375fDEC79cA5b3142d0bc908e016cC", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Unichain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xaE9E9C5f15C213b84a366581972425b790c11c2e", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xaB587deCE4E2D5F39bEC2922ED745A97BD2F2a8E", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Avalanche": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x2D677F4F2fD22d8271c97D86fA17a580cBeBfe9C", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x6B9308Ca3bAF94aC3516Df08e0cd83ed1D7c312d", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Berachain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Sonic": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA357Dd134ccB087401f562be8158969D9e85104f", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xF3162BEf5c8f0564a0F7DbC88119BbA453DA58B9", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Gnosis": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Worldchain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "HyperEVM": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x95b43AbEEdd47FA9f74Ff3586900D79D3E43d282", + "AcrossV3Adapter": "0x381D5EA470D13ceb51e5dFDd2A28a03b15d4F054", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x40c72A5667572641Ca428a2DFa8456EBD4623c10", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15" + } + } + }, + "updated_at": "2026-01-09T08:16:18Z" +} diff --git a/script/output/prod/historical/latest_2026-02-18T10-18-23Z.json b/script/output/prod/historical/latest_2026-02-18T10-18-23Z.json new file mode 100644 index 000000000..b882b423b --- /dev/null +++ b/script/output/prod/historical/latest_2026-02-18T10-18-23Z.json @@ -0,0 +1,885 @@ +{ + "networks": { + "Ethereum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x39962bE24192d0d6B6e3a19f332e3c825604d16A", + "AcrossV3Adapter": "0x4dC34c4Eb23973F3551526C2AFE8ffb7f70F0fD7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xe138e0750a1311580A2c842FF10a9824Fc2C5217", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "RecordPurchasePendlePTAmortizedOracleHook": "0x771D4fF615F87eA00488a2dbcb70DF98BDA03FA3", + "RecordRedemptionPendlePTAmortizedOracleHook": "0xCA09f3B3441E39aC8B2f474A312c956ce6F749A4", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x98313d15797048F60B1bFd41AE7A2B9877056079", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" + } + }, + "Base": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x8211082177F01eEd24B73491f8eD79eE535BD980", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "RecordPurchasePendlePTAmortizedOracleHook": "0x771D4fF615F87eA00488a2dbcb70DF98BDA03FA3", + "RecordRedemptionPendlePTAmortizedOracleHook": "0xCA09f3B3441E39aC8B2f474A312c956ce6F749A4", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x074F9973EBfB050D7abc75a5cB03491d675DA843", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracleL2": "0xDd004b9F749014cD7bd73dC0818345c66bc641c8", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" + } + }, + "BNB": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x03c551601e099C62812cBC3d5741ebECe1A58476", + "AcrossV3Adapter": "0x6DAfED46E7250A2653A5d4ed16F793d19B501ff7", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA47265CAF50a939dB95eB3237851d467265c20C3", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x6AADDD4047E7e9723c3446eb2E538cE88C12A12c", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Arbitrum": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x424d9552825aeE50b0bF34d2Bd8B6f3eEFA46A7f", + "AcrossV3Adapter": "0x4858bD9a13EeEc482d440bF1FcAE2100D37AD315", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x5F3ECd5b9209F718470e42cE50778f64e563A7A7", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xCCB88A83190257681BC0925e933A19c7Ca0b6d94", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Optimism": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x70c371683Cc5aB1eE60Da0aC3C7166E49BFf8336", + "AcrossV3Adapter": "0x946Df68ca1284D02cAe4F634d0f150E7fD88e29D", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xcCe79E3E4c7ADD7a25DfcAfe69d0d78991AcCB96", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xF65319b5D299a3B0c29cfAC7579b27845d3461E4", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Polygon": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xc2FB04Dcd5d2dB4e6d4f67F48604fc554bADa60B", + "AcrossV3Adapter": "0x8D58754A88bD1F1Ccf8dd22860d913e9933463e5", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x034208a8d1D204952db69376B2921A278C00204a", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x36B84691d3375fDEC79cA5b3142d0bc908e016cC", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Unichain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xaE9E9C5f15C213b84a366581972425b790c11c2e", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xaB587deCE4E2D5F39bEC2922ED745A97BD2F2a8E", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Avalanche": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0x2D677F4F2fD22d8271c97D86fA17a580cBeBfe9C", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0x6B9308Ca3bAF94aC3516Df08e0cd83ed1D7c312d", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Berachain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Sonic": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveAndSwapOdosV2Hook": "0xA357Dd134ccB087401f562be8158969D9e85104f", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "SwapOdosV2Hook": "0xF3162BEf5c8f0564a0F7DbC88119BbA453DA58B9", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Gnosis": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "Worldchain": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xd724315eEebefe346985E028A7382158390cB892", + "AcrossV3Adapter": "0x59d557E862E11c2Ac55Af11c4E0458f66bAb1BeA", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", + "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", + "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", + "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" + } + }, + "HyperEVM": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x95b43AbEEdd47FA9f74Ff3586900D79D3E43d282", + "AcrossV3Adapter": "0x381D5EA470D13ceb51e5dFDd2A28a03b15d4F054", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x40c72A5667572641Ca428a2DFa8456EBD4623c10", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" + } + } + }, + "updated_at": "2026-02-17T12:17:49Z" +} diff --git a/script/output/prod/latest.json b/script/output/prod/latest.json index 340aaea3b..b882b423b 100644 --- a/script/output/prod/latest.json +++ b/script/output/prod/latest.json @@ -12,7 +12,7 @@ "ApproveAndSwapOdosV2Hook": "0xe138e0750a1311580A2c842FF10a9824Fc2C5217", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -33,17 +33,21 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "RecordPurchasePendlePTAmortizedOracleHook": "0x771D4fF615F87eA00488a2dbcb70DF98BDA03FA3", + "RecordRedemptionPendlePTAmortizedOracleHook": "0xCA09f3B3441E39aC8B2f474A312c956ce6F749A4", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -57,9 +61,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0x10E1a5587036E62c19F172DD0259984D81f558c0", + "SwapOdosV2Hook": "0x98313d15797048F60B1bFd41AE7A2B9877056079", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -73,7 +77,9 @@ "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", "SuperOracle": "0x8943128DbAb4279D561654dEED2930Bb975AA070", - "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15" + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" } }, "Base": { @@ -88,7 +94,7 @@ "ApproveAndSwapOdosV2Hook": "0x8211082177F01eEd24B73491f8eD79eE535BD980", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -109,17 +115,21 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "RecordPurchasePendlePTAmortizedOracleHook": "0x771D4fF615F87eA00488a2dbcb70DF98BDA03FA3", + "RecordRedemptionPendlePTAmortizedOracleHook": "0xCA09f3B3441E39aC8B2f474A312c956ce6F749A4", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -133,9 +143,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0xED10D4407b7e59B04A40F4E36Df4583c68C5334F", + "SwapOdosV2Hook": "0x074F9973EBfB050D7abc75a5cB03491d675DA843", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -149,7 +159,9 @@ "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", "SuperOracleL2": "0xDd004b9F749014cD7bd73dC0818345c66bc641c8", - "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15" + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" } }, "BNB": { @@ -164,7 +176,7 @@ "ApproveAndSwapOdosV2Hook": "0xA47265CAF50a939dB95eB3237851d467265c20C3", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -185,17 +197,19 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -209,9 +223,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0x3C5fBfBEb5606b5c67A2C6f65BE4A38149f48a90", + "SwapOdosV2Hook": "0x6AADDD4047E7e9723c3446eb2E538cE88C12A12c", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -230,7 +244,7 @@ "ApproveAndSwapOdosV2Hook": "0x5F3ECd5b9209F718470e42cE50778f64e563A7A7", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -251,17 +265,19 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -275,9 +291,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0xf09106eAA87a5d81DAcFC91F6F564131c57495bE", + "SwapOdosV2Hook": "0xCCB88A83190257681BC0925e933A19c7Ca0b6d94", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -296,7 +312,7 @@ "ApproveAndSwapOdosV2Hook": "0xcCe79E3E4c7ADD7a25DfcAfe69d0d78991AcCB96", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -317,17 +333,19 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -341,9 +359,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0xB712038062bBd8b45445Bc4aD7DcE8f829c02154", + "SwapOdosV2Hook": "0xF65319b5D299a3B0c29cfAC7579b27845d3461E4", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -362,7 +380,7 @@ "ApproveAndSwapOdosV2Hook": "0x034208a8d1D204952db69376B2921A278C00204a", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x77d80BAEFfc379d44b5E5CD86c3968CDa27612aa", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -383,7 +401,7 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", @@ -392,6 +410,7 @@ "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -405,9 +424,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0x94A5Aaa604bBf85A6d8983f2959D50e0637Ce6C6", + "SwapOdosV2Hook": "0x36B84691d3375fDEC79cA5b3142d0bc908e016cC", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x96Ac7B20398bC776c6Bf20Fe46749F2955705Cd9", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -426,7 +445,7 @@ "ApproveAndSwapOdosV2Hook": "0xaE9E9C5f15C213b84a366581972425b790c11c2e", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -444,7 +463,7 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", @@ -453,6 +472,7 @@ "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -466,9 +486,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0x7F9c924B2FDb19F45903210b54E7615df8E6bB13", + "SwapOdosV2Hook": "0xaB587deCE4E2D5F39bEC2922ED745A97BD2F2a8E", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -485,7 +505,7 @@ "ApproveAndSwapOdosV2Hook": "0x2D677F4F2fD22d8271c97D86fA17a580cBeBfe9C", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -506,7 +526,7 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", @@ -515,6 +535,7 @@ "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -528,9 +549,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0xB1B5E159C3Be62e72ad1D052F08eE13a94216c81", + "SwapOdosV2Hook": "0x6B9308Ca3bAF94aC3516Df08e0cd83ed1D7c312d", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -546,7 +567,7 @@ "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -567,17 +588,19 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -591,7 +614,7 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -608,7 +631,7 @@ "ApproveAndSwapOdosV2Hook": "0xA357Dd134ccB087401f562be8158969D9e85104f", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -629,17 +652,19 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", - "PendleRouterSwapHook": "0xcA003b2bbbb2f9724cA71F8D9411B0De2f34D67E", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -653,9 +678,9 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", - "SwapOdosV2Hook": "0x96fFac7BB5cAcEf9244Fe1aA00C167129afd9527", + "SwapOdosV2Hook": "0xF3162BEf5c8f0564a0F7DbC88119BbA453DA58B9", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -671,7 +696,7 @@ "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -692,7 +717,7 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", @@ -701,6 +726,7 @@ "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -715,7 +741,7 @@ "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "Swap1InchHook": "0x1303d5f3e3D9e4a81945cB0C2e309E1940d2425C", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", @@ -733,7 +759,7 @@ "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", - "BatchTransferHook": "0x852c6E00A7eC7590318DEAaD03030d4ddD74C93a", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", @@ -751,7 +777,7 @@ "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", - "MerklClaimRewardHook": "0x82eD9Cb03E4509281B08071fcA44c59E9F7a82d0", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", @@ -760,6 +786,7 @@ "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", @@ -773,13 +800,86 @@ "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", - "TransferHook": "0x8800Ec593a281544Ffb1cef9528fF2Bbb61f871c", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", "NexusProxy": "0x8a3A6698C3D142b9dAD80F114947d46671A5290E", "Nexus": "0xA3AA31f8d4Da6005aAfB0d61e5012a64d15F5B3A", "NexusBootstrap": "0x5eBeb4d51723bA345080D81bBF178D93E84bC9BE", "NexusAccountFactory": "0x4153Db38136E74a88A77b51a955A88823820C050" } + }, + "HyperEVM": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x95b43AbEEdd47FA9f74Ff3586900D79D3E43d282", + "AcrossV3Adapter": "0x381D5EA470D13ceb51e5dFDd2A28a03b15d4F054", + "ApproveAndDeposit4626VaultHook": "0xF37535D96712FBaEf6D868e721E7b987ad1E6A86", + "ApproveAndDeposit5115VaultHook": "0x44c7a40f05771FdAEAee61f36902D95cbf593988", + "ApproveAndRequestDeposit7540VaultHook": "0x840B2b0553683dE46c5e6382D1a405f44773b43F", + "ApproveERC20Hook": "0x8b789980dc6cC7d88E30C442D704646ff7F6d306", + "BatchTransferFromHook": "0x816d5de8835FB7A003896f486fCce46a6DEBB00A", + "BatchTransferHook": "0x55475fa30E3EEC5996e9eF32B483E30Ed288CcBC", + "CancelDepositRequest7540Hook": "0x0BBA42ddaa6ef6CCd228BD6270565F87154E921A", + "CancelRedeemRequest7540Hook": "0x542601AfAEeB2E5dFc7d1F2fEEF5911285f0c2c0", + "CircleGatewayAddDelegateHook": "0xa7aE1263fd7D6017770147393CE130f16E1fE2cC", + "CircleGatewayMinterHook": "0x659b720a5E8E08D2c379165D17bA5F74dd104824", + "CircleGatewayRemoveDelegateHook": "0x00FbC4e3608A26E0d05905759C2A6188fDa0e2Cd", + "CircleGatewayWalletHook": "0x6383d09cF761FeAa4108B65130793c7eDA356dB5", + "ClaimCancelDepositRequest7540Hook": "0xdf958A047D90b202A7097b5f9B67Bb8CB5285858", + "ClaimCancelRedeemRequest7540Hook": "0x0668f9a638f34928f0bD91588E7B157F0699D594", + "DeBridgeCancelOrderHook": "0xc5DbbBe2D8B9ff884a7ed33f1352021CD2b482C9", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x162225095A384787a257bced9b8893b29C8f1795", + "DebridgeAdapter": "0x5bE003c2cD2DaCD4Cd23488DB7E74568475a36d8", + "Deposit4626VaultHook": "0xa067037B29431C1ff23dEB9b10CC8a1669B0698E", + "Deposit5115VaultHook": "0x32209A2302865784bC1Dc0bd3C55D0A6eB205851", + "Deposit7540VaultHook": "0x0aB1b12E090775fA67DF6e1b44DFAEe676C1DC84", + "ERC4626YieldSourceOracle": "0x2412A5d7261995b49D1F3a731F8452641B916994", + "ERC5115YieldSourceOracle": "0x53Ab533023db9f16e47774109D4Ba57b06A52b10", + "EthenaCooldownSharesHook": "0x1bD7698cc3E3f4cCF5D6CBC74a611bdDEaB18aeF", + "EthenaUnstakeHook": "0xaEBeEc6548B727fd4f3464B19D99f4676d7e7796", + "FlatFeeLedger": "0xAb56d09Ad9975116fCeb14970F2fFb3bB0ad683E", + "MarkRootAsUsedHook": "0xE61774Aa87a05fB1B5665158F2b5E0E10C71B5e2", + "MerklClaimRewardHook": "0x96a7939F94bcd57B031AAe01c1e187f3EBaCCa10", + "OfframpTokensHook": "0x08BA6FF01e651B0c0A0D99AC66563097da2789f7", + "PendlePTYieldSourceOracle": "0xc9Eda6330e1D1F7B91f72e459c85401D96BC48C9", + "PendleRouterRedeemHook": "0xAae2DB58E2f426b910f518cCbB627545aEdaff2F", + "PendleRouterSwapHook": "0x02A0A95C379220E9759960A8Ee923cBbC2d305cd", + "PendleUnifiedHook": "0xF2D6a1d41804BeB856a28218eFD260e51CA1aE87", + "Redeem4626VaultHook": "0x5c3edf3F7c43828Bb72a668e2B29f9e2D9Af5A69", + "Redeem5115VaultHook": "0x6aB1fD107825F9bB3E079d23508A07486b44e6F5", + "Redeem7540VaultHook": "0xE165FBBc89a60756F57Cf0E34c04c35Cc1BbA79D", + "RequestDeposit7540VaultHook": "0xBE7738b26992a322D53edEb9a39331Bf11b60097", + "RequestRedeem7540VaultHook": "0x9c21c130aCF3EADd781AE79d75FF5fC4Bd216797", + "SetOperator7540Hook": "0x86f9DcE0a1A83C501Ba95a1aB1088d67978636A8", + "SetSlippageHook": "0x6551d0140FFdB28920E5e84DC3DA31f4bfe4364E", + "SpectraPTYieldSourceOracle": "0xF7DB5389ED49DfB3F260dB6e3389C7d28076E601", + "StakingYieldSourceOracle": "0x985A6B8DDD9AacEA06ffbF3fc69DaEF48bC819ce", + "SuperDestinationExecutor": "0x6ac58e854798D4aae5989B18ad5a1C0fF17817EF", + "SuperDestinationValidator": "0xADEFF5A0684392C4c273a9C638d1dB8c5dfd0098", + "SuperExecutor": "0x9cC8EDCC41154aaFC74D261aD3D87140D21F6281", + "SuperLedger": "0x04916bB42564CdED96E10F55C059d65E4FCb1Be6", + "SuperLedgerConfiguration": "0x2e2D71289CBA19f831856f85DEC7f194B0165e69", + "SuperNativePaymaster": "0x2288C49689c2CceD5C5bdd74Ac3b775E61a7A532", + "SuperSenderCreator": "0xBC6FB94D2f10A3B4349F592FFA80C4B7C97C1799", + "SuperValidator": "0xB46b4773C5F53FF941533F5dfEFFD0713f5f9f8E", + "SuperVaultYieldSourceOracle": "0xeEbb42210D8a8B165dCF154b325C588EE8dF149A", + "SuperYieldSourceOracle": "0x98F0682ef39dE9cd6028D91090Be6EdAE129f52D", + "TransferERC20Hook": "0x6031c3953BC12D9Af4651B7ed517190A31a67ca4", + "TransferHook": "0x0d54e1b4060bBD598eE6ec8F7A587fF1789164E9", + "SuperGovernor": "0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4", + "SuperVault": "0x303834cd8681BD6Bd31ce7508822b12E2f38D9f2", + "SuperVaultAggregator": "0x10AC0b33e1C4501CF3ec1cB1AE51ebfdbd2d4698", + "SuperVaultStrategy": "0x770abd170404B8ed8182c04f380E567e647b457D", + "SuperVaultEscrow": "0x8982cf48eaB6616f2892888410afad9b0CD2BC9B", + "SuperVaultBatchOperator": "0x3047601ea12565C65b715137799a458971BA070B", + "ECDSAPPSOracle": "0x366d88F03B8EF34eb49F32a927ff6e1609F694F2", + "FixedPriceOracle": "0x66b30A0Dda7F868796ADC3d70232950D65F3565c", + "SuperOracle": "0x40c72A5667572641Ca428a2DFa8456EBD4623c10", + "SuperBank": "0x6fCc6a6A825FC14e6e56Fd14978FC6B97ACB5d15", + "PendlePTAmortizedOracle": "0xD64089698f82cbCD91ba5e0422aDFa81D247eB62", + "PendlePTAmortizedOracleV2": "0x2185B40476510Ad27d17AF90889CE91BE9282A04" + } } }, - "updated_at": "2025-12-19T17:52:40Z" + "updated_at": "2026-02-17T12:17:49Z" } diff --git a/script/output/staging/1/Ethereum-latest.json b/script/output/staging/1/Ethereum-latest.json index 5e5c918a4..dc9626dfc 100644 --- a/script/output/staging/1/Ethereum-latest.json +++ b/script/output/staging/1/Ethereum-latest.json @@ -8,5 +8,7 @@ "SuperVaultAggregator": "0xB383D4063d67F5452Df3e8A7C0062Eabc4049728", "SuperVaultEscrow": "0xC961bd0356b2318820bf79Fe21D23269A42B8863", "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73", - "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6" -} \ No newline at end of file + "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6", + "PendlePTAmortizedOracle": "0xE31FD1d26A52B4a958651a8E751e9362B3880524", + "PendlePTAmortizedOracleV2": "0x1F32A55b20Ee7bA0bC083671c7723dBA1608D66e" +} diff --git a/script/output/staging/8453/Base-latest.json b/script/output/staging/8453/Base-latest.json index 9de466917..24d538422 100644 --- a/script/output/staging/8453/Base-latest.json +++ b/script/output/staging/8453/Base-latest.json @@ -1,12 +1,14 @@ { "ECDSAPPSOracle": "0x68718f31849f266dF64df08320776a39f06efaBd", "FixedPriceOracle": "0xb1E823c84e4aa9Ca38e2f82d3131412254099197", + "PendlePTAmortizedOracle": "0xE31FD1d26A52B4a958651a8E751e9362B3880524", + "PendlePTAmortizedOracleV2": "0x1F32A55b20Ee7bA0bC083671c7723dBA1608D66e", "SuperBank": "0x69d53e376264EEb567213f07d8136050f99eeeC0", "SuperGovernor": "0x0370F5F5f1a63688b16c60D59B19C7469ddb3D6b", "SuperOracleL2": "0x82A3Fc75738462937053c10A24b9e8E36b957906", "SuperVault": "0xB2fA782406453Fb345cDD7f2c3586003A3FE2bBB", "SuperVaultAggregator": "0xB383D4063d67F5452Df3e8A7C0062Eabc4049728", + "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6", "SuperVaultEscrow": "0xC961bd0356b2318820bf79Fe21D23269A42B8863", - "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73", - "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6" -} \ No newline at end of file + "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73" +} diff --git a/script/output/staging/8453/SuperformGasOracle-latest.json b/script/output/staging/8453/SuperformGasOracle-latest.json index e7b4304e4..8f19c75f1 100644 --- a/script/output/staging/8453/SuperformGasOracle-latest.json +++ b/script/output/staging/8453/SuperformGasOracle-latest.json @@ -1,7 +1,7 @@ { "address": "0xCa35c983e810fBFe952A6CA59120fd9a8d2d58e3", "chainId": 8453, - "decimals": 9, + "decimals": 0, "description": "Superform Fast Gas / Gwei", "owner": "0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" } \ No newline at end of file diff --git a/script/output/staging/999/HyperEVM-latest.json b/script/output/staging/999/HyperEVM-latest.json new file mode 100644 index 000000000..8fe9b27d7 --- /dev/null +++ b/script/output/staging/999/HyperEVM-latest.json @@ -0,0 +1,14 @@ +{ + "ECDSAPPSOracle": "0x68718f31849f266dF64df08320776a39f06efaBd", + "FixedPriceOracle": "0xb1E823c84e4aa9Ca38e2f82d3131412254099197", + "SuperBank": "0x69d53e376264EEb567213f07d8136050f99eeeC0", + "SuperGovernor": "0x0370F5F5f1a63688b16c60D59B19C7469ddb3D6b", + "SuperOracle": "0xdEd271fA2a90e7e6A40AF92Ad38eBd3EB78F7675", + "SuperVault": "0xB2fA782406453Fb345cDD7f2c3586003A3FE2bBB", + "SuperVaultAggregator": "0xB383D4063d67F5452Df3e8A7C0062Eabc4049728", + "SuperVaultEscrow": "0xC961bd0356b2318820bf79Fe21D23269A42B8863", + "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73", + "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6", + "PendlePTAmortizedOracle": "0xE31FD1d26A52B4a958651a8E751e9362B3880524", + "PendlePTAmortizedOracleV2": "0x1F32A55b20Ee7bA0bC083671c7723dBA1608D66e" +} diff --git a/script/output/staging/999/SuperformGasOracle-latest.json b/script/output/staging/999/SuperformGasOracle-latest.json new file mode 100644 index 000000000..3b8f7b92b --- /dev/null +++ b/script/output/staging/999/SuperformGasOracle-latest.json @@ -0,0 +1,7 @@ +{ + "address": "0xCa35c983e810fBFe952A6CA59120fd9a8d2d58e3", + "chainId": 999, + "decimals": 0, + "description": "Superform Fast Gas / Gwei", + "owner": "0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" +} \ No newline at end of file diff --git a/script/output/staging/999/UpOFT-latest.json b/script/output/staging/999/UpOFT-latest.json new file mode 100644 index 000000000..6224c8e3f --- /dev/null +++ b/script/output/staging/999/UpOFT-latest.json @@ -0,0 +1,3 @@ +{ + "UpOFT": "0x53749a9a8dE9847DAE54E7F432616F2fDfa32B7f" +} \ No newline at end of file diff --git a/script/output/staging/latest.json b/script/output/staging/latest.json new file mode 100644 index 000000000..668e67892 --- /dev/null +++ b/script/output/staging/latest.json @@ -0,0 +1,449 @@ +{ + "networks": { + "Ethereum": { + "counter": 4, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x913D4b78d8C1c05a0C97AFf832377F82a800cf5A", + "AcrossV3Adapter": "0x0cf03D2D16363E3143e42E3f14d66EE656CA1437", + "ApproveAndAcrossSendFundsAndExecuteOnDstHook": "0x13d20FC6BEb449606D1562654C7d0eF549f76812", + "ApproveAndDeposit4626VaultHook": "0xdcAfC76B2f777bBA2d1e6C535F73AcA3dBe558F4", + "ApproveAndDeposit5115VaultHook": "0xDc997F44693d865C68d2321E41716Bdc098016ee", + "ApproveAndRequestDeposit7540VaultHook": "0xef56121Af8553C0a534052b6305301E414E79c41", + "ApproveAndSwapOdosV2Hook": "0x103F71A3ECE8fF293d2B3997acA502BE0e3932eb", + "ApproveERC20Hook": "0xD3490320fFAE7d38AaaEe4269b4A5c1700f71FDB", + "BatchTransferFromHook": "0x71bF940153Edab9B63B4b813A6D9D21B188EA07a", + "BatchTransferHook": "0x608570eED65750a9cc58bFc6DCbC0cEA25f68458", + "CancelDepositRequest7540Hook": "0xB062CE8f773D8353c1B89C2d175a46c0D489C4e7", + "CancelRedeemRequest7540Hook": "0x2aF3962aE7a3ABE785E33E1c467a2c594777dA1c", + "CircleGatewayAddDelegateHook": "0xC8D6A10ea33b48878137E3332556Ca51D455B7c0", + "CircleGatewayMinterHook": "0x3A2a1281622Aa704a6480D1745702F6F83727521", + "CircleGatewayRemoveDelegateHook": "0xfC02C7Ec6efaF48DdB5E6DB97d7F95Fd3433Ea0C", + "CircleGatewayWalletHook": "0x7Be37FB4Ad39BDe35c5168Df21f3f1E019462510", + "ClaimCancelDepositRequest7540Hook": "0x0B515b1344cb9bAe3205B1c846a9a8C942Ef41b0", + "ClaimCancelRedeemRequest7540Hook": "0xE579aDA69fbB49D0A4d3c6D3f706a74f8CFc4989", + "DeBridgeCancelOrderHook": "0x8A6bc4bA5e6E4330f8f1bE93fe27CC5dd4a3B53c", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x48A5f8319F4a9340D2D2190E03EFa60b262Dd7ae", + "DebridgeAdapter": "0x09158270738CDdF351Eaa88eF888B23301D21C05", + "Deposit4626VaultHook": "0xe3FFf64A14A38a5b082502779ae6f6a9a273b02C", + "Deposit5115VaultHook": "0x153B77421C844005C9af67cCA8A0469F814e10f8", + "Deposit7540VaultHook": "0xBDF724DA1928988F2891B9B565460161968Fc9d7", + "ERC4626YieldSourceOracle": "0x693E5364A5f95Be378eD44e27b62374d24Af6DF0", + "ERC5115YieldSourceOracle": "0x5F255eBDF9456EBF8dDe43C38b11D32d161e7300", + "EthenaCooldownSharesHook": "0xA1BD126da3d2830fe19eA93c0872aF433B7c04f7", + "EthenaUnstakeHook": "0xC836797f7b7f645248b73938d0bD2Ab2dc6A9337", + "FlatFeeLedger": "0xb989FC825C8C77fbE84b69082048372d548f6FeF", + "MarkRootAsUsedHook": "0x2a655fDfCA2113AD755F81dFf941b54919d0544d", + "MerklClaimRewardHook": "0x67CcC575D4064418406AE70cC094781837D01777", + "OfframpTokensHook": "0x45769A1252B26976896533664454b6e295b88266", + "PendlePTYieldSourceOracle": "0x5456333427e671072F77F68E90E3A7d89Cc996Aa", + "PendleRouterRedeemHook": "0x94E7D358e8BAB5fEFb53d20C2D261A579898Eab6", + "PendleRouterSwapHook": "0xB6894368ffB77a46bE4C8EcAF20f29Cd9219301D", + "Redeem4626VaultHook": "0xB10b1fCE2E4B24C5A988A9932d4Cf9DB37Ba0394", + "Redeem5115VaultHook": "0x421aE0BB3C201959D0B152a87d56BCdB2Ee1cF63", + "Redeem7540VaultHook": "0xCa50aB0375b774B2DE12919423Dd0B8e8cAad95f", + "RequestDeposit7540VaultHook": "0x01Af8d98DDA6310D8aE91af7439E1b5836ad3d9c", + "RequestRedeem7540VaultHook": "0xd9f7c658d3ec52E02e4402fE87e48A36cb9E0dC0", + "SetOperator7540Hook": "0xa31E5013096efE9bDfd590275d80fe724AD269BC", + "SpectraPTYieldSourceOracle": "0xBb9154D1a9c06047D4AD5721eAEd874Ee125f4E3", + "StakingYieldSourceOracle": "0x0737eB8db2992b13a66b46E8226F36d774CA2A02", + "SuperDestinationExecutor": "0xd0B5d200a6B136D619Dd1c7BBA30b004b4773C40", + "SuperDestinationValidator": "0xCA9bB3fcDfB455962ee284A189CbFc2262970b39", + "SuperExecutor": "0xdC903190CF37993e970aA0b15cCC6e08EA12BCa0", + "SuperLedger": "0x31A3c245C67468A93E6874Dec00A7d3Ac4eF5245", + "SuperLedgerConfiguration": "0x102146454720de58Ee1331F7a91cdCC1F0c346E0", + "SuperNativePaymaster": "0x321093026AA7Ea3d25E69e550C4102d71D82E1cD", + "SuperSenderCreator": "0xEe885bD357B603cdC18239b8036e2510Ed2d1E35", + "SuperValidator": "0x5C563Ba4881e3c2710BABe76282895EfE5C8247d", + "SuperVaultYieldSourceOracle": "0x2339E250Cc72694BFea62C594B267270d728fD2b", + "SuperYieldSourceOracle": "0x03f1d66d67BDacD1d417d884a59733f3Af626c62", + "Swap1InchHook": "0xc785A8a40D449cbd3352853a7B2A514838e07728", + "SwapOdosV2Hook": "0x6FD58b83e7518A1ABEFB67a7E32c3Ef316753A11", + "SwapUniswapV4Hook": "0x08c57a93C225E598B3D596A296F971cA80cF1B84", + "TransferERC20Hook": "0x9379C1cfaA3B660855231387F4F3167fee2cE6b2", + "TransferHook": "0xDDBde23fE91FCFd9E6856B17c4A7eE8F444f74Ea", + "Nexus": "0x10f2Ef78610aB17685656f894c556b568AeF2a35", + "NexusBootstrap": "0x3BF33e679b933446292b95F27186DCDB68492CD0", + "NexusAccountFactory": "0x4fb71F028D424358B27877fb3d9F481cf10D1C63", + "SuperGovernor": "0x0370F5F5f1a63688b16c60D59B19C7469ddb3D6b", + "SuperVault": "0xB2fA782406453Fb345cDD7f2c3586003A3FE2bBB", + "SuperVaultAggregator": "0xB383D4063d67F5452Df3e8A7C0062Eabc4049728", + "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73", + "SuperVaultEscrow": "0xC961bd0356b2318820bf79Fe21D23269A42B8863", + "ECDSAPPSOracle": "0x68718f31849f266dF64df08320776a39f06efaBd", + "FixedPriceOracle": "0xb1E823c84e4aa9Ca38e2f82d3131412254099197", + "SuperOracle": "0x672A70eb12241c4Cfe5DA89d79BdB224c323b99C", + "SuperBank": "0x69d53e376264EEb567213f07d8136050f99eeeC0", + "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6", + "SetSlippageHook": "0xcad65bEC610d0890d94d98Bd16E220f0DC90a90d", + "PendlePTAmortizedOracle": "0xE31FD1d26A52B4a958651a8E751e9362B3880524", + "RecordPurchasePendlePTAmortizedOracleHook": "0x5a64a836c7A8569b7A094Fe7145dd700b5ae1aeA", + "RecordRedemptionPendlePTAmortizedOracleHook": "0x9eb907A8591742d6DcF34E0002e870FEd9F794d7", + "PendleUnifiedHook": "0xbc7F29336BD315A32f537dCD8e1aA9efF66b73A3", + "PendlePTAmortizedOracleV2": "0x1F32A55b20Ee7bA0bC083671c7723dBA1608D66e", + "RecordPurchasePendlePTAmortizedOracleHookV2": "0xE23A3051772B0Be4A02661Aadc7a4078b77C1950", + "RecordRedemptionPendlePTAmortizedOracleHookV2": "0x65133147a37b2d1171f1c164c4C697db34419809" + } + }, + "Base": { + "counter": 3, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x445f56C4eE18a1540Ac1d0A438F355DDBFFAf476", + "AcrossV3Adapter": "0xE43Bcd153AD018e4ad3113Bd0A51275968d393B3", + "ApproveAndAcrossSendFundsAndExecuteOnDstHook": "0xAfeFab788b2572691F55F140D1A251fabfF31C21", + "ApproveAndDeposit4626VaultHook": "0xdcAfC76B2f777bBA2d1e6C535F73AcA3dBe558F4", + "ApproveAndDeposit5115VaultHook": "0xDc997F44693d865C68d2321E41716Bdc098016ee", + "ApproveAndRequestDeposit7540VaultHook": "0xef56121Af8553C0a534052b6305301E414E79c41", + "ApproveAndSwapOdosV2Hook": "0x4440F9Dede90b5eE690B2B4C239Dc4A52076686a", + "ApproveERC20Hook": "0xD3490320fFAE7d38AaaEe4269b4A5c1700f71FDB", + "BatchTransferFromHook": "0x71bF940153Edab9B63B4b813A6D9D21B188EA07a", + "BatchTransferHook": "0x608570eED65750a9cc58bFc6DCbC0cEA25f68458", + "CancelDepositRequest7540Hook": "0xB062CE8f773D8353c1B89C2d175a46c0D489C4e7", + "CancelRedeemRequest7540Hook": "0x2aF3962aE7a3ABE785E33E1c467a2c594777dA1c", + "CircleGatewayAddDelegateHook": "0xC8D6A10ea33b48878137E3332556Ca51D455B7c0", + "CircleGatewayMinterHook": "0x3A2a1281622Aa704a6480D1745702F6F83727521", + "CircleGatewayRemoveDelegateHook": "0xfC02C7Ec6efaF48DdB5E6DB97d7F95Fd3433Ea0C", + "CircleGatewayWalletHook": "0x7Be37FB4Ad39BDe35c5168Df21f3f1E019462510", + "ClaimCancelDepositRequest7540Hook": "0x0B515b1344cb9bAe3205B1c846a9a8C942Ef41b0", + "ClaimCancelRedeemRequest7540Hook": "0xE579aDA69fbB49D0A4d3c6D3f706a74f8CFc4989", + "DeBridgeCancelOrderHook": "0x8A6bc4bA5e6E4330f8f1bE93fe27CC5dd4a3B53c", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x48A5f8319F4a9340D2D2190E03EFa60b262Dd7ae", + "DebridgeAdapter": "0x09158270738CDdF351Eaa88eF888B23301D21C05", + "Deposit4626VaultHook": "0xe3FFf64A14A38a5b082502779ae6f6a9a273b02C", + "Deposit5115VaultHook": "0x153B77421C844005C9af67cCA8A0469F814e10f8", + "Deposit7540VaultHook": "0xBDF724DA1928988F2891B9B565460161968Fc9d7", + "ERC4626YieldSourceOracle": "0x693E5364A5f95Be378eD44e27b62374d24Af6DF0", + "ERC5115YieldSourceOracle": "0x5F255eBDF9456EBF8dDe43C38b11D32d161e7300", + "EthenaCooldownSharesHook": "0xA1BD126da3d2830fe19eA93c0872aF433B7c04f7", + "EthenaUnstakeHook": "0xC836797f7b7f645248b73938d0bD2Ab2dc6A9337", + "FlatFeeLedger": "0xb989FC825C8C77fbE84b69082048372d548f6FeF", + "MarkRootAsUsedHook": "0x2a655fDfCA2113AD755F81dFf941b54919d0544d", + "MerklClaimRewardHook": "0x67CcC575D4064418406AE70cC094781837D01777", + "OfframpTokensHook": "0x45769A1252B26976896533664454b6e295b88266", + "PendlePTYieldSourceOracle": "0x5456333427e671072F77F68E90E3A7d89Cc996Aa", + "PendleRouterRedeemHook": "0x94E7D358e8BAB5fEFb53d20C2D261A579898Eab6", + "PendleRouterSwapHook": "0xB6894368ffB77a46bE4C8EcAF20f29Cd9219301D", + "Redeem4626VaultHook": "0xB10b1fCE2E4B24C5A988A9932d4Cf9DB37Ba0394", + "Redeem5115VaultHook": "0x421aE0BB3C201959D0B152a87d56BCdB2Ee1cF63", + "Redeem7540VaultHook": "0xCa50aB0375b774B2DE12919423Dd0B8e8cAad95f", + "RequestDeposit7540VaultHook": "0x01Af8d98DDA6310D8aE91af7439E1b5836ad3d9c", + "RequestRedeem7540VaultHook": "0xd9f7c658d3ec52E02e4402fE87e48A36cb9E0dC0", + "SetOperator7540Hook": "0xa31E5013096efE9bDfd590275d80fe724AD269BC", + "SpectraPTYieldSourceOracle": "0xBb9154D1a9c06047D4AD5721eAEd874Ee125f4E3", + "StakingYieldSourceOracle": "0x0737eB8db2992b13a66b46E8226F36d774CA2A02", + "SuperDestinationExecutor": "0xd0B5d200a6B136D619Dd1c7BBA30b004b4773C40", + "SuperDestinationValidator": "0xCA9bB3fcDfB455962ee284A189CbFc2262970b39", + "SuperExecutor": "0xdC903190CF37993e970aA0b15cCC6e08EA12BCa0", + "SuperLedger": "0x31A3c245C67468A93E6874Dec00A7d3Ac4eF5245", + "SuperLedgerConfiguration": "0x102146454720de58Ee1331F7a91cdCC1F0c346E0", + "SuperNativePaymaster": "0x321093026AA7Ea3d25E69e550C4102d71D82E1cD", + "SuperSenderCreator": "0xEe885bD357B603cdC18239b8036e2510Ed2d1E35", + "SuperValidator": "0x5C563Ba4881e3c2710BABe76282895EfE5C8247d", + "SuperVaultYieldSourceOracle": "0x2339E250Cc72694BFea62C594B267270d728fD2b", + "SuperYieldSourceOracle": "0x03f1d66d67BDacD1d417d884a59733f3Af626c62", + "Swap1InchHook": "0xc785A8a40D449cbd3352853a7B2A514838e07728", + "SwapOdosV2Hook": "0xA3a87993C802C6Ee82B1F77DF452F310Fa1a5de9", + "SwapUniswapV4Hook": "0x2F7F2eaad2734D617b3fD14A92C28929af916cF1", + "TransferERC20Hook": "0x9379C1cfaA3B660855231387F4F3167fee2cE6b2", + "TransferHook": "0xDDBde23fE91FCFd9E6856B17c4A7eE8F444f74Ea", + "Nexus": "0x10f2Ef78610aB17685656f894c556b568AeF2a35", + "NexusBootstrap": "0x3BF33e679b933446292b95F27186DCDB68492CD0", + "NexusAccountFactory": "0x4fb71F028D424358B27877fb3d9F481cf10D1C63", + "SuperGovernor": "0x0370F5F5f1a63688b16c60D59B19C7469ddb3D6b", + "SuperVaultAggregator": "0xB383D4063d67F5452Df3e8A7C0062Eabc4049728", + "ECDSAPPSOracle": "0x68718f31849f266dF64df08320776a39f06efaBd", + "SuperVault": "0xB2fA782406453Fb345cDD7f2c3586003A3FE2bBB", + "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73", + "SuperVaultEscrow": "0xC961bd0356b2318820bf79Fe21D23269A42B8863", + "FixedPriceOracle": "0xb1E823c84e4aa9Ca38e2f82d3131412254099197", + "SuperOracleL2": "0x82A3Fc75738462937053c10A24b9e8E36b957906", + "SuperBank": "0x69d53e376264EEb567213f07d8136050f99eeeC0", + "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6", + "SetSlippageHook": "0xcad65bEC610d0890d94d98Bd16E220f0DC90a90d", + "PendlePTAmortizedOracle": "0xE31FD1d26A52B4a958651a8E751e9362B3880524", + "RecordPurchasePendlePTAmortizedOracleHook": "0x5a64a836c7A8569b7A094Fe7145dd700b5ae1aeA", + "RecordRedemptionPendlePTAmortizedOracleHook": "0x9eb907A8591742d6DcF34E0002e870FEd9F794d7", + "PendleUnifiedHook": "0xbc7F29336BD315A32f537dCD8e1aA9efF66b73A3", + "PendlePTAmortizedOracleV2": "0x1F32A55b20Ee7bA0bC083671c7723dBA1608D66e", + "RecordPurchasePendlePTAmortizedOracleHookV2": "0xE23A3051772B0Be4A02661Aadc7a4078b77C1950", + "RecordRedemptionPendlePTAmortizedOracleHookV2": "0x65133147a37b2d1171f1c164c4C697db34419809" + } + }, + "BNB": { + "counter": 3, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x2f9914c470485903f96aF29e74c08aC0780Df2f3", + "AcrossV3Adapter": "0x952767E8991D1b0a37D6212f465ab8153b6f5973", + "ApproveAndAcrossSendFundsAndExecuteOnDstHook": "0x5E68Bc3bc411525210eE397C53Ed4a68b97A1Cd3", + "ApproveAndDeposit4626VaultHook": "0xdcAfC76B2f777bBA2d1e6C535F73AcA3dBe558F4", + "ApproveAndDeposit5115VaultHook": "0xDc997F44693d865C68d2321E41716Bdc098016ee", + "ApproveAndRequestDeposit7540VaultHook": "0xef56121Af8553C0a534052b6305301E414E79c41", + "ApproveAndSwapOdosV2Hook": "0x806DBE37954Bb3965E2Cf305fd2765C651e670c0", + "ApproveERC20Hook": "0xD3490320fFAE7d38AaaEe4269b4A5c1700f71FDB", + "BatchTransferFromHook": "0x71bF940153Edab9B63B4b813A6D9D21B188EA07a", + "BatchTransferHook": "0x608570eED65750a9cc58bFc6DCbC0cEA25f68458", + "CancelDepositRequest7540Hook": "0xB062CE8f773D8353c1B89C2d175a46c0D489C4e7", + "CancelRedeemRequest7540Hook": "0x2aF3962aE7a3ABE785E33E1c467a2c594777dA1c", + "CircleGatewayAddDelegateHook": "0xC8D6A10ea33b48878137E3332556Ca51D455B7c0", + "CircleGatewayMinterHook": "0x3A2a1281622Aa704a6480D1745702F6F83727521", + "CircleGatewayRemoveDelegateHook": "0xfC02C7Ec6efaF48DdB5E6DB97d7F95Fd3433Ea0C", + "CircleGatewayWalletHook": "0x7Be37FB4Ad39BDe35c5168Df21f3f1E019462510", + "ClaimCancelDepositRequest7540Hook": "0x0B515b1344cb9bAe3205B1c846a9a8C942Ef41b0", + "ClaimCancelRedeemRequest7540Hook": "0xE579aDA69fbB49D0A4d3c6D3f706a74f8CFc4989", + "DeBridgeCancelOrderHook": "0x8A6bc4bA5e6E4330f8f1bE93fe27CC5dd4a3B53c", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x48A5f8319F4a9340D2D2190E03EFa60b262Dd7ae", + "DebridgeAdapter": "0x09158270738CDdF351Eaa88eF888B23301D21C05", + "Deposit4626VaultHook": "0xe3FFf64A14A38a5b082502779ae6f6a9a273b02C", + "Deposit5115VaultHook": "0x153B77421C844005C9af67cCA8A0469F814e10f8", + "Deposit7540VaultHook": "0xBDF724DA1928988F2891B9B565460161968Fc9d7", + "ERC4626YieldSourceOracle": "0x693E5364A5f95Be378eD44e27b62374d24Af6DF0", + "ERC5115YieldSourceOracle": "0x5F255eBDF9456EBF8dDe43C38b11D32d161e7300", + "EthenaCooldownSharesHook": "0xA1BD126da3d2830fe19eA93c0872aF433B7c04f7", + "EthenaUnstakeHook": "0xC836797f7b7f645248b73938d0bD2Ab2dc6A9337", + "FlatFeeLedger": "0xb989FC825C8C77fbE84b69082048372d548f6FeF", + "MarkRootAsUsedHook": "0x2a655fDfCA2113AD755F81dFf941b54919d0544d", + "MerklClaimRewardHook": "0x67CcC575D4064418406AE70cC094781837D01777", + "OfframpTokensHook": "0x45769A1252B26976896533664454b6e295b88266", + "PendlePTYieldSourceOracle": "0x5456333427e671072F77F68E90E3A7d89Cc996Aa", + "PendleRouterRedeemHook": "0x94E7D358e8BAB5fEFb53d20C2D261A579898Eab6", + "PendleRouterSwapHook": "0xB6894368ffB77a46bE4C8EcAF20f29Cd9219301D", + "Redeem4626VaultHook": "0xB10b1fCE2E4B24C5A988A9932d4Cf9DB37Ba0394", + "Redeem5115VaultHook": "0x421aE0BB3C201959D0B152a87d56BCdB2Ee1cF63", + "Redeem7540VaultHook": "0xCa50aB0375b774B2DE12919423Dd0B8e8cAad95f", + "RequestDeposit7540VaultHook": "0x01Af8d98DDA6310D8aE91af7439E1b5836ad3d9c", + "RequestRedeem7540VaultHook": "0xd9f7c658d3ec52E02e4402fE87e48A36cb9E0dC0", + "SetOperator7540Hook": "0xa31E5013096efE9bDfd590275d80fe724AD269BC", + "SpectraPTYieldSourceOracle": "0xBb9154D1a9c06047D4AD5721eAEd874Ee125f4E3", + "StakingYieldSourceOracle": "0x0737eB8db2992b13a66b46E8226F36d774CA2A02", + "SuperDestinationExecutor": "0xd0B5d200a6B136D619Dd1c7BBA30b004b4773C40", + "SuperDestinationValidator": "0xCA9bB3fcDfB455962ee284A189CbFc2262970b39", + "SuperExecutor": "0xdC903190CF37993e970aA0b15cCC6e08EA12BCa0", + "SuperLedger": "0x31A3c245C67468A93E6874Dec00A7d3Ac4eF5245", + "SuperLedgerConfiguration": "0x102146454720de58Ee1331F7a91cdCC1F0c346E0", + "SuperNativePaymaster": "0x321093026AA7Ea3d25E69e550C4102d71D82E1cD", + "SuperSenderCreator": "0xEe885bD357B603cdC18239b8036e2510Ed2d1E35", + "SuperValidator": "0x5C563Ba4881e3c2710BABe76282895EfE5C8247d", + "SuperVaultYieldSourceOracle": "0x2339E250Cc72694BFea62C594B267270d728fD2b", + "SuperYieldSourceOracle": "0x03f1d66d67BDacD1d417d884a59733f3Af626c62", + "Swap1InchHook": "0xc785A8a40D449cbd3352853a7B2A514838e07728", + "SwapOdosV2Hook": "0xB6BD55F3CF924D0B17ddCF80D990c056A072cFDc", + "TransferERC20Hook": "0x9379C1cfaA3B660855231387F4F3167fee2cE6b2", + "TransferHook": "0xDDBde23fE91FCFd9E6856B17c4A7eE8F444f74Ea", + "Nexus": "0x10f2Ef78610aB17685656f894c556b568AeF2a35", + "NexusBootstrap": "0x3BF33e679b933446292b95F27186DCDB68492CD0", + "NexusAccountFactory": "0x4fb71F028D424358B27877fb3d9F481cf10D1C63", + "SetSlippageHook": "0xcad65bEC610d0890d94d98Bd16E220f0DC90a90d", + "PendleUnifiedHook": "0xbc7F29336BD315A32f537dCD8e1aA9efF66b73A3" + } + }, + "Arbitrum": { + "counter": 3, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0xF228336375b193E4efF20be6104bb0573331a724", + "AcrossV3Adapter": "0xabCE458E441b8cfD6B9A487Dab0e87C9C0c06180", + "ApproveAndAcrossSendFundsAndExecuteOnDstHook": "0x0a08b98Af465c93332D1a4BE813FE0970a25e91E", + "ApproveAndDeposit4626VaultHook": "0xdcAfC76B2f777bBA2d1e6C535F73AcA3dBe558F4", + "ApproveAndDeposit5115VaultHook": "0xDc997F44693d865C68d2321E41716Bdc098016ee", + "ApproveAndRequestDeposit7540VaultHook": "0xef56121Af8553C0a534052b6305301E414E79c41", + "ApproveAndSwapOdosV2Hook": "0xAc4AA35452CF1ef22A60141eae7b80b945699e56", + "ApproveERC20Hook": "0xD3490320fFAE7d38AaaEe4269b4A5c1700f71FDB", + "BatchTransferFromHook": "0x71bF940153Edab9B63B4b813A6D9D21B188EA07a", + "BatchTransferHook": "0x608570eED65750a9cc58bFc6DCbC0cEA25f68458", + "CancelDepositRequest7540Hook": "0xB062CE8f773D8353c1B89C2d175a46c0D489C4e7", + "CancelRedeemRequest7540Hook": "0x2aF3962aE7a3ABE785E33E1c467a2c594777dA1c", + "CircleGatewayAddDelegateHook": "0xC8D6A10ea33b48878137E3332556Ca51D455B7c0", + "CircleGatewayMinterHook": "0x3A2a1281622Aa704a6480D1745702F6F83727521", + "CircleGatewayRemoveDelegateHook": "0xfC02C7Ec6efaF48DdB5E6DB97d7F95Fd3433Ea0C", + "CircleGatewayWalletHook": "0x7Be37FB4Ad39BDe35c5168Df21f3f1E019462510", + "ClaimCancelDepositRequest7540Hook": "0x0B515b1344cb9bAe3205B1c846a9a8C942Ef41b0", + "ClaimCancelRedeemRequest7540Hook": "0xE579aDA69fbB49D0A4d3c6D3f706a74f8CFc4989", + "DeBridgeCancelOrderHook": "0x8A6bc4bA5e6E4330f8f1bE93fe27CC5dd4a3B53c", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x48A5f8319F4a9340D2D2190E03EFa60b262Dd7ae", + "DebridgeAdapter": "0x09158270738CDdF351Eaa88eF888B23301D21C05", + "Deposit4626VaultHook": "0xe3FFf64A14A38a5b082502779ae6f6a9a273b02C", + "Deposit5115VaultHook": "0x153B77421C844005C9af67cCA8A0469F814e10f8", + "Deposit7540VaultHook": "0xBDF724DA1928988F2891B9B565460161968Fc9d7", + "ERC4626YieldSourceOracle": "0x693E5364A5f95Be378eD44e27b62374d24Af6DF0", + "ERC5115YieldSourceOracle": "0x5F255eBDF9456EBF8dDe43C38b11D32d161e7300", + "EthenaCooldownSharesHook": "0xA1BD126da3d2830fe19eA93c0872aF433B7c04f7", + "EthenaUnstakeHook": "0xC836797f7b7f645248b73938d0bD2Ab2dc6A9337", + "FlatFeeLedger": "0xb989FC825C8C77fbE84b69082048372d548f6FeF", + "MarkRootAsUsedHook": "0x2a655fDfCA2113AD755F81dFf941b54919d0544d", + "MerklClaimRewardHook": "0x67CcC575D4064418406AE70cC094781837D01777", + "OfframpTokensHook": "0x45769A1252B26976896533664454b6e295b88266", + "PendlePTYieldSourceOracle": "0x5456333427e671072F77F68E90E3A7d89Cc996Aa", + "PendleRouterRedeemHook": "0x94E7D358e8BAB5fEFb53d20C2D261A579898Eab6", + "PendleRouterSwapHook": "0xB6894368ffB77a46bE4C8EcAF20f29Cd9219301D", + "Redeem4626VaultHook": "0xB10b1fCE2E4B24C5A988A9932d4Cf9DB37Ba0394", + "Redeem5115VaultHook": "0x421aE0BB3C201959D0B152a87d56BCdB2Ee1cF63", + "Redeem7540VaultHook": "0xCa50aB0375b774B2DE12919423Dd0B8e8cAad95f", + "RequestDeposit7540VaultHook": "0x01Af8d98DDA6310D8aE91af7439E1b5836ad3d9c", + "RequestRedeem7540VaultHook": "0xd9f7c658d3ec52E02e4402fE87e48A36cb9E0dC0", + "SetOperator7540Hook": "0xa31E5013096efE9bDfd590275d80fe724AD269BC", + "SpectraPTYieldSourceOracle": "0xBb9154D1a9c06047D4AD5721eAEd874Ee125f4E3", + "StakingYieldSourceOracle": "0x0737eB8db2992b13a66b46E8226F36d774CA2A02", + "SuperDestinationExecutor": "0xd0B5d200a6B136D619Dd1c7BBA30b004b4773C40", + "SuperDestinationValidator": "0xCA9bB3fcDfB455962ee284A189CbFc2262970b39", + "SuperExecutor": "0xdC903190CF37993e970aA0b15cCC6e08EA12BCa0", + "SuperLedger": "0x31A3c245C67468A93E6874Dec00A7d3Ac4eF5245", + "SuperLedgerConfiguration": "0x102146454720de58Ee1331F7a91cdCC1F0c346E0", + "SuperNativePaymaster": "0x321093026AA7Ea3d25E69e550C4102d71D82E1cD", + "SuperSenderCreator": "0xEe885bD357B603cdC18239b8036e2510Ed2d1E35", + "SuperValidator": "0x5C563Ba4881e3c2710BABe76282895EfE5C8247d", + "SuperVaultYieldSourceOracle": "0x2339E250Cc72694BFea62C594B267270d728fD2b", + "SuperYieldSourceOracle": "0x03f1d66d67BDacD1d417d884a59733f3Af626c62", + "Swap1InchHook": "0xc785A8a40D449cbd3352853a7B2A514838e07728", + "SwapOdosV2Hook": "0x4D6205b40aA08b07B703892dbb369646B76BE74a", + "SwapUniswapV4Hook": "0xBE4407e2fcb049Baa5C667795397b5f0BED5eE6f", + "TransferERC20Hook": "0x9379C1cfaA3B660855231387F4F3167fee2cE6b2", + "TransferHook": "0xDDBde23fE91FCFd9E6856B17c4A7eE8F444f74Ea", + "Nexus": "0x10f2Ef78610aB17685656f894c556b568AeF2a35", + "NexusBootstrap": "0x3BF33e679b933446292b95F27186DCDB68492CD0", + "NexusAccountFactory": "0x4fb71F028D424358B27877fb3d9F481cf10D1C63", + "SetSlippageHook": "0xcad65bEC610d0890d94d98Bd16E220f0DC90a90d", + "PendleUnifiedHook": "0xbc7F29336BD315A32f537dCD8e1aA9efF66b73A3" + } + }, + "Avalanche": { + "counter": 0, + "vnet_id": "", + "contracts": { + "ApproveAndDeposit4626VaultHook": "0xdcAfC76B2f777bBA2d1e6C535F73AcA3dBe558F4", + "ApproveAndDeposit5115VaultHook": "0xDc997F44693d865C68d2321E41716Bdc098016ee", + "ApproveAndRequestDeposit7540VaultHook": "0xef56121Af8553C0a534052b6305301E414E79c41", + "ApproveAndSwapOdosV2Hook": "0x418c0b3eEad48aE2C2133D6e3265829E5e46c223", + "ApproveERC20Hook": "0xD3490320fFAE7d38AaaEe4269b4A5c1700f71FDB", + "BatchTransferFromHook": "0x71bF940153Edab9B63B4b813A6D9D21B188EA07a", + "BatchTransferHook": "0x608570eED65750a9cc58bFc6DCbC0cEA25f68458", + "CancelDepositRequest7540Hook": "0xB062CE8f773D8353c1B89C2d175a46c0D489C4e7", + "CancelRedeemRequest7540Hook": "0x2aF3962aE7a3ABE785E33E1c467a2c594777dA1c", + "CircleGatewayAddDelegateHook": "0xC8D6A10ea33b48878137E3332556Ca51D455B7c0", + "CircleGatewayMinterHook": "0x3A2a1281622Aa704a6480D1745702F6F83727521", + "CircleGatewayRemoveDelegateHook": "0xfC02C7Ec6efaF48DdB5E6DB97d7F95Fd3433Ea0C", + "CircleGatewayWalletHook": "0x7Be37FB4Ad39BDe35c5168Df21f3f1E019462510", + "ClaimCancelDepositRequest7540Hook": "0x0B515b1344cb9bAe3205B1c846a9a8C942Ef41b0", + "ClaimCancelRedeemRequest7540Hook": "0xE579aDA69fbB49D0A4d3c6D3f706a74f8CFc4989", + "DeBridgeCancelOrderHook": "0x8A6bc4bA5e6E4330f8f1bE93fe27CC5dd4a3B53c", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x48A5f8319F4a9340D2D2190E03EFa60b262Dd7ae", + "DebridgeAdapter": "0x09158270738CDdF351Eaa88eF888B23301D21C05", + "Deposit4626VaultHook": "0xe3FFf64A14A38a5b082502779ae6f6a9a273b02C", + "Deposit5115VaultHook": "0x153B77421C844005C9af67cCA8A0469F814e10f8", + "Deposit7540VaultHook": "0xBDF724DA1928988F2891B9B565460161968Fc9d7", + "ERC4626YieldSourceOracle": "0x693E5364A5f95Be378eD44e27b62374d24Af6DF0", + "ERC5115YieldSourceOracle": "0x5F255eBDF9456EBF8dDe43C38b11D32d161e7300", + "EthenaCooldownSharesHook": "0xA1BD126da3d2830fe19eA93c0872aF433B7c04f7", + "EthenaUnstakeHook": "0xC836797f7b7f645248b73938d0bD2Ab2dc6A9337", + "FlatFeeLedger": "0xb989FC825C8C77fbE84b69082048372d548f6FeF", + "MarkRootAsUsedHook": "0x2a655fDfCA2113AD755F81dFf941b54919d0544d", + "MerklClaimRewardHook": "0x67CcC575D4064418406AE70cC094781837D01777", + "OfframpTokensHook": "0x45769A1252B26976896533664454b6e295b88266", + "PendlePTYieldSourceOracle": "0x5456333427e671072F77F68E90E3A7d89Cc996Aa", + "Redeem4626VaultHook": "0xB10b1fCE2E4B24C5A988A9932d4Cf9DB37Ba0394", + "Redeem5115VaultHook": "0x421aE0BB3C201959D0B152a87d56BCdB2Ee1cF63", + "Redeem7540VaultHook": "0xCa50aB0375b774B2DE12919423Dd0B8e8cAad95f", + "RequestDeposit7540VaultHook": "0x01Af8d98DDA6310D8aE91af7439E1b5836ad3d9c", + "RequestRedeem7540VaultHook": "0xd9f7c658d3ec52E02e4402fE87e48A36cb9E0dC0", + "SetOperator7540Hook": "0xa31E5013096efE9bDfd590275d80fe724AD269BC", + "SpectraPTYieldSourceOracle": "0xBb9154D1a9c06047D4AD5721eAEd874Ee125f4E3", + "StakingYieldSourceOracle": "0x0737eB8db2992b13a66b46E8226F36d774CA2A02", + "SuperDestinationExecutor": "0xd0B5d200a6B136D619Dd1c7BBA30b004b4773C40", + "SuperDestinationValidator": "0xCA9bB3fcDfB455962ee284A189CbFc2262970b39", + "SuperExecutor": "0xdC903190CF37993e970aA0b15cCC6e08EA12BCa0", + "SuperLedger": "0x31A3c245C67468A93E6874Dec00A7d3Ac4eF5245", + "SuperLedgerConfiguration": "0x102146454720de58Ee1331F7a91cdCC1F0c346E0", + "SuperNativePaymaster": "0x321093026AA7Ea3d25E69e550C4102d71D82E1cD", + "SuperSenderCreator": "0xEe885bD357B603cdC18239b8036e2510Ed2d1E35", + "SuperValidator": "0x5C563Ba4881e3c2710BABe76282895EfE5C8247d", + "SuperVaultYieldSourceOracle": "0x2339E250Cc72694BFea62C594B267270d728fD2b", + "SuperYieldSourceOracle": "0x03f1d66d67BDacD1d417d884a59733f3Af626c62", + "Swap1InchHook": "0xc785A8a40D449cbd3352853a7B2A514838e07728", + "SwapOdosV2Hook": "0x49774d860b7D3d5B9BdEBD9f8961FDb5B3CeF096", + "SwapUniswapV4Hook": "0x19AEF162cc077d22375e3e072695D9e50e954C12", + "TransferERC20Hook": "0x9379C1cfaA3B660855231387F4F3167fee2cE6b2", + "TransferHook": "0xDDBde23fE91FCFd9E6856B17c4A7eE8F444f74Ea", + "Nexus": "0x10f2Ef78610aB17685656f894c556b568AeF2a35", + "NexusBootstrap": "0x3BF33e679b933446292b95F27186DCDB68492CD0", + "NexusAccountFactory": "0x4fb71F028D424358B27877fb3d9F481cf10D1C63", + "SetSlippageHook": "0xcad65bEC610d0890d94d98Bd16E220f0DC90a90d" + } + }, + "HyperEVM": { + "counter": 0, + "vnet_id": "", + "contracts": { + "AcrossSendFundsAndExecuteOnDstHook": "0x00d601aA01270B1707F2A56511aa64783D2d03BC", + "AcrossV3Adapter": "0x96A56f1f3113eCaDC5848E7B538C800B5dCb68C1", + "ApproveAndAcrossSendFundsAndExecuteOnDstHook": "0x880a2B0B585625D5057a8414998Ba76A33380133", + "ApproveAndDeposit4626VaultHook": "0xdcAfC76B2f777bBA2d1e6C535F73AcA3dBe558F4", + "ApproveAndDeposit5115VaultHook": "0xDc997F44693d865C68d2321E41716Bdc098016ee", + "ApproveAndRequestDeposit7540VaultHook": "0xef56121Af8553C0a534052b6305301E414E79c41", + "ApproveERC20Hook": "0xD3490320fFAE7d38AaaEe4269b4A5c1700f71FDB", + "BatchTransferFromHook": "0x71bF940153Edab9B63B4b813A6D9D21B188EA07a", + "BatchTransferHook": "0x608570eED65750a9cc58bFc6DCbC0cEA25f68458", + "CancelDepositRequest7540Hook": "0xB062CE8f773D8353c1B89C2d175a46c0D489C4e7", + "CancelRedeemRequest7540Hook": "0x2aF3962aE7a3ABE785E33E1c467a2c594777dA1c", + "CircleGatewayAddDelegateHook": "0xC8D6A10ea33b48878137E3332556Ca51D455B7c0", + "CircleGatewayMinterHook": "0x3A2a1281622Aa704a6480D1745702F6F83727521", + "CircleGatewayRemoveDelegateHook": "0xfC02C7Ec6efaF48DdB5E6DB97d7F95Fd3433Ea0C", + "CircleGatewayWalletHook": "0x7Be37FB4Ad39BDe35c5168Df21f3f1E019462510", + "ClaimCancelDepositRequest7540Hook": "0x0B515b1344cb9bAe3205B1c846a9a8C942Ef41b0", + "ClaimCancelRedeemRequest7540Hook": "0xE579aDA69fbB49D0A4d3c6D3f706a74f8CFc4989", + "DeBridgeCancelOrderHook": "0x8A6bc4bA5e6E4330f8f1bE93fe27CC5dd4a3B53c", + "DeBridgeSendOrderAndExecuteOnDstHook": "0x48A5f8319F4a9340D2D2190E03EFa60b262Dd7ae", + "DebridgeAdapter": "0x09158270738CDdF351Eaa88eF888B23301D21C05", + "Deposit4626VaultHook": "0xe3FFf64A14A38a5b082502779ae6f6a9a273b02C", + "Deposit5115VaultHook": "0x153B77421C844005C9af67cCA8A0469F814e10f8", + "Deposit7540VaultHook": "0xBDF724DA1928988F2891B9B565460161968Fc9d7", + "ERC4626YieldSourceOracle": "0x693E5364A5f95Be378eD44e27b62374d24Af6DF0", + "ERC5115YieldSourceOracle": "0x5F255eBDF9456EBF8dDe43C38b11D32d161e7300", + "EthenaCooldownSharesHook": "0xA1BD126da3d2830fe19eA93c0872aF433B7c04f7", + "EthenaUnstakeHook": "0xC836797f7b7f645248b73938d0bD2Ab2dc6A9337", + "FlatFeeLedger": "0xb989FC825C8C77fbE84b69082048372d548f6FeF", + "MarkRootAsUsedHook": "0x2a655fDfCA2113AD755F81dFf941b54919d0544d", + "MerklClaimRewardHook": "0x67CcC575D4064418406AE70cC094781837D01777", + "OfframpTokensHook": "0x45769A1252B26976896533664454b6e295b88266", + "PendlePTYieldSourceOracle": "0x5456333427e671072F77F68E90E3A7d89Cc996Aa", + "PendleRouterRedeemHook": "0x94E7D358e8BAB5fEFb53d20C2D261A579898Eab6", + "PendleRouterSwapHook": "0xB6894368ffB77a46bE4C8EcAF20f29Cd9219301D", + "PendleUnifiedHook": "0xbc7F29336BD315A32f537dCD8e1aA9efF66b73A3", + "Redeem4626VaultHook": "0xB10b1fCE2E4B24C5A988A9932d4Cf9DB37Ba0394", + "Redeem5115VaultHook": "0x421aE0BB3C201959D0B152a87d56BCdB2Ee1cF63", + "Redeem7540VaultHook": "0xCa50aB0375b774B2DE12919423Dd0B8e8cAad95f", + "RequestDeposit7540VaultHook": "0x01Af8d98DDA6310D8aE91af7439E1b5836ad3d9c", + "RequestRedeem7540VaultHook": "0xd9f7c658d3ec52E02e4402fE87e48A36cb9E0dC0", + "SetOperator7540Hook": "0xa31E5013096efE9bDfd590275d80fe724AD269BC", + "SetSlippageHook": "0xcad65bEC610d0890d94d98Bd16E220f0DC90a90d", + "SpectraPTYieldSourceOracle": "0xBb9154D1a9c06047D4AD5721eAEd874Ee125f4E3", + "StakingYieldSourceOracle": "0x0737eB8db2992b13a66b46E8226F36d774CA2A02", + "SuperDestinationExecutor": "0xd0B5d200a6B136D619Dd1c7BBA30b004b4773C40", + "SuperDestinationValidator": "0xCA9bB3fcDfB455962ee284A189CbFc2262970b39", + "SuperExecutor": "0xdC903190CF37993e970aA0b15cCC6e08EA12BCa0", + "SuperLedger": "0x31A3c245C67468A93E6874Dec00A7d3Ac4eF5245", + "SuperLedgerConfiguration": "0x102146454720de58Ee1331F7a91cdCC1F0c346E0", + "SuperNativePaymaster": "0x321093026AA7Ea3d25E69e550C4102d71D82E1cD", + "SuperSenderCreator": "0xEe885bD357B603cdC18239b8036e2510Ed2d1E35", + "SuperValidator": "0x5C563Ba4881e3c2710BABe76282895EfE5C8247d", + "SuperVaultYieldSourceOracle": "0x2339E250Cc72694BFea62C594B267270d728fD2b", + "SuperYieldSourceOracle": "0x03f1d66d67BDacD1d417d884a59733f3Af626c62", + "TransferERC20Hook": "0x9379C1cfaA3B660855231387F4F3167fee2cE6b2", + "TransferHook": "0xDDBde23fE91FCFd9E6856B17c4A7eE8F444f74Ea", + "SuperGovernor": "0x0370F5F5f1a63688b16c60D59B19C7469ddb3D6b", + "SuperVault": "0xB2fA782406453Fb345cDD7f2c3586003A3FE2bBB", + "SuperVaultAggregator": "0xB383D4063d67F5452Df3e8A7C0062Eabc4049728", + "SuperVaultStrategy": "0xaE15a0Cec3ef44843E7A88e0E5FA7A7527e6BC73", + "SuperVaultEscrow": "0xC961bd0356b2318820bf79Fe21D23269A42B8863", + "SuperVaultBatchOperator": "0x3D0e34316f3deF7bce5fDEBC7083E6eE4E088AC6", + "ECDSAPPSOracle": "0x68718f31849f266dF64df08320776a39f06efaBd", + "FixedPriceOracle": "0xb1E823c84e4aa9Ca38e2f82d3131412254099197", + "SuperOracle": "0xdEd271fA2a90e7e6A40AF92Ad38eBd3EB78F7675", + "SuperBank": "0x69d53e376264EEb567213f07d8136050f99eeeC0", + "PendlePTAmortizedOracle": "0xE31FD1d26A52B4a958651a8E751e9362B3880524", + "PendlePTAmortizedOracleV2": "0x1F32A55b20Ee7bA0bC083671c7723dBA1608D66e" + } + } + }, + "updated_at": "2026-02-17T17:07:50Z" +} diff --git a/script/run/add_hooks_to_governor_staging_prod.sh b/script/run/add_hooks_to_governor_staging_prod.sh index d7af7acb4..21642eb0e 100755 --- a/script/run/add_hooks_to_governor_staging_prod.sh +++ b/script/run/add_hooks_to_governor_staging_prod.sh @@ -35,6 +35,28 @@ set -euo pipefail # Exit on error, undefined var, pipe failure +################################################################################### +# Network Filter Configuration +################################################################################### + +# Networks to SKIP (these are already configured) +# Comment out networks you want to configure +SKIP_NETWORKS=( + "1" # Ethereum - already configured + "8453" # Base - already configured +) + +# Function to check if a network should be skipped +should_skip_network() { + local network_id=$1 + for skip_id in "${SKIP_NETWORKS[@]}"; do + if [ "$network_id" = "$skip_id" ]; then + return 0 # Should skip + fi + done + return 1 # Should not skip +} + ################################################################################### # Script Configuration ################################################################################### @@ -220,16 +242,31 @@ read_merged_state_from_local() { check_supergovernor_exists() { local merged_state_file=$1 local network_name=$2 + local network_id=$3 + local environment=$4 local governor_addr + + # First, try to get from merged state file governor_addr=$(jq -r ".networks[\"$network_name\"].contracts.SuperGovernor // empty" "$merged_state_file" 2>/dev/null) if [ -n "$governor_addr" ] && [ "$governor_addr" != "null" ]; then echo "$governor_addr" return 0 - else - return 1 fi + + # Fallback: try to read from individual chain output file + local individual_file="$SCRIPT_DIR/../output/$environment/$network_id/$network_name-latest.json" + if [ -f "$individual_file" ]; then + governor_addr=$(jq -r '.SuperGovernor // empty' "$individual_file" 2>/dev/null) + if [ -n "$governor_addr" ] && [ "$governor_addr" != "null" ]; then + log "INFO" "Found SuperGovernor in individual output file: $individual_file" + echo "$governor_addr" + return 0 + fi + fi + + return 1 } # Load RPC URLs from credential manager @@ -351,10 +388,24 @@ configure_all_networks() { return 1 fi + # Display skip list + if [ ${#SKIP_NETWORKS[@]} -gt 0 ]; then + log "INFO" "Networks to skip: ${SKIP_NETWORKS[*]}" + log "INFO" "(Edit SKIP_NETWORKS in script to change)" + fi + # Process each network for network_id in $supported_network_ids; do total_count=$((total_count + 1)) + # Check if network should be skipped + if should_skip_network "$network_id"; then + local skip_network_name=$(get_network_name "$network_id" 2>/dev/null || echo "Unknown") + log "INFO" "SKIP: $skip_network_name (Chain ID: $network_id) - in SKIP_NETWORKS list" + skipped_count=$((skipped_count + 1)) + continue + fi + # Get network name local network_name=$(get_network_name "$network_id") if [ $? -ne 0 ]; then @@ -370,7 +421,7 @@ configure_all_networks() { # Check if SuperGovernor exists for this network local governor_addr - if ! governor_addr=$(check_supergovernor_exists "$merged_state_file" "$network_name"); then + if ! governor_addr=$(check_supergovernor_exists "$merged_state_file" "$network_name" "$network_id" "$environment"); then log "WARNING" "SuperGovernor not found for $network_name - skipping" log "WARNING" "Make sure periphery contracts have been deployed and merged" skipped_count=$((skipped_count + 1)) diff --git a/script/run/configure_governor_addresses_staging_prod.sh b/script/run/configure_governor_addresses_staging_prod.sh new file mode 100755 index 000000000..71c31e21f --- /dev/null +++ b/script/run/configure_governor_addresses_staging_prod.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +################################################################################### +# Configure SuperGovernor Core Addresses Script +################################################################################### +# Description: +# This script registers core contract addresses (SUPER_VAULT_AGGREGATOR, +# SUPER_ORACLE, SUPER_BANK) in SuperGovernor after deployment. +# +# Use this when the deployment script exits early because all contracts are +# already deployed, but the configuration step was never run. +# +# Usage: +# ./configure_governor_addresses_staging_prod.sh [account] +# +# Examples: +# ./configure_governor_addresses_staging_prod.sh staging simulate +# ./configure_governor_addresses_staging_prod.sh prod configure v2 +################################################################################### + +set -euo pipefail + +# ===== NETWORK FILTER CONFIGURATION ===== +# Networks to SKIP (these are already configured) +# Comment out networks you want to configure +SKIP_NETWORKS=( + "1" # Ethereum - already configured + "8453" # Base - already configured +) + +# Function to check if a network should be skipped +should_skip_network() { + local network_id=$1 + for skip_id in "${SKIP_NETWORKS[@]}"; do + if [ "$network_id" = "$skip_id" ]; then + return 0 # Should skip + fi + done + return 1 # Should not skip +} + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +NC='\033[0m' + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +print_header() { + echo -e "${CYAN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${WHITE} Configure SuperGovernor Core Addresses ${CYAN}║${NC}" + echo -e "${CYAN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" +} + +print_header + +# Check arguments +if [ $# -lt 2 ]; then + echo -e "${RED}Usage: $0 [account]${NC}" + echo -e "${CYAN} environment: staging or prod${NC}" + echo -e "${CYAN} mode: simulate or configure${NC}" + echo -e "${CYAN} account: foundry account (required for configure mode)${NC}" + exit 1 +fi + +ENVIRONMENT=$1 +MODE=$2 +ACCOUNT="${3:-}" + +# Validate environment +if [ "$ENVIRONMENT" = "staging" ]; then + echo -e "${CYAN}Loading staging network configuration...${NC}" + source "$SCRIPT_DIR/networks-staging.sh" + FORGE_ENV=2 +elif [ "$ENVIRONMENT" = "prod" ]; then + echo -e "${CYAN}Loading production network configuration...${NC}" + source "$SCRIPT_DIR/networks-production.sh" + FORGE_ENV=0 +else + echo -e "${RED}Invalid environment: $ENVIRONMENT${NC}" + exit 1 +fi + +# Set up forge flags +if [ "$MODE" = "simulate" ]; then + echo -e "${YELLOW}Running in SIMULATION mode (no broadcast)${NC}" + BROADCAST_FLAG="" + SENDER_FLAG="--sender 0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" + ACCOUNT_FLAG="" +elif [ "$MODE" = "configure" ]; then + if [ -z "$ACCOUNT" ]; then + echo -e "${RED}Account required for configure mode${NC}" + exit 1 + fi + echo -e "${GREEN}Running in CONFIGURE mode (will broadcast)${NC}" + BROADCAST_FLAG="--broadcast" + SENDER_FLAG="" + ACCOUNT_FLAG="--account $ACCOUNT" +else + echo -e "${RED}Invalid mode: $MODE${NC}" + exit 1 +fi + +# Load RPC URLs +echo -e "${CYAN}Loading RPC URLs...${NC}" +if ! load_rpc_urls; then + echo -e "${RED}Failed to load RPC URLs${NC}" + exit 1 +fi + +cd "$PROJECT_ROOT" + +echo "" +echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + +# Display skip list +if [ ${#SKIP_NETWORKS[@]} -gt 0 ]; then + echo -e "${YELLOW}Networks to skip: ${SKIP_NETWORKS[*]}${NC}" + echo -e "${CYAN}(Edit SKIP_NETWORKS in script to change)${NC}" +fi +echo "" + +# Configure each network +for network_def in "${NETWORKS[@]}"; do + IFS=':' read -r network_id network_name rpc_var <<< "$network_def" + + # Check if network should be skipped + if should_skip_network "$network_id"; then + echo -e "${YELLOW}SKIP: $network_name (Chain ID: $network_id) - in SKIP_NETWORKS list${NC}" + continue + fi + + echo -e "${CYAN}Configuring SuperGovernor on $network_name (Chain ID: $network_id)...${NC}" + + rpc_url="${!rpc_var}" + if [ -z "$rpc_url" ]; then + echo -e "${RED} RPC URL not set for $network_name, skipping${NC}" + continue + fi + + # Skip etherscan verification for HyperEVM + VERIFY_FLAGS="" + SLOW_FLAG="" + if [ "$network_id" = "999" ]; then + SLOW_FLAG="--slow" + fi + + if forge script script/ConfigureGovernorAddresses.s.sol:ConfigureGovernorAddresses \ + --sig 'run(uint256,uint64)' $FORGE_ENV $network_id \ + --rpc-url "$rpc_url" \ + --chain $network_id \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + $SLOW_FLAG \ + -vvv; then + echo -e "${GREEN}✅ Successfully configured $network_name${NC}" + else + echo -e "${RED}❌ Failed to configure $network_name${NC}" + fi + + echo "" +done + +echo -e "${GREEN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}║${WHITE} Configuration Complete ${GREEN}║${NC}" +echo -e "${GREEN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" diff --git a/script/run/configure_hyperevm_from_ethbase.sh b/script/run/configure_hyperevm_from_ethbase.sh new file mode 100755 index 000000000..50682f919 --- /dev/null +++ b/script/run/configure_hyperevm_from_ethbase.sh @@ -0,0 +1,330 @@ +#!/usr/bin/env bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +NC='\033[0m' + +################################################################################### +# Fireblocks Configuration +################################################################################### +FIREBLOCKS_POLLING_INTERVAL_MS=5000 +FIREBLOCKS_TX_TIMEOUT_SECONDS=300 + +print_header() { + echo -e "${CYAN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${WHITE} 🔧 Configure ETH/Base -> HyperEVM (Fireblocks Wallet Required) 🔧 ${CYAN}║${NC}" + echo -e "${CYAN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" +} + +print_separator() { + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +} + +################################################################################### +# Fireblocks Helpers +################################################################################### + +load_fireblocks_credentials() { + echo -e "${CYAN} • Loading Fireblocks credentials from 1Password...${NC}" + + if [ -z "${FIREBLOCKS_API_KEY_OP_PATH:-}" ]; then + echo -e "${RED}❌ FIREBLOCKS_API_KEY_OP_PATH not set${NC}" + echo -e "${YELLOW}Set the 1Password path for the Fireblocks API key${NC}" + exit 1 + fi + if [ -z "${FIREBLOCKS_SECRET_OP_PATH:-}" ]; then + echo -e "${RED}❌ FIREBLOCKS_SECRET_OP_PATH not set${NC}" + echo -e "${YELLOW}Set the 1Password path for the Fireblocks private key${NC}" + exit 1 + fi + + export FIREBLOCKS_API_KEY=$(op read "$FIREBLOCKS_API_KEY_OP_PATH" 2>/dev/null || echo "") + export FIREBLOCKS_API_PRIVATE_KEY_PATH=$(op read "$FIREBLOCKS_SECRET_OP_PATH" 2>/dev/null || echo "") + + if [ -n "${FIREBLOCKS_VAULT_ID:-}" ]; then + export FIREBLOCKS_VAULT_ACCOUNT_IDS="$FIREBLOCKS_VAULT_ID" + fi + + if [ -z "$FIREBLOCKS_API_KEY" ]; then + echo -e "${RED}❌ Failed to load Fireblocks API key from 1Password${NC}" + echo -e "${YELLOW}Path: $FIREBLOCKS_API_KEY_OP_PATH${NC}" + exit 1 + fi + if [ -z "$FIREBLOCKS_API_PRIVATE_KEY_PATH" ]; then + echo -e "${RED}❌ Failed to load Fireblocks private key from 1Password${NC}" + echo -e "${YELLOW}Path: $FIREBLOCKS_SECRET_OP_PATH${NC}" + exit 1 + fi + + echo -e "${GREEN} ✅ Fireblocks credentials loaded (API key: ${FIREBLOCKS_API_KEY:0:8}...)${NC}" +} + +# Run a forge script via Fireblocks (execute) or directly (simulate) +# Arguments: $1=sig $2=args $3=rpc_url $4=chain_id +fireblocks_forge() { + local sig=$1 + local args=$2 + local rpc_url=$3 + local chain_id=$4 + + if [ "$MODE" = "simulate" ]; then + forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig "$sig" $args \ + --rpc-url "$rpc_url" \ + --chain "$chain_id" \ + --sender "$SENDER_ADDRESS" \ + -vvv + else + local tx_hash=$(echo -n "configure_hyperevm:${sig}:${chain_id}:${SENDER_ADDRESS}:$(date +%Y%m%d)" | openssl dgst -md5 | sed 's/.*= //' | head -c 16) + local tx_id="up-oft-hyperevm-${chain_id}-${tx_hash}" + + echo -e "${CYAN} Fireblocks TX ID: $tx_id${NC}" + + fireblocks-json-rpc --http \ + --pollingInterval "$FIREBLOCKS_POLLING_INTERVAL_MS" \ + --externalTxId "$tx_id" \ + -- forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig "$sig" $args \ + --sender "$SENDER_ADDRESS" \ + --rpc-url {} \ + --broadcast \ + --unlocked \ + --timeout "$FIREBLOCKS_TX_TIMEOUT_SECONDS" \ + -vvv + fi +} + +################################################################################### +# Main Script +################################################################################### + +print_header + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +if [ $# -lt 3 ]; then + echo -e "${RED}❌ Error: Missing required arguments${NC}" + echo -e "${YELLOW}Usage: $0 ${NC}" + echo -e "${CYAN} environment: staging or prod${NC}" + echo -e "${CYAN} mode: simulate or execute${NC}" + echo -e "${CYAN} sender-address: address of the Fireblocks wallet that owns ETH/Base OFTs${NC}" + echo "" + echo -e "${CYAN}Required env vars for execute mode:${NC}" + echo -e "${CYAN} FIREBLOCKS_API_KEY_OP_PATH - 1Password path for Fireblocks API key${NC}" + echo -e "${CYAN} FIREBLOCKS_SECRET_OP_PATH - 1Password path for Fireblocks private key${NC}" + echo -e "${CYAN} FIREBLOCKS_VAULT_ID - Fireblocks vault account ID (optional)${NC}" + echo "" + echo -e "${CYAN}Examples:${NC}" + echo -e "${CYAN} $0 staging simulate 0x1234...abcd${NC}" + echo -e "${CYAN} FIREBLOCKS_API_KEY_OP_PATH=\"op://vault/item/field\" \\\\${NC}" + echo -e "${CYAN} FIREBLOCKS_SECRET_OP_PATH=\"op://vault/item/field\" \\\\${NC}" + echo -e "${CYAN} $0 prod execute 0x1234...abcd${NC}" + exit 1 +fi + +ENVIRONMENT=$1 +MODE=$2 +SENDER_ADDRESS=$3 + +if [ "$ENVIRONMENT" != "staging" ] && [ "$ENVIRONMENT" != "prod" ]; then + echo -e "${RED}❌ Invalid environment: $ENVIRONMENT${NC}" + echo -e "${YELLOW}Environment must be either 'staging' or 'prod'${NC}" + exit 1 +fi + +if [ "$MODE" != "simulate" ] && [ "$MODE" != "execute" ]; then + echo -e "${RED}❌ Invalid mode: $MODE${NC}" + echo -e "${YELLOW}Mode must be either 'simulate' or 'execute'${NC}" + exit 1 +fi + +if ! echo "$SENDER_ADDRESS" | grep -qE '^0x[0-9a-fA-F]{40}$'; then + echo -e "${RED}❌ Invalid sender address: $SENDER_ADDRESS${NC}" + echo -e "${YELLOW}Must be a valid 0x-prefixed Ethereum address${NC}" + exit 1 +fi + +echo -e "${GREEN} ✅ Sender address: $SENDER_ADDRESS${NC}" + +print_separator +echo -e "${BLUE}🔧 Loading Configuration...${NC}" + +echo -e "${CYAN} • Loading RPC URLs from 1Password...${NC}" +if ! export ETH_MAINNET=$(op read op://5ylebqljbh3x6zomdxi3qd7tsa/ETHEREUM_RPC_URL/credential 2>/dev/null); then + echo -e "${RED}❌ Failed to load ETHEREUM_RPC_URL from 1Password${NC}" + exit 1 +fi +echo -e "${GREEN} ✅ Ethereum RPC loaded${NC}" + +if ! export BASE_MAINNET=$(op read op://5ylebqljbh3x6zomdxi3qd7tsa/BASE_RPC_URL/credential 2>/dev/null); then + echo -e "${RED}❌ Failed to load BASE_RPC_URL from 1Password${NC}" + exit 1 +fi +echo -e "${GREEN} ✅ Base RPC loaded${NC}" + +# Satisfy foundry.toml [etherscan] env var references (resolved eagerly by forge on startup) +export ETHERSCANV2_API_KEY_TEST="${ETHERSCANV2_API_KEY_TEST:-}" + +if [ "$ENVIRONMENT" = "staging" ]; then + FORGE_ENV=2 + ENV_NAME="staging" +elif [ "$ENVIRONMENT" = "prod" ]; then + FORGE_ENV=0 + ENV_NAME="prod" +fi + +echo -e "${CYAN} • Loading HyperEVM OFT address from deployment output...${NC}" +HYPEREVM_OFT_JSON="$PROJECT_ROOT/script/output/$ENV_NAME/999/UpOFT-latest.json" +if [ ! -f "$HYPEREVM_OFT_JSON" ]; then + echo -e "${RED}❌ HyperEVM OFT deployment output not found: $HYPEREVM_OFT_JSON${NC}" + echo -e "${YELLOW}Run deploy_up_oft_hyperevm.sh first to deploy and export addresses${NC}" + exit 1 +fi +HYPEREVM_OFT_ADDRESS=$(jq -r '.UpOFT' "$HYPEREVM_OFT_JSON" 2>/dev/null) +if [ -z "$HYPEREVM_OFT_ADDRESS" ] || [ "$HYPEREVM_OFT_ADDRESS" = "null" ]; then + echo -e "${RED}❌ Could not read UpOFT address from $HYPEREVM_OFT_JSON${NC}" + exit 1 +fi +if ! echo "$HYPEREVM_OFT_ADDRESS" | grep -qE '^0x[0-9a-fA-F]{40}$'; then + echo -e "${RED}❌ Invalid HyperEVM OFT address in JSON: $HYPEREVM_OFT_ADDRESS${NC}" + exit 1 +fi +echo -e "${GREEN} ✅ HyperEVM OFT address: $HYPEREVM_OFT_ADDRESS${NC}" + +# Load Fireblocks credentials for execute mode +if [ "$MODE" = "execute" ]; then + load_fireblocks_credentials +fi + +echo -e "${GREEN}✅ Configuration loaded successfully${NC}" +echo -e "${CYAN} • Environment: $ENVIRONMENT (env=$FORGE_ENV)${NC}" +echo -e "${CYAN} • Sender: $SENDER_ADDRESS${NC}" +echo -e "${CYAN} • HyperEVM OFT: $HYPEREVM_OFT_ADDRESS${NC}" + +cd "$PROJECT_ROOT" + +print_separator + +if [ "$MODE" = "execute" ]; then + echo -e "${YELLOW}⚠️ CONFIGURATION CONFIRMATION REQUIRED ⚠️${NC}" + echo -e "${CYAN}You are about to configure ETH/Base -> HyperEVM pathways:${NC}" + echo -e "${CYAN} • Environment: ${WHITE}$ENVIRONMENT${NC}" + echo -e "${CYAN} • Sender (Fireblocks): ${WHITE}$SENDER_ADDRESS${NC}" + echo -e "${CYAN} • HyperEVM OFT: ${WHITE}$HYPEREVM_OFT_ADDRESS${NC}" + echo -e "${CYAN} • Steps:${NC}" + echo -e "${CYAN} 1. Configure peer on Ethereum -> HyperEVM${NC}" + echo -e "${CYAN} 2. Configure peer on Base -> HyperEVM${NC}" + echo -e "${CYAN} 3. Set enforced options on Ethereum for HyperEVM${NC}" + echo -e "${CYAN} 4. Set enforced options on Base for HyperEVM${NC}" + echo -e "${CYAN} 5. Configure libraries on Ethereum for HyperEVM${NC}" + echo -e "${CYAN} 6. Configure libraries on Base for HyperEVM${NC}" + echo "" + read -p "$(echo -e ${YELLOW}Type \"CONFIGURE\" to continue or anything else to abort: ${NC})" confirmation + if [ "$confirmation" != "CONFIGURE" ]; then + echo -e "${RED}❌ Configuration aborted by user${NC}" + exit 1 + fi + echo -e "${GREEN}✅ Configuration confirmed${NC}" + print_separator +fi + +echo -e "${BLUE}🔧 Configuring peer on Ethereum for HyperEVM...${NC}" +fireblocks_forge \ + 'configurePeerOnEthereumForHyperEVM(uint256,address)' \ + "$FORGE_ENV $HYPEREVM_OFT_ADDRESS" \ + "$ETH_MAINNET" \ + 1 +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure peer on Ethereum for HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Ethereum peer configured for HyperEVM${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring peer on Base for HyperEVM...${NC}" +fireblocks_forge \ + 'configurePeerOnBaseForHyperEVM(uint256,address)' \ + "$FORGE_ENV $HYPEREVM_OFT_ADDRESS" \ + "$BASE_MAINNET" \ + 8453 +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure peer on Base for HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Base peer configured for HyperEVM${NC}" + +print_separator + +echo -e "${BLUE}🔧 Setting enforced options on Ethereum for HyperEVM...${NC}" +fireblocks_forge \ + 'setEnforcedOptionsOnEthereumForHyperEVM(uint256)' \ + "$FORGE_ENV" \ + "$ETH_MAINNET" \ + 1 +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to set enforced options on Ethereum for HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Ethereum enforced options set for HyperEVM${NC}" + +print_separator + +echo -e "${BLUE}🔧 Setting enforced options on Base for HyperEVM...${NC}" +fireblocks_forge \ + 'setEnforcedOptionsOnBaseForHyperEVM(uint256)' \ + "$FORGE_ENV" \ + "$BASE_MAINNET" \ + 8453 +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to set enforced options on Base for HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Base enforced options set for HyperEVM${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring libraries on Ethereum for HyperEVM...${NC}" +fireblocks_forge \ + 'configureLibrariesOnEthereumForHyperEVM(uint256)' \ + "$FORGE_ENV" \ + "$ETH_MAINNET" \ + 1 +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure libraries on Ethereum for HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Ethereum libraries configured for HyperEVM${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring libraries on Base for HyperEVM...${NC}" +fireblocks_forge \ + 'configureLibrariesOnBaseForHyperEVM(uint256)' \ + "$FORGE_ENV" \ + "$BASE_MAINNET" \ + 8453 +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure libraries on Base for HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Base libraries configured for HyperEVM${NC}" + +print_separator + +echo -e "${GREEN}🎉 ETH/Base -> HyperEVM Configuration Complete!${NC}" +echo -e "${CYAN} • Ethereum -> HyperEVM peer configured${NC}" +echo -e "${CYAN} • Base -> HyperEVM peer configured${NC}" +echo -e "${CYAN} • Ethereum -> HyperEVM enforced options set${NC}" +echo -e "${CYAN} • Base -> HyperEVM enforced options set${NC}" +echo -e "${CYAN} • Ethereum -> HyperEVM libraries + ULN/DVN configured${NC}" +echo -e "${CYAN} • Base -> HyperEVM libraries + ULN/DVN configured${NC}" +echo "" +echo -e "${GREEN}🔗 Bidirectional configuration is now complete:${NC}" +echo -e "${CYAN} • ETH <-> HyperEVM${NC}" +echo -e "${CYAN} • Base <-> HyperEVM${NC}" diff --git a/script/run/configure_hyperevm_lz_endpoint.sh b/script/run/configure_hyperevm_lz_endpoint.sh new file mode 100755 index 000000000..2f4784b0f --- /dev/null +++ b/script/run/configure_hyperevm_lz_endpoint.sh @@ -0,0 +1,299 @@ +#!/usr/bin/env bash + +################################################################################### +# Configure HyperEVM LZ Endpoint (TX 3-6) +################################################################################### +# Description: +# Configures LayerZero Endpoint for ETH/Base -> HyperEVM OFT pathways. +# These are TX 3-6 from the full configuration: +# - TX 3: setSendLibrary +# - TX 4: setReceiveLibrary +# - TX 5: setConfig (SendLib - Executor + ULN) +# - TX 6: setConfig (ReceiveLib - ULN only) +# +# NOTE: TX 1-2 (setPeer, setEnforcedOptions) require the OFT owner (MPC wallet) +# and must be executed separately via Etherscan/Basescan with Porto. +# +# Authorization: +# These transactions can be executed by the DELEGATE (deployer address). +# Current delegate for both OFTs: 0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8 +# +# Usage: +# ./configure_hyperevm_lz_endpoint.sh [account] [chain] +# +# Parameters: +# mode: "simulate" or "execute" +# account: Account name (required for execute mode, e.g., "v2-supervaults") +# chain: Optional - "eth", "base", or "all" (default: all) +# +# Examples: +# # Simulate on all chains +# ./configure_hyperevm_lz_endpoint.sh simulate +# +# # Simulate on Ethereum only +# ./configure_hyperevm_lz_endpoint.sh simulate "" eth +# +# # Simulate on Base only +# ./configure_hyperevm_lz_endpoint.sh simulate "" base +# +# # Execute on all chains +# ./configure_hyperevm_lz_endpoint.sh execute v2-supervaults +# +# # Execute on Ethereum only +# ./configure_hyperevm_lz_endpoint.sh execute v2-supervaults eth +# +# Prerequisites: +# - For execute mode: Foundry account (v2-supervaults) configured +# +# Author: Superform Team +################################################################################### + +set -euo pipefail + +################################################################################### +# Constants +################################################################################### + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +# Deployer address (delegate for LZ Endpoint calls) +readonly DEPLOYER="0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" + +# RPC URLs (using public endpoints) +readonly ETH_RPC_URL="https://ethereum-rpc.publicnode.com" +readonly BASE_RPC_URL="https://base-rpc.publicnode.com" + +################################################################################### +# Helper Functions +################################################################################### + +log() { + local level=$1 + shift + echo "[$(date +'%Y-%m-%d %H:%M:%S')] [$level] $*" >&2 +} + +usage() { + cat << EOF +Usage: $0 [account] [chain] + +Arguments: + mode Mode: "simulate" or "execute" (required) + account Account name (required for execute mode, e.g., "v2-supervaults") + chain Chain to configure: "eth", "base", or "all" (default: all) + +Examples: + # Simulate on all chains + $0 simulate + + # Simulate on Ethereum only + $0 simulate "" eth + + # Simulate on Base only + $0 simulate "" base + + # Execute on all chains + $0 execute v2-supervaults + + # Execute on Ethereum only + $0 execute v2-supervaults eth + +EOF + exit 1 +} + +validate_mode() { + local mode=$1 + if [ "$mode" != "simulate" ] && [ "$mode" != "execute" ]; then + log "ERROR" "Invalid mode: $mode" + log "ERROR" "Must be 'simulate' or 'execute'" + exit 1 + fi +} + +validate_chain() { + local chain=$1 + if [ "$chain" != "eth" ] && [ "$chain" != "base" ] && [ "$chain" != "all" ]; then + log "ERROR" "Invalid chain: $chain" + log "ERROR" "Must be 'eth', 'base', or 'all'" + exit 1 + fi +} + +################################################################################### +# Configuration Functions +################################################################################### + +configure_ethereum() { + local mode=$1 + local account=$2 + + log "INFO" "============================================" + log "INFO" "Configuring Ethereum -> HyperEVM pathway" + log "INFO" "============================================" + + local BROADCAST_FLAG="" + local SENDER_FLAG="" + local ACCOUNT_FLAG="" + + if [ "$mode" = "execute" ]; then + BROADCAST_FLAG="--broadcast" + ACCOUNT_FLAG="--account $account" + log "INFO" "Mode: Execute (will broadcast using account: $account)" + else + SENDER_FLAG="--sender $DEPLOYER" + log "INFO" "Mode: Simulate (no broadcast, using sender: $DEPLOYER)" + fi + + local forge_cmd="forge script" + forge_cmd+=" script/ConfigureHyperEVMLZEndpoint.s.sol:ConfigureHyperEVMLZEndpointETH" + forge_cmd+=" --rpc-url $ETH_RPC_URL" + forge_cmd+=" --chain 1" + [ -n "$ACCOUNT_FLAG" ] && forge_cmd+=" $ACCOUNT_FLAG" + [ -n "$SENDER_FLAG" ] && forge_cmd+=" $SENDER_FLAG" + [ -n "$BROADCAST_FLAG" ] && forge_cmd+=" $BROADCAST_FLAG" + forge_cmd+=" -vvv" + + log "INFO" "Executing forge script..." + log "INFO" "" + + local exit_code=0 + eval "$forge_cmd" || exit_code=$? + + if [ $exit_code -ne 0 ]; then + log "ERROR" "Ethereum configuration failed with exit code: $exit_code" + return $exit_code + fi + + log "INFO" "Ethereum configuration successful!" + return 0 +} + +configure_base() { + local mode=$1 + local account=$2 + + log "INFO" "============================================" + log "INFO" "Configuring Base -> HyperEVM pathway" + log "INFO" "============================================" + + local BROADCAST_FLAG="" + local SENDER_FLAG="" + local ACCOUNT_FLAG="" + + if [ "$mode" = "execute" ]; then + BROADCAST_FLAG="--broadcast" + ACCOUNT_FLAG="--account $account" + log "INFO" "Mode: Execute (will broadcast using account: $account)" + else + SENDER_FLAG="--sender $DEPLOYER" + log "INFO" "Mode: Simulate (no broadcast, using sender: $DEPLOYER)" + fi + + local forge_cmd="forge script" + forge_cmd+=" script/ConfigureHyperEVMLZEndpoint.s.sol:ConfigureHyperEVMLZEndpointBase" + forge_cmd+=" --rpc-url $BASE_RPC_URL" + forge_cmd+=" --chain 8453" + [ -n "$ACCOUNT_FLAG" ] && forge_cmd+=" $ACCOUNT_FLAG" + [ -n "$SENDER_FLAG" ] && forge_cmd+=" $SENDER_FLAG" + [ -n "$BROADCAST_FLAG" ] && forge_cmd+=" $BROADCAST_FLAG" + forge_cmd+=" -vvv" + + log "INFO" "Executing forge script..." + log "INFO" "" + + local exit_code=0 + eval "$forge_cmd" || exit_code=$? + + if [ $exit_code -ne 0 ]; then + log "ERROR" "Base configuration failed with exit code: $exit_code" + return $exit_code + fi + + log "INFO" "Base configuration successful!" + return 0 +} + +################################################################################### +# Main +################################################################################### + +main() { + if [ $# -lt 1 ]; then + log "ERROR" "Missing required arguments" + usage + fi + + local mode="$1" + local account="${2:-}" + local chain="${3:-all}" + + validate_mode "$mode" + validate_chain "$chain" + + # Validate account for execute mode + if [ "$mode" = "execute" ]; then + if [ -z "$account" ]; then + log "ERROR" "Account name is required for execute mode" + log "ERROR" "Usage: $0 execute [chain]" + exit 1 + fi + log "INFO" "Using account: $account" + fi + + log "INFO" "============================================" + log "INFO" "HyperEVM LZ Endpoint Configuration (TX 3-6)" + log "INFO" "============================================" + log "INFO" "Mode: $mode" + log "INFO" "Chain(s): $chain" + log "INFO" "Delegate: $DEPLOYER" + log "INFO" "" + + local eth_result=0 + local base_result=0 + + # Configure based on chain selection + if [ "$chain" = "eth" ] || [ "$chain" = "all" ]; then + configure_ethereum "$mode" "$account" || eth_result=$? + echo "" + fi + + if [ "$chain" = "base" ] || [ "$chain" = "all" ]; then + configure_base "$mode" "$account" || base_result=$? + echo "" + fi + + # Summary + log "INFO" "============================================" + log "INFO" "Summary" + log "INFO" "============================================" + + if [ "$chain" = "eth" ] || [ "$chain" = "all" ]; then + if [ $eth_result -eq 0 ]; then + log "INFO" "Ethereum: SUCCESS" + else + log "ERROR" "Ethereum: FAILED" + fi + fi + + if [ "$chain" = "base" ] || [ "$chain" = "all" ]; then + if [ $base_result -eq 0 ]; then + log "INFO" "Base: SUCCESS" + else + log "ERROR" "Base: FAILED" + fi + fi + + log "INFO" "" + log "INFO" "NOTE: TX 1-2 (setPeer, setEnforcedOptions) must be executed" + log "INFO" " separately via Porto wallet on Etherscan/Basescan." + log "INFO" " See: docs/HyperEVM_Configuration_Calldata.md" + + # Return failure if any chain failed + if [ $eth_result -ne 0 ] || [ $base_result -ne 0 ]; then + exit 1 + fi +} + +main "$@" diff --git a/script/run/deploy_superform_gas_oracle.sh b/script/run/deploy_superform_gas_oracle.sh index 4cb8556c7..849c28399 100644 --- a/script/run/deploy_superform_gas_oracle.sh +++ b/script/run/deploy_superform_gas_oracle.sh @@ -3,44 +3,35 @@ ################################################################################### # Deploy SuperformGasOracle Script ################################################################################### -# Description: -# Deploys SuperformGasOracle - a keeper-updated gas price oracle for Base chain -# where Chainlink's Fast Gas feed is not available. +# +# Deploys SuperformGasOracle on HyperEVM (999). +# +# This oracle provides keeper-updated gas prices for chains where Chainlink's +# Fast Gas feed is not available. # # Usage: # ./deploy_superform_gas_oracle.sh [account] [gas_price] # -# Parameters: -# environment: "prod" or "staging" -# mode: "simulate", "execute", or "check" -# account: Account name (required for execute mode, e.g., "v2-supervaults") -# gas_price: Initial gas price in Gwei (optional, default: 30) +# Parameters: +# environment "prod" or "staging" +# mode "simulate", "execute", or "check" +# account Account name for execute mode (e.g., "v2-supervaults") +# gas_price Initial gas price (optional, default: 1 Gwei) # # Examples: -# # Check deployment status on Base staging # ./deploy_superform_gas_oracle.sh staging check -# -# # Simulate deployment on Base staging # ./deploy_superform_gas_oracle.sh staging simulate -# -# # Execute deployment on Base staging # ./deploy_superform_gas_oracle.sh staging execute v2-supervaults -# -# # Execute deployment on Base prod # ./deploy_superform_gas_oracle.sh prod execute v2-supervaults # -# # Execute with custom gas price (50 Gwei) -# ./deploy_superform_gas_oracle.sh staging execute v2-supervaults 50 -# # Prerequisites: # - 1Password CLI configured for RPC URL access # - For execute mode: Foundry account (v2-supervaults) configured # -# Note: -# - This script only deploys on Base chain (ID: 8453) +# Notes: +# - Already-deployed chains are skipped automatically # - Owner is set to v2-supervaults keystore address # -# Author: Superform Team ################################################################################### set -euo pipefail @@ -54,14 +45,16 @@ readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Default gas price in Gwei (oracle has 0 decimals - value is directly in Gwei) # This value is used for deterministic address computation and must match the deployed oracle. +# 1 GWEI readonly DEFAULT_GAS_PRICE=1000000 # Owner address (v2-supervaults keystore - DEPLOYER) readonly OWNER="0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" -# Base chain only -readonly CHAIN_ID=8453 -readonly CHAIN_NAME="base" +# Supported chains: "CHAIN_ID:CHAIN_NAME" +readonly SUPPORTED_CHAINS=( + "999:HyperEVM" +) ################################################################################### # Helper Functions @@ -84,22 +77,22 @@ Arguments: gas_price Initial gas price in Gwei (optional, default: $DEFAULT_GAS_PRICE) Examples: - # Check deployment status on Base staging + # Check deployment status on all chains $0 staging check - # Simulate deployment on Base staging + # Simulate deployment on all chains $0 staging simulate - # Execute deployment on Base staging + # Execute deployment on all chains $0 staging execute v2-supervaults - # Execute deployment on Base prod + # Execute deployment on prod $0 prod execute v2-supervaults - # Execute with custom gas price (50 Gwei) + # Execute with custom gas price $0 staging execute v2-supervaults 50 -Note: This script deploys only on Base chain (ID: 8453) +Note: Deploys on Base (8453) and HyperEVM (999). Already-deployed chains are skipped. EOF exit 1 @@ -145,6 +138,95 @@ validate_mode() { fi } +# Get RPC URL for a given chain ID +get_chain_rpc_url() { + local chain_id=$1 + case "$chain_id" in + 8453) + echo "${BASE_MAINNET:-}" + ;; + 999) + echo "${HYPEREVM_MAINNET:-}" + ;; + *) + echo "" + ;; + esac +} + +# Deploy on a single chain +deploy_on_chain() { + local env=$1 + local chain_id=$2 + local chain_name=$3 + local mode=$4 + local account=$5 + local gas_price=$6 + local rpc_url=$7 + + log "INFO" "--------------------------------------------" + log "INFO" "Deploying on chain: $chain_name (ID: $chain_id)" + log "INFO" "--------------------------------------------" + + # Set flags based on mode + local BROADCAST_FLAG="" + local VERIFY_FLAG="" + local SENDER_FLAG="" + local ACCOUNT_FLAG="" + local ETHERSCAN_FLAGS="" + + if [ "$mode" = "execute" ]; then + BROADCAST_FLAG="--broadcast" + ACCOUNT_FLAG="--account $account" + # Only enable etherscan verification for chains that support it (not HyperEVM) + if [ "$chain_id" != "999" ]; then + VERIFY_FLAG="--verify" + ETHERSCAN_FLAGS="--etherscan-api-key $ETHERSCANV2_API_KEY --verifier etherscan" + fi + log "INFO" "Mode: Execute (will broadcast using account: $account)" + elif [ "$mode" = "simulate" ]; then + SENDER_FLAG="--sender $OWNER" + log "INFO" "Mode: Simulate (no broadcast, using sender: $OWNER)" + else + log "INFO" "Mode: Check (read-only)" + fi + + # Build forge command + local forge_cmd="forge script" + forge_cmd+=" script/DeploySuperformGasOracle.s.sol:DeploySuperformGasOracle" + + if [ "$mode" = "check" ]; then + forge_cmd+=" --sig 'runCheck(uint256,uint64,address)' $env $chain_id $OWNER" + else + forge_cmd+=" --sig 'run(uint256,uint64,int256,address)' $env $chain_id $gas_price $OWNER" + fi + + forge_cmd+=" --rpc-url '$rpc_url'" + forge_cmd+=" --chain $chain_id" + [ -n "$ACCOUNT_FLAG" ] && forge_cmd+=" $ACCOUNT_FLAG" + [ -n "$SENDER_FLAG" ] && forge_cmd+=" $SENDER_FLAG" + [ -n "$BROADCAST_FLAG" ] && forge_cmd+=" $BROADCAST_FLAG" + [ -n "$VERIFY_FLAG" ] && forge_cmd+=" $VERIFY_FLAG" + [ -n "$ETHERSCAN_FLAGS" ] && forge_cmd+=" $ETHERSCAN_FLAGS" + + # Add verbosity + forge_cmd+=" -vvvv" + + log "INFO" "Executing forge script..." + log "INFO" "" + + # Execute (capture exit code to prevent set -e from exiting) + local exit_code=0 + eval "$forge_cmd" || exit_code=$? + + if [ $exit_code -ne 0 ]; then + log "ERROR" "Deployment failed on $chain_name ($chain_id) with exit code: $exit_code" + return $exit_code + fi + + log "INFO" "$chain_name ($chain_id) deployment successful" + return 0 +} ################################################################################### # Main @@ -166,7 +248,7 @@ main() { validate_environment "$environment" validate_mode "$mode" - # Source network configuration + # Source network configuration (for Base RPC via load_rpc_urls) source_network_config "$environment" # Validate account for execute mode @@ -190,23 +272,25 @@ main() { ;; esac - # Load RPC URLs from 1Password + # Load RPC URLs from 1Password (loads BASE_MAINNET etc.) log "INFO" "Loading RPC URLs..." load_rpc_urls - # Get RPC URL for Base (use BASE_MAINNET directly after load_rpc_urls) - local rpc_url="${BASE_MAINNET:-}" - if [ -z "$rpc_url" ]; then - log "ERROR" "BASE_MAINNET RPC URL not loaded. Check 1Password configuration." - exit 1 + # Load HyperEVM RPC separately (not in network config) + log "INFO" "Loading HyperEVM RPC URL..." + if ! export HYPEREVM_MAINNET=$(op read op://5ylebqljbh3x6zomdxi3qd7tsa/HYPEREVM_RPC_URL/credential 2>/dev/null); then + log "WARN" "HYPEREVM_RPC_URL not in 1Password, using default RPC" + export HYPEREVM_MAINNET="https://rpc.hyperliquid.xyz/evm" fi - # Load Etherscan API key for verification + # Satisfy foundry.toml [etherscan] env var references + export ETHERSCANV2_API_KEY_TEST="${ETHERSCANV2_API_KEY_TEST:-}" + + # Load Etherscan API key for verification (needed for Base) if [ "$mode" = "execute" ]; then log "INFO" "Loading Etherscan API credentials..." if ! load_etherscan_api_key; then - log "ERROR" "Failed to load Etherscan API key. Verification will not work." - exit 1 + log "WARN" "Failed to load Etherscan API key. Base verification will not work." fi fi @@ -214,75 +298,74 @@ main() { log "INFO" "Deploy SuperformGasOracle" log "INFO" "============================================" log "INFO" "Environment: $environment (env=$env)" - log "INFO" "Chain: $CHAIN_NAME (ID: $CHAIN_ID)" log "INFO" "Mode: $mode" log "INFO" "Owner (v2-supervaults): $OWNER" log "INFO" "Initial Gas Price: $gas_price (Gwei, 0 decimals)" - log "INFO" "RPC URL: ${rpc_url:0:50}..." + log "INFO" "Target Chains: HyperEVM (999)" log "INFO" "============================================" - # Set flags based on mode - local BROADCAST_FLAG="" - local VERIFY_FLAG="" - local SENDER_FLAG="" - local ACCOUNT_FLAG="" - local ETHERSCAN_FLAGS="" + local successful_chains=() + local skipped_chains=() + local failed_chains=() - if [ "$mode" = "execute" ]; then - BROADCAST_FLAG="--broadcast" - VERIFY_FLAG="--verify" - ACCOUNT_FLAG="--account $account" - ETHERSCAN_FLAGS="--etherscan-api-key $ETHERSCANV2_API_KEY --verifier etherscan" - log "INFO" "Mode: Execute (will broadcast and verify using account: $account)" - elif [ "$mode" = "simulate" ]; then - SENDER_FLAG="--sender $OWNER" - log "INFO" "Mode: Simulate (no broadcast, using sender: $OWNER)" - else - # Check mode - log "INFO" "Mode: Check (read-only)" - fi + # Deploy on each supported chain + for chain_def in "${SUPPORTED_CHAINS[@]}"; do + IFS=':' read -r chain_id chain_name <<< "$chain_def" - # Build forge command - local forge_cmd="forge script" - forge_cmd+=" script/DeploySuperformGasOracle.s.sol:DeploySuperformGasOracle" + # Get RPC URL for this chain + local rpc_url + rpc_url=$(get_chain_rpc_url "$chain_id") - if [ "$mode" = "check" ]; then - # Check mode - just verify deployment status - forge_cmd+=" --sig 'runCheck(uint256,uint64,address)' $env $CHAIN_ID $OWNER" - else - # Deploy mode (simulate or execute) - forge_cmd+=" --sig 'run(uint256,uint64,int256,address)' $env $CHAIN_ID $gas_price $OWNER" - fi + if [ -z "$rpc_url" ]; then + log "WARN" "Skipping $chain_name ($chain_id) - RPC URL not available" + skipped_chains+=("$chain_name ($chain_id)") + continue + fi - forge_cmd+=" --rpc-url '$rpc_url'" - forge_cmd+=" --chain $CHAIN_ID" - [ -n "$ACCOUNT_FLAG" ] && forge_cmd+=" $ACCOUNT_FLAG" - [ -n "$SENDER_FLAG" ] && forge_cmd+=" $SENDER_FLAG" - [ -n "$BROADCAST_FLAG" ] && forge_cmd+=" $BROADCAST_FLAG" - [ -n "$VERIFY_FLAG" ] && forge_cmd+=" $VERIFY_FLAG" - [ -n "$ETHERSCAN_FLAGS" ] && forge_cmd+=" $ETHERSCAN_FLAGS" + if deploy_on_chain "$env" "$chain_id" "$chain_name" "$mode" "$account" "$gas_price" "$rpc_url"; then + successful_chains+=("$chain_name ($chain_id)") + else + failed_chains+=("$chain_name ($chain_id)") + fi - # Add verbosity - forge_cmd+=" -vvvv" + log "INFO" "" + done - log "INFO" "Executing forge script..." + # Summary log "INFO" "" + log "INFO" "============================================" + log "INFO" "Deployment Summary" + log "INFO" "============================================" - # Execute - eval "$forge_cmd" - local exit_code=$? + if [ ${#successful_chains[@]} -gt 0 ]; then + log "INFO" "Deployed:" + for chain in "${successful_chains[@]}"; do + log "INFO" " ✓ $chain" + done + fi - log "INFO" "" - if [ $exit_code -eq 0 ]; then - log "INFO" "============================================" - log "INFO" "SuperformGasOracle deployment completed successfully!" - log "INFO" "============================================" - else - log "ERROR" "============================================" - log "ERROR" "SuperformGasOracle deployment FAILED with exit code: $exit_code" - log "ERROR" "============================================" - exit $exit_code + if [ ${#skipped_chains[@]} -gt 0 ]; then + log "INFO" "Skipped:" + for chain in "${skipped_chains[@]}"; do + log "INFO" " - $chain" + done + fi + + if [ ${#failed_chains[@]} -gt 0 ]; then + log "WARN" "Failed:" + for chain in "${failed_chains[@]}"; do + log "WARN" " ✗ $chain" + done fi + + log "INFO" "============================================" + + if [ ${#failed_chains[@]} -gt 0 ]; then + log "ERROR" "Deployment completed with failures" + exit 1 + fi + + log "INFO" "Deployment completed successfully!" } main "$@" diff --git a/script/run/deploy_supervault_batch_operator.sh b/script/run/deploy_supervault_batch_operator.sh index 78d45d77e..374289a78 100644 --- a/script/run/deploy_supervault_batch_operator.sh +++ b/script/run/deploy_supervault_batch_operator.sh @@ -166,10 +166,13 @@ deploy_on_chain() { if [ "$mode" = "execute" ]; then BROADCAST_FLAG="--broadcast" - VERIFY_FLAG="--verify" ACCOUNT_FLAG="--account $account" - ETHERSCAN_FLAGS="--etherscan-api-key $ETHERSCANV2_API_KEY --verifier etherscan" - log "INFO" "Mode: Execute (will broadcast and verify using account: $account)" + # Skip etherscan verification for HyperEVM (no etherscan support) + if [ "$chain_id" != "999" ]; then + VERIFY_FLAG="--verify" + ETHERSCAN_FLAGS="--etherscan-api-key $ETHERSCANV2_API_KEY --verifier etherscan" + fi + log "INFO" "Mode: Execute (will broadcast using account: $account)" elif [ "$mode" = "simulate" ]; then SENDER_FLAG="--sender $ADMIN" log "INFO" "Mode: Simulate (no broadcast, using sender: $ADMIN)" @@ -264,6 +267,9 @@ main() { log "INFO" "Loading RPC URLs..." load_rpc_urls + # Satisfy foundry.toml [etherscan] env var references + export ETHERSCANV2_API_KEY_TEST="${ETHERSCANV2_API_KEY_TEST:-}" + # Load Etherscan API key for verification if [ "$mode" = "execute" ]; then log "INFO" "Loading Etherscan API credentials..." diff --git a/script/run/deploy_up_oft_hyperevm.sh b/script/run/deploy_up_oft_hyperevm.sh new file mode 100755 index 000000000..f296ac2b6 --- /dev/null +++ b/script/run/deploy_up_oft_hyperevm.sh @@ -0,0 +1,296 @@ +#!/usr/bin/env bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +NC='\033[0m' + +print_header() { + echo -e "${CYAN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${WHITE} 🚀 UP OFT HyperEVM Deployment Script 🚀 ${CYAN}║${NC}" + echo -e "${CYAN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" +} + +print_separator() { + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +} + +print_header + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +if [ $# -lt 3 ]; then + echo -e "${RED}❌ Error: Missing required arguments${NC}" + echo -e "${YELLOW}Usage: $0 ${NC}" + echo -e "${CYAN} environment: staging or prod${NC}" + echo -e "${CYAN} mode: simulate or deploy${NC}" + echo -e "${CYAN} account: foundry account name (e.g., v2-supervaults)${NC}" + echo -e "${CYAN}Examples:${NC}" + echo -e "${CYAN} $0 staging simulate v2-supervaults${NC}" + echo -e "${CYAN} $0 prod deploy v2-supervaults${NC}" + echo -e "${CYAN}Available accounts: $(cast wallet list 2>/dev/null | sed 's/ (Local)//' | tr '\n' ' ' || echo 'Run "cast wallet list" to see available accounts')${NC}" + exit 1 +fi + +ENVIRONMENT=$1 +MODE=$2 +ACCOUNT=$3 + +if [ "$ENVIRONMENT" != "staging" ] && [ "$ENVIRONMENT" != "prod" ]; then + echo -e "${RED}❌ Invalid environment: $ENVIRONMENT${NC}" + echo -e "${YELLOW}Environment must be either 'staging' or 'prod'${NC}" + exit 1 +fi + +if ! cast wallet list 2>/dev/null | sed 's/ (Local)//' | grep -q "^$ACCOUNT$"; then + echo -e "${RED}❌ Account '$ACCOUNT' not found in foundry wallet list${NC}" + echo -e "${YELLOW}Available accounts:${NC}" + cast wallet list 2>/dev/null | sed 's/ (Local)//' | sed 's/^/ • /' || echo -e "${RED} No accounts found. Run 'cast wallet import' to add accounts.${NC}" + exit 1 +fi + +echo -e "${CYAN} • Getting account address...${NC}" +ACCOUNT_ADDRESS=$(cast wallet address --account "$ACCOUNT" 2>/dev/null) +if [ -z "$ACCOUNT_ADDRESS" ]; then + echo -e "${RED}❌ Could not get address for account '$ACCOUNT'${NC}" + exit 1 +fi +echo -e "${GREEN} ✅ Account address: $ACCOUNT_ADDRESS${NC}" + +if [ "$MODE" = "simulate" ]; then + echo -e "${YELLOW}🔍 Running in simulation mode for $ENVIRONMENT...${NC}" + BROADCAST_FLAG="" + SENDER_FLAG="--sender $ACCOUNT_ADDRESS" + ACCOUNT_FLAG="" +elif [ "$MODE" = "deploy" ]; then + echo -e "${GREEN}🚀 Running in deployment mode for $ENVIRONMENT...${NC}" + BROADCAST_FLAG="--broadcast" + SENDER_FLAG="--sender $ACCOUNT_ADDRESS" + ACCOUNT_FLAG="--account $ACCOUNT" +else + echo -e "${RED}❌ Invalid mode: $MODE${NC}" + echo -e "${YELLOW}Mode must be either 'simulate' or 'deploy'${NC}" + exit 1 +fi + +print_separator +echo -e "${BLUE}🔧 Loading Configuration...${NC}" + +echo -e "${CYAN} • Loading RPC URL from 1Password...${NC}" +if ! export HYPEREVM_MAINNET=$(op read op://5ylebqljbh3x6zomdxi3qd7tsa/HYPEREVM_RPC_URL/credential 2>/dev/null); then + echo -e "${YELLOW}⚠️ HYPEREVM_RPC_URL not in 1Password, using default RPC...${NC}" + export HYPEREVM_MAINNET="https://rpc.hyperliquid.xyz/evm" +fi +echo -e "${GREEN} ✅ HyperEVM RPC loaded${NC}" + +# Satisfy foundry.toml [etherscan] env var references (resolved eagerly by forge on startup) +export ETHERSCANV2_API_KEY_TEST="${ETHERSCANV2_API_KEY_TEST:-}" + +if [ "$ENVIRONMENT" = "staging" ]; then + FORGE_ENV=2 +elif [ "$ENVIRONMENT" = "prod" ]; then + FORGE_ENV=0 +fi + +echo -e "${GREEN}✅ Configuration loaded successfully${NC}" +echo -e "${CYAN} • Environment: $ENVIRONMENT (env=$FORGE_ENV)${NC}" +echo -e "${CYAN} • Account: $ACCOUNT${NC}" + +cd "$PROJECT_ROOT" + +print_separator + +if [ "$MODE" = "deploy" ]; then + echo -e "${YELLOW}⚠️ DEPLOYMENT CONFIRMATION REQUIRED ⚠️${NC}" + echo -e "${CYAN}You are about to deploy UP OFT contracts on HyperEVM:${NC}" + echo -e "${CYAN} • Environment: ${WHITE}$ENVIRONMENT${NC}" + echo -e "${CYAN} • Account: ${WHITE}$ACCOUNT${NC}" + echo -e "${CYAN} • Account Address: ${WHITE}$ACCOUNT_ADDRESS${NC}" + echo -e "${CYAN} • Steps (HyperEVM side only):${NC}" + echo -e "${CYAN} 1. Deploy UpOFT on HyperEVM (Chain ID: 999)${NC}" + echo -e "${CYAN} 2. Configure peer on HyperEVM -> Ethereum${NC}" + echo -e "${CYAN} 3. Configure peer on HyperEVM -> Base${NC}" + echo -e "${CYAN} 4. Set enforced options on HyperEVM -> Ethereum${NC}" + echo -e "${CYAN} 5. Set enforced options on HyperEVM -> Base${NC}" + echo -e "${CYAN} 6. Configure libraries on HyperEVM -> Ethereum${NC}" + echo -e "${CYAN} 7. Configure libraries on HyperEVM -> Base${NC}" + echo -e "${CYAN} 8. Export addresses to JSON files${NC}" + echo -e "${YELLOW} NOTE: ETH/Base -> HyperEVM config requires MCP wallet (different owner)${NC}" + echo "" + read -p "$(echo -e ${YELLOW}Type \"DEPLOY\" to continue or anything else to abort: ${NC})" confirmation + if [ "$confirmation" != "DEPLOY" ]; then + echo -e "${RED}❌ Deployment aborted by user${NC}" + exit 1 + fi + echo -e "${GREEN}✅ Deployment confirmed${NC}" + print_separator +fi + +echo -e "${BLUE}🚀 Deploying UpOFT on HyperEVM...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'deployOFTOnHyperEVM(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to deploy UpOFT on HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ UpOFT deployment on HyperEVM complete${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring peer on HyperEVM...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'configurePeerOnHyperEVM(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure peer on HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ HyperEVM peer configured${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring peer on HyperEVM for Base...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'configurePeerOnHyperEVMForBase(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure peer on HyperEVM for Base${NC}" + exit 1 +fi +echo -e "${GREEN}✅ HyperEVM peer configured for Base${NC}" + +print_separator + +echo -e "${BLUE}🔧 Setting enforced options on HyperEVM...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'setEnforcedOptionsOnHyperEVM(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to set enforced options on HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ HyperEVM enforced options set${NC}" + +print_separator + +echo -e "${BLUE}🔧 Setting enforced options on HyperEVM for Base...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'setEnforcedOptionsOnHyperEVMForBase(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to set enforced options on HyperEVM for Base${NC}" + exit 1 +fi +echo -e "${GREEN}✅ HyperEVM enforced options set for Base${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring libraries + ULN on HyperEVM for Ethereum...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'configureLibrariesOnHyperEVM(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure libraries on HyperEVM${NC}" + exit 1 +fi +echo -e "${GREEN}✅ HyperEVM libraries + ULN configured${NC}" + +print_separator + +echo -e "${BLUE}🔧 Configuring libraries + ULN on HyperEVM for Base...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'configureLibrariesOnHyperEVMForBase(uint256)' $FORGE_ENV \ + --rpc-url $HYPEREVM_MAINNET \ + --chain 999 \ + $ACCOUNT_FLAG \ + $SENDER_FLAG \ + $BROADCAST_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to configure libraries on HyperEVM for Base${NC}" + exit 1 +fi +echo -e "${GREEN}✅ HyperEVM libraries + ULN configured for Base${NC}" + +print_separator + +echo -e "${BLUE}📄 Exporting contract addresses to JSON...${NC}" + +forge script script/DeployUpOFT.s.sol:DeployUpOFT \ + --sig 'exportAddresses(uint256)' $FORGE_ENV \ + $SENDER_FLAG \ + -vvv + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Failed to export addresses${NC}" + exit 1 +fi +echo -e "${GREEN}✅ Addresses exported to script/output/$ENVIRONMENT/999/UpOFT-latest.json${NC}" + +print_separator + +echo -e "${GREEN}🎉 UP OFT HyperEVM Deployment Complete!${NC}" +echo -e "${CYAN} • UpOFT deployed on HyperEVM (Chain ID: 999)${NC}" +echo -e "${CYAN} • HyperEVM -> Ethereum peer configured${NC}" +echo -e "${CYAN} • HyperEVM -> Base peer configured${NC}" +echo -e "${CYAN} • HyperEVM -> Ethereum enforced options set${NC}" +echo -e "${CYAN} • HyperEVM -> Base enforced options set${NC}" +echo -e "${CYAN} • HyperEVM -> Ethereum libraries + ULN/DVN configured${NC}" +echo -e "${CYAN} • HyperEVM -> Base libraries + ULN/DVN configured${NC}" +echo -e "${CYAN} • Addresses exported to JSON files${NC}" +echo "" +echo -e "${YELLOW}⚠️ NEXT STEPS (require Fireblocks wallet that owns ETH/Base OFTs):${NC}" +echo -e "${CYAN} Run the following script to complete bidirectional config:${NC}" +echo -e "${CYAN} FIREBLOCKS_API_KEY_OP_PATH=\"op://vault/item/field\" \\${NC}" +echo -e "${CYAN} FIREBLOCKS_SECRET_OP_PATH=\"op://vault/item/field\" \\${NC}" +echo -e "${CYAN} ./script/run/configure_hyperevm_from_ethbase.sh $ENVIRONMENT execute ${NC}" +echo -e "${CYAN} (HyperEVM OFT address will be read from script/output/$ENVIRONMENT/999/UpOFT-latest.json)${NC}" diff --git a/script/run/deploy_v2_periphery_staging_prod.sh b/script/run/deploy_v2_periphery_staging_prod.sh index 062cd5d2b..268935c6d 100755 --- a/script/run/deploy_v2_periphery_staging_prod.sh +++ b/script/run/deploy_v2_periphery_staging_prod.sh @@ -483,6 +483,9 @@ fi print_separator echo -e "${BLUE}🔧 Loading Configuration...${NC}" +# Satisfy foundry.toml [etherscan] env var references +export ETHERSCANV2_API_KEY_TEST="${ETHERSCANV2_API_KEY_TEST:-}" + # Load RPC URLs using network-specific function echo -e "${CYAN} • Loading RPC URLs...${NC}" if ! load_rpc_urls; then @@ -680,17 +683,29 @@ for network_def in "${NETWORKS[@]}"; do echo -e "${CYAN} • Status: $deployed/$total contracts already deployed${NC}" echo "" + # Set verification flags (skip etherscan for HyperEVM) + local CHAIN_VERIFY_FLAG="$VERIFY_FLAG" + local CHAIN_ETHERSCAN_FLAGS="" + local CHAIN_SLOW_FLAG="" + if [ "$network_id" != "999" ]; then + CHAIN_ETHERSCAN_FLAGS="--etherscan-api-key $ETHERSCANV2_API_KEY --verifier etherscan" + else + CHAIN_VERIFY_FLAG="" + # HyperEVM needs --slow to avoid nonce issues + CHAIN_SLOW_FLAG="--slow" + fi + # Run deployment script if forge script script/DeployV2Periphery.s.sol:DeployV2Periphery \ --sig 'run(uint256,uint64)' $FORGE_ENV $network_id \ --rpc-url ${!rpc_var} \ --chain $network_id \ - --etherscan-api-key $ETHERSCANV2_API_KEY \ - --verifier etherscan \ + $CHAIN_ETHERSCAN_FLAGS \ + $CHAIN_SLOW_FLAG \ $ACCOUNT_FLAG \ $SENDER_FLAG \ $BROADCAST_FLAG \ - $VERIFY_FLAG \ + $CHAIN_VERIFY_FLAG \ -vvv; then echo -e "${GREEN}✅ Successfully deployed to $network_name${NC}" diff --git a/script/run/merge_periphery_to_core_s3_staging.sh b/script/run/merge_periphery_to_core_s3_staging.sh index f3a7b9f3e..9538b37e8 100755 --- a/script/run/merge_periphery_to_core_s3_staging.sh +++ b/script/run/merge_periphery_to_core_s3_staging.sh @@ -386,40 +386,58 @@ process_periphery_merge() { return 1 fi - # Show periphery contracts that will be merged + # Show diff of what will change compared to current S3 state (only differences) echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" - echo -e "${CYAN}Periphery contracts that will be merged into core S3:${NC}" + echo -e "${CYAN}Changes to be applied to core S3 state:${NC}" echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" - # Show updated networks with periphery contracts + local any_changes=false + for network_id in $supported_network_ids; do local network_name=$(get_network_name "$network_id") if [ $? -ne 0 ]; then continue fi - local network_exists=$(echo "$updated_content" | jq -r ".networks[\"$network_name\"] // empty") - if [ -n "$network_exists" ] && [ "$network_exists" != "null" ]; then - echo -e "${CYAN}📍 $network_name:${NC}" + local new_network=$(echo "$updated_content" | jq -r ".networks[\"$network_name\"] // empty") + if [ -z "$new_network" ] || [ "$new_network" = "null" ]; then + continue + fi - # Show only periphery contracts that were merged - local periphery_contracts_display="{}" - for contract in "${ALLOWED_PERIPHERY_CONTRACTS[@]}"; do - local contract_addr=$(echo "$updated_content" | jq -r ".networks[\"$network_name\"].contracts.$contract // empty") - if [ -n "$contract_addr" ] && [ "$contract_addr" != "empty" ] && [ "$contract_addr" != "null" ]; then - periphery_contracts_display=$(echo "$periphery_contracts_display" | jq --arg contract "$contract" --arg addr "$contract_addr" '.[$contract] = $addr') - fi - done + # Collect changes for this network first + local network_changes="" - if [ "$(echo "$periphery_contracts_display" | jq 'length')" -gt 0 ]; then - echo "$periphery_contracts_display" | jq '.' - else - echo -e "${YELLOW} No periphery contracts found${NC}" + for contract in "${ALLOWED_PERIPHERY_CONTRACTS[@]}"; do + local old_addr=$(echo "$core_content" | jq -r ".networks[\"$network_name\"].contracts.$contract // empty") + local new_addr=$(echo "$updated_content" | jq -r ".networks[\"$network_name\"].contracts.$contract // empty") + + # Normalize empties + [ "$old_addr" = "null" ] && old_addr="" + [ "$new_addr" = "null" ] && new_addr="" + + if [ -n "$new_addr" ] && [ -z "$old_addr" ]; then + # New contract being added + network_changes+=" ${GREEN}+ $contract: $new_addr${NC}\n" + elif [ -n "$new_addr" ] && [ "$old_addr" != "$new_addr" ]; then + # Contract address changed + network_changes+=" ${RED}- $contract: $old_addr${NC}\n" + network_changes+=" ${GREEN}+ $contract: $new_addr${NC}\n" fi - echo "" + done + + # Only print network header if there are changes + if [ -n "$network_changes" ]; then + echo -e "${CYAN} $network_name:${NC}" + echo -e "$network_changes" + any_changes=true fi done + if [ "$any_changes" = false ]; then + echo -e "${WHITE} (no changes to apply)${NC}" + echo "" + fi + echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" # Ask for confirmation to upload all changes @@ -440,12 +458,23 @@ process_periphery_merge() { if aws s3 cp "$latest_file_path" "s3://$BUCKET/$environment/latest.json" --quiet; then log "SUCCESS" "Successfully uploaded merged state to S3 for $environment" echo -e "${GREEN}✅ Successfully uploaded merged state to S3${NC}" - return 0 else log "ERROR" "Failed to upload merged state to S3" echo -e "${RED}❌ Failed to upload merged state to S3${NC}" return 1 fi + + # Also save locally so other scripts can use it + local local_latest_path="$SCRIPT_DIR/../output/$environment/latest.json" + if echo "$updated_content" | jq '.' > "$local_latest_path"; then + log "SUCCESS" "Successfully saved merged state locally to: $local_latest_path" + echo -e "${GREEN}✅ Successfully saved merged state locally${NC}" + else + log "WARN" "Failed to save merged state locally" + echo -e "${YELLOW}⚠️ Failed to save merged state locally (S3 upload succeeded)${NC}" + fi + + return 0 } ################################################################################### diff --git a/script/run/networks-production.sh b/script/run/networks-production.sh index 35cb0f35c..e474fabba 100644 --- a/script/run/networks-production.sh +++ b/script/run/networks-production.sh @@ -18,6 +18,7 @@ NETWORKS=( # "146:Sonic:SONIC_MAINNET" # "100:Gnosis:GNOSIS_MAINNET" # "480:Worldchain:WORLDCHAIN_MAINNET" + "999:HyperEVM:HYPEREVM_MAINNET" ) # Network name mapping function @@ -60,6 +61,9 @@ get_network_name() { # 480) # echo "Worldchain" # ;; + 999) + echo "HyperEVM" + ;; *) echo "ERROR: Unknown production network ID: $network_id" >&2 return 1 @@ -107,6 +111,9 @@ get_rpc_var() { # 480) # echo "WORLDCHAIN_MAINNET" # ;; + 999) + echo "HYPEREVM_MAINNET" + ;; *) echo "ERROR: Unknown production network ID for RPC: $network_id" >&2 return 1 @@ -154,6 +161,9 @@ get_rpc_url() { # 480) # echo "$WORLDCHAIN_MAINNET" # ;; + 999) + echo "$HYPEREVM_MAINNET" + ;; *) echo "ERROR: Unknown production network ID for RPC: $network_id" >&2 return 1 @@ -273,6 +283,14 @@ load_rpc_urls_ci() { # failed_rpcs+=("WORLDCHAIN_RPC_URL") # fi + echo " • Loading HyperEVM RPC..." + if [[ -n "${HYPEREVM_RPC_URL:-}" ]]; then + export HYPEREVM_MAINNET="$HYPEREVM_RPC_URL" + else + echo " • HYPEREVM_RPC_URL not set, using default RPC" + export HYPEREVM_MAINNET="https://rpc.hyperliquid.xyz/evm" + fi + if [[ ${#failed_rpcs[@]} -gt 0 ]]; then echo "❌ Failed to load the following RPC URLs from environment:" for failed_rpc in "${failed_rpcs[@]}"; do @@ -282,7 +300,7 @@ load_rpc_urls_ci() { return 1 fi - echo "✅ Production RPC URLs loaded successfully from environment (Ethereum, Base)" + echo "✅ Production RPC URLs loaded successfully from environment (Ethereum, Base, HyperEVM)" } # Load RPC URLs from credential manager for all production networks @@ -353,6 +371,15 @@ load_rpc_urls() { # failed_rpcs+=("WORLDCHAIN_RPC_URL") # fi + echo " • Loading HyperEVM RPC..." + HYPEREVM_MAINNET=$(op read op://5ylebqljbh3x6zomdxi3qd7tsa/HYPEREVM_RPC_URL/credential 2>/dev/null) || true + if [ -z "$HYPEREVM_MAINNET" ]; then + echo " • HYPEREVM_RPC_URL not in 1Password, using default RPC" + export HYPEREVM_MAINNET="https://rpc.hyperliquid.xyz/evm" + else + export HYPEREVM_MAINNET + fi + if [[ ${#failed_rpcs[@]} -gt 0 ]]; then echo "❌ Failed to load the following RPC URLs from 1Password:" for failed_rpc in "${failed_rpcs[@]}"; do @@ -362,7 +389,7 @@ load_rpc_urls() { return 1 fi - echo "✅ Production RPC URLs loaded successfully (Ethereum, Base)" + echo "✅ Production RPC URLs loaded successfully (Ethereum, Base, HyperEVM)" } # Load Etherscan V2 API key for verification diff --git a/script/run/networks-staging.sh b/script/run/networks-staging.sh index c6e8ad1c3..fbb0f87fe 100755 --- a/script/run/networks-staging.sh +++ b/script/run/networks-staging.sh @@ -11,6 +11,7 @@ NETWORKS=( # "56:BNB:BSC_MAINNET" # "42161:Arbitrum:ARBITRUM_MAINNET" # "43114:Avalanche:AVALANCHE_MAINNET" + "999:HyperEVM:HYPEREVM_MAINNET" ) # Network name mapping function @@ -32,6 +33,9 @@ get_network_name() { # 43114) # echo "Avalanche" # ;; + 999) + echo "HyperEVM" + ;; *) echo "ERROR: Unknown staging network ID: $network_id" >&2 return 1 @@ -58,6 +62,9 @@ get_rpc_var() { # 43114) # echo "AVALANCHE_MAINNET" # ;; + 999) + echo "HYPEREVM_MAINNET" + ;; *) echo "ERROR: Unknown staging network ID for RPC: $network_id" >&2 return 1 @@ -84,6 +91,9 @@ get_rpc_url() { # 43114) # echo "$AVALANCHE_MAINNET" # ;; + 999) + echo "$HYPEREVM_MAINNET" + ;; *) echo "ERROR: Unknown staging network ID for RPC: $network_id" >&2 return 1 @@ -142,6 +152,12 @@ load_rpc_urls() { # failed_rpcs+=("AVALANCHE_RPC_URL") # fi + echo " • Loading HyperEVM RPC..." + if ! export HYPEREVM_MAINNET=$(op read op://5ylebqljbh3x6zomdxi3qd7tsa/HYPEREVM_RPC_URL/credential 2>/dev/null); then + echo " • HYPEREVM_RPC_URL not in 1Password, using default RPC" + export HYPEREVM_MAINNET="https://rpc.hyperliquid.xyz/evm" + fi + if [[ ${#failed_rpcs[@]} -gt 0 ]]; then echo "❌ Failed to load the following RPC URLs from 1Password:" for failed_rpc in "${failed_rpcs[@]}"; do @@ -151,7 +167,7 @@ load_rpc_urls() { return 1 fi - echo "✅ Staging RPC URLs loaded successfully (Ethereum, Base)" + echo "✅ Staging RPC URLs loaded successfully (Ethereum, Base, HyperEVM)" } # Load Etherscan V2 API key for verification diff --git a/script/run/regenerate_bytecode.sh b/script/run/regenerate_bytecode.sh index c2f02e97a..12a58eb02 100755 --- a/script/run/regenerate_bytecode.sh +++ b/script/run/regenerate_bytecode.sh @@ -95,6 +95,59 @@ CORE_PERIPHERY_CONTRACTS=( "SuperformGasOracle" ) +# Function to map contract name to source file path (for Standard JSON Input generation) +get_contract_source() { + local contract_name=$1 + case $contract_name in + "SuperOracle") echo "src/oracles/SuperOracle.sol" ;; + "SuperOracleL2") echo "src/oracles/SuperOracleL2.sol" ;; + "SuperformGasOracle") echo "src/oracles/SuperformGasOracle.sol" ;; + "FixedPriceOracle") echo "src/oracles/FixedPriceOracle.sol" ;; + "ECDSAPPSOracle") echo "src/oracles/ECDSAPPSOracle.sol" ;; + "SuperVault") echo "src/SuperVault/SuperVault.sol" ;; + "SuperVaultAggregator") echo "src/SuperVault/SuperVaultAggregator.sol" ;; + "SuperVaultEscrow") echo "src/SuperVault/SuperVaultEscrow.sol" ;; + "SuperVaultStrategy") echo "src/SuperVault/SuperVaultStrategy.sol" ;; + "SuperVaultBatchOperator") echo "src/SuperVault/SuperVaultBatchOperator.sol" ;; + "SuperBank") echo "src/SuperBank.sol" ;; + "SuperGovernor") echo "src/SuperGovernor.sol" ;; + "UpOFT") echo "src/UP/UpOFT.sol" ;; + "UpOFTAdapter") echo "src/UP/UpOFTAdapter.sol" ;; + "Up") echo "src/UP/Up.sol" ;; + *) echo "" ;; + esac +} + +# Function to generate Standard JSON Input for Etherscan verification +# This captures the exact source files and compiler settings used in the build, +# enabling direct Etherscan API verification without recompilation. +generate_standard_json_input() { + local contract_name=$1 + local source_file=$(get_contract_source "$contract_name") + local dest_path="script/generated-bytecode/${contract_name}.standard-json-input.json" + + if [ -z "$source_file" ]; then + log "WARN" "${YELLOW} ⚠️ Unknown source path for ${contract_name}, skipping standard JSON input${NC}" + return 1 + fi + + log "INFO" "${BLUE} Generating standard JSON input for ${contract_name}...${NC}" + + if forge verify-contract \ + 0x0000000000000000000000000000000000000000 \ + "${source_file}:${contract_name}" \ + --chain 1 \ + --etherscan-api-key "dummy" \ + --show-standard-json-input > "$dest_path" 2>/dev/null; then + log "INFO" "${GREEN} ✅ Standard JSON input saved for ${contract_name}${NC}" + return 0 + else + log "ERROR" "${RED} ❌ Failed to generate standard JSON input for ${contract_name}${NC}" + rm -f "$dest_path" + return 1 + fi +} + # Function to copy contract artifact copy_contract() { local contract_name=$1 @@ -121,6 +174,7 @@ if [ -n "$CONTRACT_NAME" ]; then # Single contract mode log "INFO" "${BLUE}📦 Copying specific contract: ${CONTRACT_NAME}...${NC}" if copy_contract "$CONTRACT_NAME"; then + generate_standard_json_input "$CONTRACT_NAME" log "INFO" "${GREEN}🎉 Contract ${CONTRACT_NAME} successfully updated in generated-bytecode!${NC}" exit 0 else @@ -133,7 +187,9 @@ else log "INFO" "${BLUE}📦 Copying core periphery contracts...${NC}" failed_core=0 for contract in "${CORE_PERIPHERY_CONTRACTS[@]}"; do - if ! copy_contract "$contract"; then + if copy_contract "$contract"; then + generate_standard_json_input "$contract" + else failed_core=$((failed_core + 1)) fi done diff --git a/script/run/transfer_supervault_batch_operator_ownership.sh b/script/run/transfer_supervault_batch_operator_ownership.sh new file mode 100755 index 000000000..19402d268 --- /dev/null +++ b/script/run/transfer_supervault_batch_operator_ownership.sh @@ -0,0 +1,180 @@ +#!/usr/bin/env bash + +################################################################################### +# Transfer SuperVaultBatchOperator Ownership Script +################################################################################### +# Description: +# Transfers SuperVaultBatchOperator DEFAULT_ADMIN_ROLE from deployer to +# SUPER_GOVERNOR_ADDRESS (0x89226a5Fd572f380991Bb17c20c96ba91F98aD2e) +# +# Usage: +# ./transfer_supervault_batch_operator_ownership.sh [account] [--slow] +# +# Parameters: +# environment: "staging" or "prod" +# mode: "simulate" or "execute" +# chain_id: Chain ID (e.g., 8453 for Base) +# contract_address: The deployed SuperVaultBatchOperator address +# account: Account name (required for execute mode) +# --slow: Optional flag for polling-based tx confirmation +# +# Examples: +# ./transfer_supervault_batch_operator_ownership.sh prod simulate 8453 0x3047601ea12565C65b715137799a458971BA070B +# ./transfer_supervault_batch_operator_ownership.sh prod execute 8453 0x3047601ea12565C65b715137799a458971BA070B v2-supervaults +################################################################################### + +set -euo pipefail + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +NC='\033[0m' + +# Constants +DEPLOYER="0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" +SUPER_GOVERNOR_ADDRESS="0x89226a5Fd572f380991Bb17c20c96ba91F98aD2e" + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +log() { + echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" +} + +print_header() { + echo -e "${CYAN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${WHITE} 🔐 Transfer SuperVaultBatchOperator Ownership 🔐 ${CYAN}║${NC}" + echo -e "${CYAN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" +} + +# Check arguments +if [ $# -lt 4 ]; then + echo -e "${RED}❌ Error: Missing required arguments${NC}" + echo -e "${YELLOW}Usage: $0 [account] [--slow]${NC}" + echo -e "${CYAN} environment: staging or prod${NC}" + echo -e "${CYAN} mode: simulate or execute${NC}" + echo -e "${CYAN} chain_id: Chain ID (e.g., 8453 for Base)${NC}" + echo -e "${CYAN} contract_address: Deployed SuperVaultBatchOperator address${NC}" + echo -e "${CYAN} account: Account name (required for execute mode)${NC}" + echo -e "${CYAN} --slow: Optional flag for polling-based tx confirmation${NC}" + echo "" + echo -e "${CYAN}Examples:${NC}" + echo -e "${CYAN} $0 prod simulate 8453 0x3047601ea12565C65b715137799a458971BA070B${NC}" + echo -e "${CYAN} $0 prod execute 8453 0x3047601ea12565C65b715137799a458971BA070B v2-supervaults${NC}" + exit 1 +fi + +ENVIRONMENT=$1 +MODE=$2 +CHAIN_ID=$3 +CONTRACT_ADDRESS=$4 +ACCOUNT="" +SLOW_FLAG="" + +# Parse remaining arguments +shift 4 +while [ $# -gt 0 ]; do + case "$1" in + --slow) + SLOW_FLAG="--slow" + ;; + *) + if [ -z "$ACCOUNT" ]; then + ACCOUNT="$1" + fi + ;; + esac + shift +done + +# Validate environment +if [ "$ENVIRONMENT" != "staging" ] && [ "$ENVIRONMENT" != "prod" ]; then + echo -e "${RED}❌ Invalid environment: $ENVIRONMENT${NC}" + exit 1 +fi + +# Validate mode +if [ "$MODE" != "simulate" ] && [ "$MODE" != "execute" ]; then + echo -e "${RED}❌ Invalid mode: $MODE${NC}" + exit 1 +fi + +# Require account for execute mode +if [ "$MODE" = "execute" ] && [ -z "$ACCOUNT" ]; then + echo -e "${RED}❌ Account name required for execute mode${NC}" + exit 1 +fi + +print_header + +log "Environment: $ENVIRONMENT" +log "Mode: $MODE" +log "Chain ID: $CHAIN_ID" +log "Contract Address: $CONTRACT_ADDRESS" +log "Current Admin (Deployer): $DEPLOYER" +log "New Admin (SUPER_GOVERNOR): $SUPER_GOVERNOR_ADDRESS" +if [ -n "$ACCOUNT" ]; then + log "Account: $ACCOUNT" +fi + +# Source network config +if [ "$ENVIRONMENT" = "staging" ]; then + source "$SCRIPT_DIR/networks-staging.sh" + FORGE_ENV=2 +else + source "$SCRIPT_DIR/networks-production.sh" + FORGE_ENV=0 +fi + +# Load RPC URLs +log "Loading RPC URLs..." +load_rpc_urls + +# Get RPC URL for chain +RPC_URL=$(get_rpc_url "$CHAIN_ID") +if [ -z "$RPC_URL" ]; then + echo -e "${RED}❌ RPC URL not found for chain $CHAIN_ID${NC}" + exit 1 +fi + +log "RPC URL loaded for chain $CHAIN_ID" + +# Set up forge flags +if [ "$MODE" = "execute" ]; then + FORGE_FLAGS="--account $ACCOUNT --broadcast" + + echo "" + echo -e "${RED}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${RED}║${WHITE} ⚠️ WARNING ⚠️ ${RED}║${NC}" + echo -e "${RED}║${WHITE} You are about to transfer SuperVaultBatchOperator admin role. ${RED}║${NC}" + echo -e "${RED}║${WHITE} This is a ONE-WAY operation! ${RED}║${NC}" + echo -e "${RED}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" + echo "" + read -p "Are you sure you want to continue? (yes/no): " confirm + if [ "$confirm" != "yes" ]; then + log "Operation cancelled by user" + exit 0 + fi +else + FORGE_FLAGS="--sender $DEPLOYER" +fi + +# Change to project root +cd "$SCRIPT_DIR/../.." + +log "Executing TransferSuperVaultBatchOperatorOwnership..." + +forge script script/TransferSuperVaultBatchOperatorOwnership.s.sol:TransferSuperVaultBatchOperatorOwnership \ + --sig 'run(uint256,uint64,address,address)' "$FORGE_ENV" "$CHAIN_ID" "$CONTRACT_ADDRESS" "$DEPLOYER" \ + --rpc-url "$RPC_URL" \ + $FORGE_FLAGS \ + $SLOW_FLAG \ + -vvv + +echo "" +echo -e "${GREEN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}║${WHITE} 🎉 SuperVaultBatchOperator Ownership Transfer Complete! 🎉 ${GREEN}║${NC}" +echo -e "${GREEN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" diff --git a/script/run/verify_v2_periphery_staging_prod.sh b/script/run/verify_v2_periphery_staging_prod.sh new file mode 100755 index 000000000..b3f27c292 --- /dev/null +++ b/script/run/verify_v2_periphery_staging_prod.sh @@ -0,0 +1,787 @@ +#!/usr/bin/env bash + +# ===== CHAIN FILTER CONFIGURATION ===== +# Specify which chains to verify (comment out to verify all chains) +# Leave empty array to verify all chains from network configuration +CHAINS_TO_VERIFY=() + +# ===== CONTRACT FILTER CONFIGURATION ===== +# Specify which contracts to verify (comment out to verify all contracts) +# Leave empty array to verify all contracts found in deployment JSON +CONTRACTS_TO_VERIFY=() + +# Colors for better visual output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +NC='\033[0m' # No Color + +# Function to print colored header +print_header() { + echo -e "${CYAN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║ ║${NC}" + echo -e "${CYAN}║${WHITE} 🔍 V2 Periphery Contract Verification 🔍 ${CYAN}║${NC}" + echo -e "${CYAN}║ ║${NC}" + echo -e "${CYAN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" +} + +# Function to print section separator +print_separator() { + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +} + +# Function to print network header +print_network_header() { + local network=$1 + echo -e "${PURPLE}╭─────────────────────────────────────────────────────────────────────────────────────╮${NC}" + echo -e "${PURPLE}│${WHITE} 🌐 Verifying on ${network} Network 🌐 ${PURPLE}│${NC}" + echo -e "${PURPLE}╰─────────────────────────────────────────────────────────────────────────────────────╯${NC}" +} + +print_header + +# Script directory and project root setup +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +# Check if arguments are provided +if [ $# -lt 1 ]; then + echo -e "${RED}❌ Error: Missing required argument${NC}" + echo -e "${YELLOW}Usage: $0 ${NC}" + echo -e "${CYAN} environment: staging or prod${NC}" + echo -e "${CYAN}Examples:${NC}" + echo -e "${CYAN} $0 staging${NC}" + echo -e "${CYAN} $0 prod${NC}" + exit 1 +fi + +ENVIRONMENT=$1 + +# Validate environment and source appropriate network configuration +if [ "$ENVIRONMENT" = "staging" ]; then + echo -e "${CYAN}🌐 Loading staging network configuration...${NC}" + source "$SCRIPT_DIR/networks-staging.sh" +elif [ "$ENVIRONMENT" = "prod" ]; then + echo -e "${CYAN}🌐 Loading production network configuration...${NC}" + source "$SCRIPT_DIR/networks-production.sh" +else + echo -e "${RED}❌ Invalid environment: $ENVIRONMENT${NC}" + echo -e "${YELLOW}Environment must be either 'staging' or 'prod'${NC}" + exit 1 +fi + +# Set locked bytecode directory based on environment +if [ "$ENVIRONMENT" = "staging" ]; then + LOCKED_BYTECODE_DIR="$PROJECT_ROOT/script/locked-bytecode-dev" +else + LOCKED_BYTECODE_DIR="$PROJECT_ROOT/script/locked-bytecode" +fi + +echo -e "${CYAN}✅ Network configuration loaded for $ENVIRONMENT environment${NC}" +print_network_info + +print_separator +echo -e "${BLUE}🔧 Loading Configuration...${NC}" + +# Load RPC URLs using network-specific function +echo -e "${CYAN} • Loading RPC URLs...${NC}" +if ! load_rpc_urls; then + echo -e "${RED}❌ Failed to load some RPC URLs from credential manager${NC}" + echo -e "${YELLOW}⚠️ This may cause connectivity issues during verification${NC}" + echo -e "${YELLOW} Please ensure all required RPC URLs are configured in 1Password${NC}" + exit 1 +fi + +# Load Etherscan V2 API key for verification +echo -e "${CYAN} • Loading Etherscan V2 API credentials...${NC}" +if ! load_etherscan_api_key; then + echo -e "${RED}❌ Failed to load Etherscan V2 API key${NC}" + echo -e "${RED} Contract verification will not work without this credential${NC}" + exit 1 +fi + +echo -e "${GREEN}✅ Configuration loaded successfully${NC}" +echo -e "${CYAN} • Using Etherscan V2 verification${NC}" +echo -e "${CYAN} • Environment: $ENVIRONMENT${NC}" + +print_separator + +# Get network suffix from chain id +get_network_suffix() { + local chain_id=$1 + case $chain_id in + "1") echo "Ethereum-latest" ;; + "8453") echo "Base-latest" ;; + "56") echo "BNB-latest" ;; + "42161") echo "Arbitrum-latest" ;; + "10") echo "Optimism-latest" ;; + "137") echo "Polygon-latest" ;; + "130") echo "Unichain-latest" ;; + "43114") echo "Avalanche-latest" ;; + "80094") echo "Berachain-latest" ;; + "146") echo "Sonic-latest" ;; + "100") echo "Gnosis-latest" ;; + "480") echo "Worldchain-latest" ;; + "999") echo "HyperEVM-latest" ;; + *) + local network_name=$(get_network_name "$chain_id") + echo "${network_name}-latest" + ;; + esac +} + +# Function to get contract address from JSON +get_contract_address() { + local chain_id=$1 + local contract_name=$2 + local json_file=$3 + + if [ -f "$json_file" ]; then + local address=$(jq -r ".$contract_name // empty" "$json_file") + echo "$address" + else + echo "" + fi +} + +# Function to get contract source file path +get_contract_source() { + local contract_name=$1 + + case $contract_name in + # Oracles + "SuperOracle") echo "src/oracles/SuperOracle.sol" ;; + "SuperOracleL2") echo "src/oracles/SuperOracleL2.sol" ;; + "SuperformGasOracle") echo "src/oracles/SuperformGasOracle.sol" ;; + "FixedPriceOracle") echo "src/oracles/FixedPriceOracle.sol" ;; + "ECDSAPPSOracle") echo "src/oracles/ECDSAPPSOracle.sol" ;; + + # SuperVault + "SuperVault") echo "src/SuperVault/SuperVault.sol" ;; + "SuperVaultAggregator") echo "src/SuperVault/SuperVaultAggregator.sol" ;; + "SuperVaultEscrow") echo "src/SuperVault/SuperVaultEscrow.sol" ;; + "SuperVaultStrategy") echo "src/SuperVault/SuperVaultStrategy.sol" ;; + "SuperVaultBatchOperator") echo "src/SuperVault/SuperVaultBatchOperator.sol" ;; + + # Core + "SuperBank") echo "src/SuperBank.sol" ;; + "SuperGovernor") echo "src/SuperGovernor.sol" ;; + + # UP Token + "UpOFT") echo "src/UP/UpOFT.sol" ;; + "UpOFTAdapter") echo "src/UP/UpOFTAdapter.sol" ;; + "Up") echo "src/UP/Up.sol" ;; + + *) echo "src/unknown/$contract_name.sol" ;; + esac +} + +# Function to generate constructor arguments based on deployment logic +# Follows the exact same constructor arg patterns as: +# - script/DeployV2Periphery.s.sol (main periphery contracts) +# - script/DeploySuperformGasOracle.s.sol +# - script/DeploySuperVaultBatchOperator.s.sol +# - script/DeployUpOFT.s.sol +generate_constructor_args() { + local contract_name=$1 + local chain_id=$2 + local json_file=$3 + + # ===== Constants from ConfigBase.sol ===== + local DEPLOYER="0x6E3dadcAf328ebB58753e89a3e589F5C5e988dF8" + local BANK_MANAGER="0xBe3B40a05BA6120B73F94c5018Bc90E49A6275E7" + local ORACLE_MANAGER="0xC72F6950FBF6ffE315525E200F6E54A05F739311" + local GAS_MANAGER="0x4d7AACD4b72e6BC6eA0eee6AA61A773A8b556B99" + local GUARDIAN="0x5E8C68Ef250fdBcF696F838033CCcE23785DA03F" + local SUPERFORM_TREASURY="0x1dbD9b26b295A33f126456Ab4e498cd308622f08" + local SUPER_GOVERNOR_ADDR="0x89226a5Fd572f380991Bb17c20c96ba91F98aD2e" + + # Oracle constant addresses (precomputed from Solidity keccak256) + local GAS_QUOTE="0x2facc608f385d9435b7c3773f83bd2a8902fdca0" + local WEI_QUOTE="0x0687868a5f4b140eb03f4a07ba66b35601c6fc8f" + local NATIVE_TOKEN="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + local USD_TOKEN="0x0000000000000000000000000000000000000348" + local PROVIDER_CHAINLINK="0x531b25f722d0a8a71503c7385b01570de01ad80b519cff2a790a6255312abee0" + local PROVIDER_SUPERFORM="0x882d8c67ce5072aca91c6d5a5ca4eb7a2e5098a13e008e22004c1e0af2493746" + + # Chain-specific oracle feed addresses + local ORACLE_GAS_TO_ETH="0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C" + local ORACLE_GAS_TO_WEI_BASE="0x473b88f017dE39d85a102DA01A35a1b3507eBcFc" + local ORACLE_GAS_TO_WEI_HYPEREVM="0x473b88f017dE39d85a102DA01A35a1b3507eBcFc" + local ORACLE_GAS_TO_WEI_HYPEREVM_STAGING="0xCa35c983e810fBFe952A6CA59120fd9a8d2d58e3" + local ORACLE_ETH_USD_MAINNET="0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419" + local ORACLE_ETH_USD_BASE="0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70" + local ORACLE_ETH_USD_HYPEREVM="0x017151e74fB3a393673B5B5149F53578c0Fa55B0" + + # UP Token addresses per chain + local UP_TOKEN="0x1D926bbE67425C9F507b9A0E8030eEdc7880BF33" + local UP_TOKEN_BASE="0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B" + local UP_TOKEN_HYPEREVM="0x642fFC3496AcA19106BAB7A42F1F221a329654fe" + local UP_TOKEN_HYPEREVM_STAGING="0x53749a9a8dE9847DAE54E7F432616F2fDfa32B7f" + + # LayerZero V2 endpoints + local LZ_ENDPOINT="0x1a44076050125825900e736c501f859c50fE728c" + local LZ_ENDPOINT_HYPEREVM="0x3A73033C0b1407574C76BdBAc67f126f6b4a9AA9" + + case $contract_name in + "SuperGovernor") + # DeployV2Periphery.s.sol L645-661: abi.encode(owner, governor, bankManager, oracleManager, + # gasManager, guardian, treasury, upkeepPaymentsEnabled) + # upkeepPaymentsEnabled is true only for production + local upkeep_enabled="false" + if [ "$ENVIRONMENT" = "prod" ]; then + upkeep_enabled="true" + fi + echo "$(cast abi-encode "constructor(address,address,address,address,address,address,address,bool)" \ + "$DEPLOYER" "$DEPLOYER" "$BANK_MANAGER" "$ORACLE_MANAGER" \ + "$GAS_MANAGER" "$GUARDIAN" "$SUPERFORM_TREASURY" "$upkeep_enabled")" + ;; + + "SuperVault"|"SuperVaultStrategy") + # DeployV2Periphery.s.sol L669/L676: abi.encode(superGovernor) + local sg=$(jq -r '.SuperGovernor // empty' "$json_file") + if [ -n "$sg" ]; then + echo "$(cast abi-encode "constructor(address)" "$sg")" + fi + ;; + + "SuperVaultEscrow") + # DeployV2Periphery.s.sol L683: no constructor args + echo "" + ;; + + "SuperVaultAggregator") + # DeployV2Periphery.s.sol L693-698: abi.encode(superGovernor, vaultImpl, strategyImpl, escrowImpl) + local sg=$(jq -r '.SuperGovernor // empty' "$json_file") + local vault_impl=$(jq -r '.SuperVault // empty' "$json_file") + local strategy_impl=$(jq -r '.SuperVaultStrategy // empty' "$json_file") + local escrow_impl=$(jq -r '.SuperVaultEscrow // empty' "$json_file") + if [ -n "$sg" ] && [ -n "$vault_impl" ] && [ -n "$strategy_impl" ] && [ -n "$escrow_impl" ]; then + echo "$(cast abi-encode "constructor(address,address,address,address)" \ + "$sg" "$vault_impl" "$strategy_impl" "$escrow_impl")" + fi + ;; + + "ECDSAPPSOracle") + # DeployV2Periphery.s.sol L709: abi.encode(superGovernor, "ECDSAPPSOracle", "1.0") + local sg=$(jq -r '.SuperGovernor // empty' "$json_file") + if [ -n "$sg" ]; then + echo "$(cast abi-encode "constructor(address,string,string)" "$sg" "ECDSAPPSOracle" "1.0")" + fi + ;; + + "FixedPriceOracle") + # DeployV2Periphery.s.sol L721: abi.encode(INITIAL_UP_PRICE, UP_PRICE_DECIMALS, deployer) + # INITIAL_UP_PRICE = 0.09e18 = 90000000000000000, UP_PRICE_DECIMALS = 18 + echo "$(cast abi-encode "constructor(int256,uint8,address)" 90000000000000000 18 "$DEPLOYER")" + ;; + + "SuperOracle") + # DeployV2Periphery.s.sol L836: abi.encode(superGovernor, bases, quotes, providers, feeds) + # Used on mainnet (chain 1) and HyperEVM (chain 999) + local sg=$(jq -r '.SuperGovernor // empty' "$json_file") + local fixed_oracle=$(jq -r '.FixedPriceOracle // empty' "$json_file") + if [ -z "$sg" ] || [ -z "$fixed_oracle" ]; then + echo "" + return + fi + + local gas_oracle="" eth_usd_oracle="" up_token="" + case $chain_id in + "1") + gas_oracle="$ORACLE_GAS_TO_ETH" + eth_usd_oracle="$ORACLE_ETH_USD_MAINNET" + up_token="$UP_TOKEN" + ;; + "999") + if [ "$ENVIRONMENT" = "staging" ]; then + gas_oracle="$ORACLE_GAS_TO_WEI_HYPEREVM_STAGING" + up_token="$UP_TOKEN_HYPEREVM_STAGING" + else + gas_oracle="$ORACLE_GAS_TO_WEI_HYPEREVM" + up_token="$UP_TOKEN_HYPEREVM" + fi + eth_usd_oracle="$ORACLE_ETH_USD_HYPEREVM" + ;; + *) + echo "" + return + ;; + esac + + echo "$(cast abi-encode "constructor(address,address[],address[],bytes32[],address[])" \ + "$sg" \ + "[$GAS_QUOTE,$NATIVE_TOKEN,$up_token]" \ + "[$WEI_QUOTE,$USD_TOKEN,$USD_TOKEN]" \ + "[$PROVIDER_CHAINLINK,$PROVIDER_CHAINLINK,$PROVIDER_SUPERFORM]" \ + "[$gas_oracle,$eth_usd_oracle,$fixed_oracle]")" + ;; + + "SuperOracleL2") + # DeployV2Periphery.s.sol L847: same constructor as SuperOracle, used on L2 chains + local sg=$(jq -r '.SuperGovernor // empty' "$json_file") + local fixed_oracle=$(jq -r '.FixedPriceOracle // empty' "$json_file") + if [ -z "$sg" ] || [ -z "$fixed_oracle" ]; then + echo "" + return + fi + + local gas_oracle="" eth_usd_oracle="" up_token="" + case $chain_id in + "8453") + gas_oracle="$ORACLE_GAS_TO_WEI_BASE" + eth_usd_oracle="$ORACLE_ETH_USD_BASE" + up_token="$UP_TOKEN_BASE" + ;; + *) + echo "" + return + ;; + esac + + echo "$(cast abi-encode "constructor(address,address[],address[],bytes32[],address[])" \ + "$sg" \ + "[$GAS_QUOTE,$NATIVE_TOKEN,$up_token]" \ + "[$WEI_QUOTE,$USD_TOKEN,$USD_TOKEN]" \ + "[$PROVIDER_CHAINLINK,$PROVIDER_CHAINLINK,$PROVIDER_SUPERFORM]" \ + "[$gas_oracle,$eth_usd_oracle,$fixed_oracle]")" + ;; + + "SuperBank") + # DeployV2Periphery.s.sol L741: abi.encode(superGovernor) + local sg=$(jq -r '.SuperGovernor // empty' "$json_file") + if [ -n "$sg" ]; then + echo "$(cast abi-encode "constructor(address)" "$sg")" + fi + ;; + + "SuperformGasOracle") + # DeploySuperformGasOracle.s.sol L107: abi.encode(initialGasPrice, owner) + # DEFAULT_INITIAL_GAS_PRICE = 1_000_000 + local owner=$(jq -r '.owner // empty' "$json_file") + if [ -n "$owner" ]; then + echo "$(cast abi-encode "constructor(int256,address)" 1000000 "$owner")" + fi + ;; + + "SuperVaultBatchOperator") + # DeploySuperVaultBatchOperator.s.sol L148: abi.encode(admin, operator) + # Try reading from JSON (separate JSON has admin/operator fields) + local admin=$(jq -r '.admin // empty' "$json_file") + local operator=$(jq -r '.operator // empty' "$json_file") + # Fall back to known constants when verifying from main deployment JSON + if [ -z "$admin" ]; then + admin="$SUPER_GOVERNOR_ADDR" + fi + if [ -z "$operator" ]; then + if [ "$ENVIRONMENT" = "prod" ]; then + operator="0x92C0B875501611B91C6aF3D801424E724Ab039DE" + else + operator="0x02cbf3dac926743ec757b5A51310f46580e25A04" + fi + fi + echo "$(cast abi-encode "constructor(address,address)" "$admin" "$operator")" + ;; + + "UpOFT") + # DeployUpOFT.s.sol L1116: abi.encode(LZ_ENDPOINT, owner) + local lz_endpoint="$LZ_ENDPOINT" + if [ "$chain_id" = "999" ]; then + lz_endpoint="$LZ_ENDPOINT_HYPEREVM" + fi + echo "$(cast abi-encode "constructor(address,address)" "$lz_endpoint" "$DEPLOYER")" + ;; + + "UpOFTAdapter") + # DeployUpOFT.s.sol L1098: abi.encode(UP_TOKEN, LZ_ENDPOINT, owner) + echo "$(cast abi-encode "constructor(address,address,address)" "$UP_TOKEN" "$LZ_ENDPOINT" "$DEPLOYER")" + ;; + + *) + # Unknown contracts (e.g., PendlePTAmortizedOracle from v2-core) - skip constructor args + echo "" + ;; + esac +} + +# Compiler version for Etherscan API submissions +SOLC_VERSION="v0.8.30+commit.73712a01" + +# Function to verify a single contract +verify_contract() { + local chain_id=$1 + local contract_name=$2 + local contract_address=$3 + local constructor_args=$4 + local source_file=$5 + local rpc_url=$6 + + echo -e "${YELLOW} 🔍 Verifying $contract_name...${NC}" + echo -e "${CYAN} Address: $contract_address${NC}" + echo -e "${CYAN} Source: $source_file${NC}" + echo -e "${CYAN} Chain ID: $chain_id${NC}" + + # Check for Standard JSON Input in locked bytecode directory + local standard_json_path="${LOCKED_BYTECODE_DIR}/${contract_name}.standard-json-input.json" + + if [ -f "$standard_json_path" ]; then + echo -e "${CYAN} Using saved Standard JSON Input from locked bytecodes${NC}" + + # Strip 0x prefix from constructor args for Etherscan API + local constructor_args_no_0x="" + if [ -n "$constructor_args" ]; then + constructor_args_no_0x="${constructor_args#0x}" + echo -e "${CYAN} Constructor args: ${constructor_args_no_0x:0:40}...${NC}" + fi + + # Submit to Etherscan V2 API + local response + response=$(curl -s -X POST "https://api.etherscan.io/v2/api?chainid=${chain_id}" \ + --data-urlencode "module=contract" \ + --data-urlencode "action=verifysourcecode" \ + --data-urlencode "apikey=${ETHERSCANV2_API_KEY}" \ + --data-urlencode "sourceCode@${standard_json_path}" \ + --data-urlencode "codeformat=solidity-standard-json-input" \ + --data-urlencode "contractaddress=${contract_address}" \ + --data-urlencode "contractname=${source_file}:${contract_name}" \ + --data-urlencode "compilerversion=${SOLC_VERSION}" \ + --data-urlencode "constructorArguements=${constructor_args_no_0x}" \ + --data-urlencode "evmversion=prague") + + local api_status + api_status=$(echo "$response" | jq -r '.status') + local api_result + api_result=$(echo "$response" | jq -r '.result') + + if [ "$api_status" != "1" ]; then + echo -e "${RED} ❌ $contract_name submission failed: $api_result${NC}" + echo "" + return 1 + fi + + local guid="$api_result" + echo -e "${CYAN} Verification GUID: $guid${NC}" + echo -e "${CYAN} Polling for result...${NC}" + + # Poll for verification result + local max_attempts=30 + local attempt=0 + while [ $attempt -lt $max_attempts ]; do + sleep 5 + local check_response + check_response=$(curl -s "https://api.etherscan.io/v2/api?chainid=${chain_id}&module=contract&action=checkverifystatus&guid=${guid}&apikey=${ETHERSCANV2_API_KEY}") + local check_result + check_result=$(echo "$check_response" | jq -r '.result') + + if echo "$check_result" | grep -qi "pass"; then + echo -e "${GREEN} ✅ $contract_name verified successfully${NC}" + echo "" + return 0 + elif echo "$check_result" | grep -qi "fail"; then + echo -e "${RED} ❌ $contract_name verification failed: $check_result${NC}" + echo "" + return 1 + fi + + # Still pending + attempt=$((attempt + 1)) + echo -e "${CYAN} Still pending (attempt $attempt/$max_attempts)...${NC}" + done + + echo -e "${YELLOW} ⚠️ $contract_name verification timed out after $max_attempts attempts${NC}" + echo "" + return 1 + else + # Fallback: use forge verify-contract (no Standard JSON Input available) + echo -e "${YELLOW} No Standard JSON Input found, falling back to forge verify-contract${NC}" + + local verify_cmd="forge verify-contract \"$contract_address\" \"$source_file:$contract_name\" --rpc-url \"$rpc_url\" --chain \"$chain_id\" --etherscan-api-key \"$ETHERSCANV2_API_KEY\" --verifier etherscan --watch" + + if [ -n "$constructor_args" ]; then + echo -e "${CYAN} Constructor args: $constructor_args${NC}" + verify_cmd="$verify_cmd --constructor-args \"$constructor_args\"" + fi + + eval $verify_cmd + + if [ $? -eq 0 ]; then + echo -e "${GREEN} ✅ $contract_name verified successfully${NC}" + else + echo -e "${RED} ❌ $contract_name verification failed${NC}" + fi + + echo "" + fi +} + +# Function to verify contracts from a single JSON file +verify_json_file() { + local chain_id=$1 + local json_file=$2 + local rpc_url=$3 + local file_type=$4 + + if [ ! -f "$json_file" ]; then + return 0 + fi + + echo -e "${CYAN} 📄 Processing: $(basename "$json_file")${NC}" + + case $file_type in + "main") + # Standard JSON with contract_name: address format + local all_contract_names=($(jq -r 'keys[]' "$json_file" 2>/dev/null)) + + if [ ${#all_contract_names[@]} -eq 0 ]; then + echo -e "${YELLOW} ⚠️ No contracts found in file${NC}" + return 0 + fi + + local contract_names=() + + # Apply contract filter if specified + if [ ${#CONTRACTS_TO_VERIFY[@]} -eq 0 ]; then + contract_names=("${all_contract_names[@]}") + else + for contract_name in "${CONTRACTS_TO_VERIFY[@]}"; do + for deployed_contract in "${all_contract_names[@]}"; do + if [ "$deployed_contract" = "$contract_name" ]; then + contract_names+=("$contract_name") + break + fi + done + done + fi + + for contract_name in "${contract_names[@]}"; do + local contract_address=$(get_contract_address "$chain_id" "$contract_name" "$json_file") + + if [ -z "$contract_address" ] || [ "$contract_address" = "null" ]; then + echo -e "${YELLOW} ⚠️ Skipping $contract_name (address not found)${NC}" + continue + fi + + local constructor_args=$(generate_constructor_args "$contract_name" "$chain_id" "$json_file") + local source_file=$(get_contract_source "$contract_name") + + verify_contract "$chain_id" "$contract_name" "$contract_address" "$constructor_args" "$source_file" "$rpc_url" + done + ;; + + "gas_oracle") + # SuperformGasOracle JSON format: { address, chainId, decimals, description, owner } + local contract_address=$(jq -r '.address // empty' "$json_file") + if [ -n "$contract_address" ] && [ "$contract_address" != "null" ]; then + # Check if we should verify this contract based on filter + local should_verify=true + if [ ${#CONTRACTS_TO_VERIFY[@]} -gt 0 ]; then + should_verify=false + for filter_contract in "${CONTRACTS_TO_VERIFY[@]}"; do + if [ "$filter_contract" = "SuperformGasOracle" ]; then + should_verify=true + break + fi + done + fi + + if [ "$should_verify" = true ]; then + local source_file=$(get_contract_source "SuperformGasOracle") + local constructor_args=$(generate_constructor_args "SuperformGasOracle" "$chain_id" "$json_file") + verify_contract "$chain_id" "SuperformGasOracle" "$contract_address" "$constructor_args" "$source_file" "$rpc_url" + fi + fi + ;; + + "up_oft") + # UpOFT JSON format: { UpOFT: address } + local contract_address=$(jq -r '.UpOFT // empty' "$json_file") + if [ -n "$contract_address" ] && [ "$contract_address" != "null" ]; then + # Check if we should verify this contract based on filter + local should_verify=true + if [ ${#CONTRACTS_TO_VERIFY[@]} -gt 0 ]; then + should_verify=false + for filter_contract in "${CONTRACTS_TO_VERIFY[@]}"; do + if [ "$filter_contract" = "UpOFT" ]; then + should_verify=true + break + fi + done + fi + + if [ "$should_verify" = true ]; then + local source_file=$(get_contract_source "UpOFT") + local constructor_args=$(generate_constructor_args "UpOFT" "$chain_id" "$json_file") + verify_contract "$chain_id" "UpOFT" "$contract_address" "$constructor_args" "$source_file" "$rpc_url" + fi + fi + ;; + + "super_vault_batch_operator") + # SuperVaultBatchOperator JSON format: { address, admin, chainId, operator } + local contract_address=$(jq -r '.address // empty' "$json_file") + if [ -n "$contract_address" ] && [ "$contract_address" != "null" ]; then + # Check if we should verify this contract based on filter + local should_verify=true + if [ ${#CONTRACTS_TO_VERIFY[@]} -gt 0 ]; then + should_verify=false + for filter_contract in "${CONTRACTS_TO_VERIFY[@]}"; do + if [ "$filter_contract" = "SuperVaultBatchOperator" ]; then + should_verify=true + break + fi + done + fi + + if [ "$should_verify" = true ]; then + local source_file=$(get_contract_source "SuperVaultBatchOperator") + local constructor_args=$(generate_constructor_args "SuperVaultBatchOperator" "$chain_id" "$json_file") + verify_contract "$chain_id" "SuperVaultBatchOperator" "$contract_address" "$constructor_args" "$source_file" "$rpc_url" + fi + fi + ;; + esac +} + +# Function to verify all contracts for a network +verify_network() { + local chain_id=$1 + + # Get network name and RPC URL from loaded configuration + local network_name=$(get_network_name "$chain_id") + if [ $? -ne 0 ]; then + echo -e "${RED}❌ Unknown network ID: $chain_id${NC}" + return 1 + fi + + local rpc_url=$(get_rpc_url "$chain_id") + if [ -z "$rpc_url" ]; then + echo -e "${RED}❌ RPC URL not found for chain $chain_id${NC}" + return 1 + fi + + print_network_header "$network_name" + echo -e "${CYAN} Chain ID: ${WHITE}$chain_id${NC}" + echo -e "${CYAN} RPC URL: ${WHITE}$rpc_url${NC}" + echo -e "${CYAN} Verification: ${WHITE}Etherscan V2${NC}" + + local chain_dir="script/output/$ENVIRONMENT/$chain_id" + + if [ ! -d "$chain_dir" ]; then + echo -e "${YELLOW} ⚠️ No deployment directory found for chain $chain_id${NC}" + return 0 + fi + + echo -e "${CYAN} 📋 Starting contract verification...${NC}" + + # Get network suffix for main JSON file + local network_suffix=$(get_network_suffix "$chain_id") + local main_json="$chain_dir/$network_suffix.json" + + # Verify main contracts file (e.g., Base-latest.json) + if [ -f "$main_json" ]; then + verify_json_file "$chain_id" "$main_json" "$rpc_url" "main" + fi + + # Verify SuperformGasOracle if exists + local gas_oracle_json="$chain_dir/SuperformGasOracle-latest.json" + if [ -f "$gas_oracle_json" ]; then + verify_json_file "$chain_id" "$gas_oracle_json" "$rpc_url" "gas_oracle" + fi + + # Verify UpOFT if exists + local up_oft_json="$chain_dir/UpOFT-latest.json" + if [ -f "$up_oft_json" ]; then + verify_json_file "$chain_id" "$up_oft_json" "$rpc_url" "up_oft" + fi + + # Verify SuperVaultBatchOperator if exists (separate file) + local batch_operator_json="$chain_dir/SuperVaultBatchOperator-latest.json" + if [ -f "$batch_operator_json" ]; then + verify_json_file "$chain_id" "$batch_operator_json" "$rpc_url" "super_vault_batch_operator" + fi + + echo -e "${GREEN}✅ Network $network_name verification completed${NC}" +} + +# Main verification loop +main() { + # Get chain IDs from the loaded network configuration or use filter + local chains=() + + if [ ${#CHAINS_TO_VERIFY[@]} -eq 0 ]; then + # No filter specified, use all chains from network configuration + echo -e "${CYAN}📋 No chain filter specified, verifying all configured networks...${NC}" + for network_def in "${NETWORKS[@]}"; do + IFS=':' read -r network_id _ _ <<< "$network_def" + chains+=("$network_id") + done + else + # Use filtered chains + echo -e "${CYAN}📋 Chain filter active, verifying only specified chains...${NC}" + for chain_id in "${CHAINS_TO_VERIFY[@]}"; do + # Verify the chain exists in network configuration + local found=false + for network_def in "${NETWORKS[@]}"; do + IFS=':' read -r network_id _ _ <<< "$network_def" + if [ "$network_id" = "$chain_id" ]; then + chains+=("$chain_id") + found=true + break + fi + done + if [ "$found" = false ]; then + echo -e "${YELLOW}⚠️ Warning: Chain $chain_id not found in network configuration, skipping...${NC}" + fi + done + fi + + echo -e "${BLUE}🔍 Starting verification for ${#chains[@]} networks in $ENVIRONMENT environment...${NC}" + if [ ${#CHAINS_TO_VERIFY[@]} -gt 0 ]; then + echo -e "${CYAN} Filtered chains: ${CHAINS_TO_VERIFY[*]}${NC}" + fi + if [ ${#CONTRACTS_TO_VERIFY[@]} -gt 0 ]; then + echo -e "${CYAN} Filtered contracts: ${CONTRACTS_TO_VERIFY[*]}${NC}" + fi + echo "" + + local successful_networks=0 + local failed_networks=0 + + for chain_id in "${chains[@]}"; do + if verify_network "$chain_id"; then + ((successful_networks++)) + else + ((failed_networks++)) + fi + print_separator + done + + echo -e "${BLUE}📊 Verification Summary:${NC}" + echo -e "${GREEN} • Networks verified successfully: $successful_networks${NC}" + if [ $failed_networks -gt 0 ]; then + echo -e "${RED} • Networks with verification failures: $failed_networks${NC}" + fi + echo "" + + if [ $failed_networks -eq 0 ]; then + echo -e "${GREEN}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}║ ║${NC}" + echo -e "${GREEN}║${WHITE} 🎉 All V2 Periphery $ENVIRONMENT Contract Verification Completed! 🎉 ${GREEN}║${NC}" + echo -e "${GREEN}║ ║${NC}" + echo -e "${GREEN}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" + else + echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${YELLOW}║ ║${NC}" + echo -e "${YELLOW}║${WHITE} ⚠️ V2 Periphery $ENVIRONMENT Verification Completed with Issues ⚠️ ${YELLOW}║${NC}" + echo -e "${YELLOW}║ ║${NC}" + echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════════════════════════════╝${NC}" + exit 1 + fi +} + +# Run the main function +main diff --git a/script/utils/ConfigBase.sol b/script/utils/ConfigBase.sol index 9ec6e94ef..c50fd79b7 100644 --- a/script/utils/ConfigBase.sol +++ b/script/utils/ConfigBase.sol @@ -63,12 +63,20 @@ abstract contract ConfigBase is Constants { /// @notice Gas to WEI oracle on Base (SuperformGasOracle - keeper updated) address internal constant ORACLE_GAS_TO_WEI_BASE = 0x473b88f017dE39d85a102DA01A35a1b3507eBcFc; + /// @notice Gas to WEI oracle on HyperEVM (SuperformGasOracle - keeper updated) + address internal constant ORACLE_GAS_TO_WEI_HYPEREVM = 0x473b88f017dE39d85a102DA01A35a1b3507eBcFc; + /// @notice Gas to WEI oracle on HyperEVM - STAGING + address internal constant ORACLE_GAS_TO_WEI_HYPEREVM_STAGING = 0xCa35c983e810fBFe952A6CA59120fd9a8d2d58e3; + /// @notice ETH/USD oracle on Mainnet address internal constant ORACLE_ETH_USD_MAINNET = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; /// @notice ETH/USD oracle on Base address internal constant ORACLE_ETH_USD_BASE = 0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70; + /// @notice ETH/USD oracle on HyperEVM + address internal constant ORACLE_ETH_USD_HYPEREVM = 0x017151e74fB3a393673B5B5149F53578c0Fa55B0; + /// @notice Base Sequencer Uptime Feed (required for SuperOracleL2) address internal constant ORACLE_SEQUENCER_UPTIME_BASE = 0xBCF85224fc0756B9Fa45aA7892530B47e10b6433; @@ -78,7 +86,9 @@ abstract contract ConfigBase is Constants { address internal constant GAS_QUOTE = address(uint160(uint256(keccak256("GAS_QUOTE")))); address internal constant WEI_QUOTE = address(uint160(uint256(keccak256("WEI_QUOTE")))); address internal constant UP_TOKEN = 0x1D926bbE67425C9F507b9A0E8030eEdc7880BF33; - address internal constant UP_TOKEN_BASE = 0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B ; + address internal constant UP_TOKEN_BASE = 0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B; + address internal constant UP_TOKEN_HYPEREVM = 0x642fFC3496AcA19106BAB7A42F1F221a329654fe; + address internal constant UP_TOKEN_HYPEREVM_STAGING = 0x53749a9a8dE9847DAE54E7F432616F2fDfa32B7f; int256 internal constant INITIAL_UP_PRICE = 0.09e18; // $0.09 with 18 decimals uint8 internal constant UP_PRICE_DECIMALS = 18; bytes32 internal constant PROVIDER_CHAINLINK = keccak256("CHAINLINK"); @@ -97,6 +107,11 @@ abstract contract ConfigBase is Constants { /// @notice UPKEEP_TOKEN on Base (UP token) address internal constant UPKEEP_TOKEN_BASE = 0x5b2193fDc451C1f847bE09CA9d13A4Bf60f8c86B; + /// @notice UPKEEP_TOKEN on HyperEVM (UpOFT) + address internal constant UPKEEP_TOKEN_HYPEREVM = 0x642fFC3496AcA19106BAB7A42F1F221a329654fe; + /// @notice UPKEEP_TOKEN on HyperEVM - STAGING + address internal constant UPKEEP_TOKEN_HYPEREVM_STAGING = 0x53749a9a8dE9847DAE54E7F432616F2fDfa32B7f; + /*////////////////////////////////////////////////////////////// GAS CONFIGURATION //////////////////////////////////////////////////////////////*/ @@ -136,6 +151,7 @@ abstract contract ConfigBase is Constants { chainNames[OPTIMISM_CHAIN_ID] = OPTIMISM_KEY; chainNames[ARBITRUM_CHAIN_ID] = ARBITRUM_KEY; chainNames[BNB_CHAIN_ID] = BNB_KEY; + chainNames[HYPEREVM_CHAIN_ID] = HYPEREVM_KEY; // ===== COMMON CONFIGURATION ===== if (env == 0) { diff --git a/script/utils/Constants.sol b/script/utils/Constants.sol index 1444a0e4c..0ac8a27cc 100644 --- a/script/utils/Constants.sol +++ b/script/utils/Constants.sol @@ -8,6 +8,7 @@ abstract contract Constants { string internal constant OPTIMISM_KEY = "Optimism"; string internal constant ARBITRUM_KEY = "Arbitrum"; string internal constant BNB_KEY = "BNB"; + string internal constant HYPEREVM_KEY = "HyperEVM"; string internal constant SEPOLIA_KEY = "Sepolia"; string internal constant ARB_SEPOLIA_KEY = "Arbitrum_Sepolia"; string internal constant BASE_SEPOLIA_KEY = "Base_Sepolia"; @@ -19,6 +20,7 @@ abstract contract Constants { uint64 internal constant OPTIMISM_CHAIN_ID = 10; uint64 internal constant ARBITRUM_CHAIN_ID = 42_161; uint64 internal constant BNB_CHAIN_ID = 56; + uint64 internal constant HYPEREVM_CHAIN_ID = 999; // testnets uint64 internal constant SEPOLIA_CHAIN_ID = 11_155_111; uint64 internal constant ARB_SEPOLIA_CHAIN_ID = 421_613; diff --git a/specs/pendle-pt-amortized-pricing/interview-notes.md b/specs/pendle-pt-amortized-pricing/interview-notes.md new file mode 100644 index 000000000..8959af995 --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/interview-notes.md @@ -0,0 +1,127 @@ +# Interview Notes: Pendle PT Amortized Pricing + +**Date:** 2026-01-21 +**Interviewee:** Cosmin (Engineering) + +--- + +## Problem Statement + +The current `PendlePTYieldSourceOracle` uses `getPtToAssetRate()` which returns mark-to-market pricing based on AMM supply/demand. This causes PPS (Price Per Share) volatility in SuperVaults even though PT is guaranteed to converge to 1 at maturity. + +For a "Boring PT Strategy" (hold-to-maturity), we need smooth, monotonically increasing prices that reflect accrued value from pull-to-par dynamics rather than market volatility. + +--- + +## Solution: Cost-Basis Amortized Pricing + +Replace mark-to-market pricing with a cost-basis approach that: +1. Tracks weighted average entry price (P0) and entry time (T0) +2. Applies linear pull-to-par formula: `P(t) = P0 + (1 - P0) × (t - T0) / (T_maturity - T0)` + +### Why Cost-Basis Over Other Approaches? + +| Approach | Discount Rate Source | Market Discovered? | Fits Strategy? | +|----------|---------------------|-------------------|----------------| +| LinearDiscountOracle | Governance-set rate | No | No - arbitrary | +| Chaos Labs PT Risk Oracle | Liquidity-aware | Yes | No - causes volatility | +| AMM TWAP | Supply/demand | Yes | No - mark-to-market | +| **Cost-basis** | Implied rate at purchase | Yes | **Yes** | + +--- + +## Technical Decisions + +### Architecture +**Decision:** New dedicated oracle (`PendlePTAmortizedOracle`) +**Rationale:** Keep existing `PendlePTYieldSourceOracle` for mark-to-market use cases; new oracle specifically for amortized pricing + +### Purchase Recording +**Decision:** Keeper/executor call with specific `KEEPER_ROLE` +**Rationale:** Cannot modify SuperVault code, so external authorized caller records purchases +**Flow:** +1. Strategy executes PT buy via hooks +2. Keeper observes purchase (via events/logs) +3. Keeper calls `recordPurchase(vault, market, quantity, entryPrice, timestamp)` + +### Multi-Market Support +**Decision:** Support multiple PT positions with different maturities per vault +**Data Structure:** `mapping(address vault => mapping(address market => Position))` + +### Migration Strategy +**Decision:** Fresh start - only apply to new purchases after deployment +**Rationale:** Simpler, avoids complex historical reconstruction + +### Fallback Behavior +**Decision:** Revert if no cost-basis data exists for a position +**Rationale:** Clear failure mode; forces explicit recording before pricing + +### Redemption Handling +**Decision:** No adjustment to cost basis on partial redemptions +**Formula:** Keep same `avgP0` and `avgT0`, just reduce `totalQuantity` +**Rationale:** Standard moving average cost accounting + +### Integration with Pricing Service +**Decision:** Oracle as source - pricing service reads from `getPrice()`, then pushes to aggregator +**Flow:** +1. Oracle provides deterministic price at any block +2. Pricing service queries oracle +3. Pricing service applies Step 3 conversion (e.g., DETH→WETH) +4. Pricing service pushes final PPS to aggregator + +--- + +## Requirements + +### Functional Requirements +1. Track weighted average entry price and entry time per vault/market +2. Calculate amortized price using linear pull-to-par formula +3. Support multiple PT markets with different maturities +4. Record purchases via authorized keeper role +5. Handle quantity reductions on redemptions + +### Non-Functional Requirements +1. **Deterministic:** Same result for same block height (validator network) +2. **Transparent:** On-chain, verifiable (Hypernative monitoring) +3. **Single source of truth:** No off-chain state dependencies +4. **Gas efficient:** View functions must be cheap (<20k gas) + +--- + +## Access Control + +- `KEEPER_ROLE`: Can call `recordPurchase()` and `recordRedemption()` +- `ADMIN_ROLE`: Can grant/revoke keeper role, set market configurations + +--- + +## Testing Strategy + +**Decision:** Full integration tests +- Unit tests for weighted average math +- Unit tests for linear interpolation +- Fork tests against real Pendle markets +- Integration tests with SuperVaultStrategy +- Edge case tests (maturity reached, zero quantity, etc.) + +--- + +## Open Questions (Resolved) + +| Question | Answer | Decided By | +|----------|--------|------------| +| Where should logic live? | New dedicated oracle | Cosmin | +| How to record purchases? | Keeper/executor call | Cosmin | +| Multi-market support? | Yes, per vault/market | Cosmin | +| Migration approach? | Fresh start | Cosmin | +| Fallback behavior? | Revert | Cosmin | +| Redemption handling? | No adjustment | Cosmin | + +--- + +## References + +- Current oracle: `v2-core/src/accounting/oracles/PendlePTYieldSourceOracle.sol` +- Similar pattern: Cost-basis tracking for performance fees +- Pendle docs: https://docs.pendle.finance/pendle-v2/Developers/Oracles/ +- Chaos Labs PT Risk Oracle: https://chaoslabs.xyz/posts/introducing-pendle-pt-risk-oracle diff --git a/specs/pendle-pt-amortized-pricing/knowledge/new-feature-amortized-oracle.md b/specs/pendle-pt-amortized-pricing/knowledge/new-feature-amortized-oracle.md new file mode 100644 index 000000000..517edaa6c --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/knowledge/new-feature-amortized-oracle.md @@ -0,0 +1,119 @@ +--- +title: Pendle PT Amortized Oracle Implementation +category: new-feature +date: 2026-01-23 +spec: /specs/pendle-pt-amortized-pricing/spec.md +components: [PendlePTAmortizedOracle, BookValueState] +tags: [pendle, oracle, amortization, book-value, pt-pricing] +--- + +# Pendle PT Amortized Oracle Implementation + +## Summary + +Implemented `PendlePTAmortizedOracle` - a new oracle contract that provides amortized cost pricing for Pendle Principal Token (PT) positions held by SuperVault strategies. This replaces volatile mark-to-market pricing with deterministic, linear pull-to-par pricing suitable for hold-to-maturity strategies. + +The oracle uses the Book Value accounting formula: `B(t) = A - (A - B(t0)) × (T - t) / (T - t0)`, where the price linearly converges from purchase price to face value at maturity. + +## Implementation Details + +### Key Decisions + +**1. Storage Structure - 3 Variables Instead of 2** + +The original spec proposed storing only 2 variables (`lastUpdateBookValue` and `lastUpdateTime`) and reading `ptAmount` from `balanceOf` on-demand. During implementation, I discovered this causes incorrect amortization calculations for subsequent purchases. + +**Problem:** When recording a purchase after PT is received, `balanceOf` returns the NEW total amount, but the amortization formula should use the OLD amount to calculate the current book value before adding the new purchase. + +**Solution:** Store `lastUpdatePtAmount` alongside the other two variables. This ensures mathematically correct amortization: + +```solidity +struct BookValueState { + uint128 lastUpdateBookValue; // B(t0): Book value at last update + uint64 lastUpdateTime; // t0: Timestamp of last update + uint128 lastUpdatePtAmount; // A(t0): PT amount at last update +} +``` + +**2. Two Calculation Functions** + +- `_calculateBookValue()` - Uses current `balanceOf` for external queries via `getBookValue()` +- `_calculateBookValueWithStoredAmount()` - Uses stored `lastUpdatePtAmount` for keeper updates + +This separation ensures: +- External callers always get the current amortized value based on actual holdings +- Keeper updates use consistent state for calculations + +**3. Market Address vs PT Address** + +The spec showed accepting PT address directly, but the existing codebase pattern uses Market address. Implementation accepts Market address and extracts PT via `IPMarket(market).readTokens()`. + +### Code Examples + +**Recording a purchase:** +```solidity +function recordPurchase(address strategy, address market, uint256 sySpent) external onlyRole(KEEPER_ROLE) { + // Get current book value using STORED ptAmount (not current balanceOf) + uint256 currentBookValue = _calculateBookValueWithStoredAmount(state, maturity); + uint256 newBookValue = currentBookValue + sySpent; + + // Sanity check against CURRENT balanceOf + uint256 ptAmount = IERC20(address(pt)).balanceOf(strategy); + if (newBookValue > ptAmount) revert BOOK_VALUE_EXCEEDS_FACE_VALUE(); + + // Update state with current ptAmount + state.lastUpdatePtAmount = ptAmount.toUint128(); +} +``` + +**Amortization formula implementation:** +```solidity +// B(t) = A - (A - B(t0)) × (T - t) / (T - t0) +uint256 timeRemaining = T - block.timestamp; +uint256 totalDuration = T - t0; +uint256 unamortizedDiscount = (A - B_t0).mulDiv(timeRemaining, totalDuration); +return A - unamortizedDiscount; +``` + +## Testing Strategy + +**Unit Tests (29 tests):** +- Constructor and role initialization +- First purchase and subsequent purchase recording +- Partial and full redemption with cost basis accounting +- Linear amortization at various time points (0%, 25%, 50%, 75%, 100%) +- Edge cases: after maturity, zero balance, no position +- Error conditions: zero address, zero amount, market expired, insufficient position +- Access control: keeper-only functions, manager-only functions +- Numerical example validation from SV-1095 proposal +- Fuzz tests for amounts and time points + +**Integration Tests (fork tests):** +- Real Pendle markets on Ethereum mainnet +- Verify `balanceOf()` and `expiry()` reads work correctly +- Full lifecycle with actual PT tokens + +## Prevention & Best Practices + +**When implementing similar amortization oracles:** + +1. **State Consistency**: If using on-demand reads for variables in time-dependent formulas, ensure the formula is evaluated with consistent state. Either: + - Store all variables needed for calculation + - Ensure external reads happen at the same logical time point + +2. **Keeper Call Ordering**: Document whether keeper calls should happen BEFORE or AFTER token transfers: + - `recordPurchase`: Called AFTER PT received (needs current balanceOf for sanity check) + - `recordRedemption`: Called BEFORE PT redeemed (needs current balanceOf for cost basis) + +3. **Sanity Checks**: Always validate keeper inputs against chain state to catch errors: + - Book value should never exceed face value (ptAmount) + - Redemption amount should not exceed holdings + +4. **SafeCast Usage**: Use SafeCast for all integer downcasts to prevent silent overflow + +## Related Documentation + +- [SV-1095 Proposal](../research/sv-1095-proposal.md) - Mathematical framework +- [Technical Spec](../technical-spec.md) - Full implementation details +- [Pendle Oracle Docs](https://docs.pendle.finance/pendle-v2/Developers/Oracles/) +- Existing implementation: `v2-core/src/accounting/oracles/PendlePTYieldSourceOracle.sol` diff --git a/specs/pendle-pt-amortized-pricing/research/best-practices.md b/specs/pendle-pt-amortized-pricing/research/best-practices.md new file mode 100644 index 000000000..9ba16f1c9 --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/research/best-practices.md @@ -0,0 +1,145 @@ +# Best Practices for Amortized Cost Pricing in Solidity + +## 1. Weighted Average Cost Basis Tracking + +### Core Pattern +```solidity +struct Position { + uint256 totalFaceValue; // Total face value of bonds held + uint256 totalCostBasis; // Total amount paid for bonds + uint256 weightedAvgPrice; // WAC per unit (18 decimals) + uint256 lastUpdateTimestamp; +} + +function recordPurchase(uint256 faceValue, uint256 purchasePrice) external { + Position storage pos = positions[user][asset]; + + uint256 newTotalFace = pos.totalFaceValue + faceValue; + uint256 newTotalCost = pos.totalCostBasis + purchasePrice; + + // WAC = totalCostBasis / totalFaceValue + pos.weightedAvgPrice = newTotalCost.mulDiv(PRECISION, newTotalFace, Math.Rounding.Floor); + + pos.totalFaceValue = newTotalFace; + pos.totalCostBasis = newTotalCost; +} +``` + +## 2. Linear Pull-to-Par Implementation + +### Formula +``` +P(t) = P0 + (1 - P0) × (t - T0) / (T_maturity - T0) +``` + +### Solidity Implementation +```solidity +function getAmortizedPrice(Position memory pos) public view returns (uint256) { + if (block.timestamp >= pos.maturityTimestamp) { + return PRECISION; // Par value + } + + uint256 totalDuration = pos.maturityTimestamp - pos.purchaseTimestamp; + uint256 elapsed = block.timestamp - pos.purchaseTimestamp; + + uint256 discount = PRECISION - pos.purchasePrice; + uint256 accretion = discount.mulDiv(elapsed, totalDuration, Math.Rounding.Floor); + + return pos.purchasePrice + accretion; +} +``` + +## 3. Fixed-Point Math Best Practices + +### Use OpenZeppelin Math.mulDiv +```solidity +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +// Safe: (a * b) / c with full 512-bit precision +result = a.mulDiv(b, c, Math.Rounding.Floor); +``` + +### Rounding Direction +- **Floor (down)**: Conservative valuation, use for asset outputs +- **Ceil (up)**: Use for share inputs (how many shares needed) + +## 4. Gas Optimization for View Functions + +### Storage Packing +```solidity +// BAD: 3 storage slots +struct UnpackedPosition { + uint256 timestamp; // Slot 0 + uint256 price; // Slot 1 + uint256 amount; // Slot 2 +} + +// GOOD: 2 storage slots +struct PackedPosition { + uint128 amount; // Slot 0 (16 bytes) + uint128 purchasePrice; // Slot 0 (16 bytes) + uint64 purchaseTimestamp; // Slot 1 (8 bytes) + uint64 maturityTimestamp; // Slot 1 (8 bytes) + uint128 bookValue; // Slot 1 (16 bytes) +} +``` + +### Use unchecked for Safe Math +```solidity +unchecked { + // Safe: maturityTimestamp > purchaseTimestamp (validated on creation) + uint256 totalDuration = pos.maturityTimestamp - pos.purchaseTimestamp; + uint256 elapsed = block.timestamp - pos.purchaseTimestamp; +} +``` + +## 5. Time-Based Calculations + +### 15-Second Rule +If your time-dependent calculation can tolerate 15 seconds of variance, `block.timestamp` is safe to use. For bond pricing over days/months, this is acceptable. + +### Minimum Duration Validation +```solidity +uint256 public constant MIN_DURATION = 1 days; + +function createPosition(uint256 maturity) external { + uint256 duration = maturity - block.timestamp; + require(duration >= MIN_DURATION, "Duration too short"); +} +``` + +## 6. Access Control Patterns + +### Role-Based with OpenZeppelin +```solidity +bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE"); +bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); + +constructor(address admin) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _grantRole(MANAGER_ROLE, admin); + + // Set MANAGER as admin of KEEPER role + _setRoleAdmin(KEEPER_ROLE, MANAGER_ROLE); +} +``` + +## 7. Event Logging + +```solidity +event PositionOpened( + address indexed vault, + address indexed market, + uint256 ptAmount, + uint256 bookValue, + uint256 maturityTimestamp +); + +event BookValueUpdated( + address indexed vault, + address indexed market, + uint256 previousValue, + uint256 newValue, + uint256 timestamp +); +``` diff --git a/specs/pendle-pt-amortized-pricing/research/framework-docs.md b/specs/pendle-pt-amortized-pricing/research/framework-docs.md new file mode 100644 index 000000000..afd1c41fe --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/research/framework-docs.md @@ -0,0 +1,177 @@ +# Framework Documentation: Pendle V2 & OpenZeppelin + +## 1. Pendle V2 Contracts + +### IPMarket Interface + +```solidity +import "@pendle/core-v2/contracts/interfaces/IPMarket.sol"; + +interface IPMarket { + // Get market tokens + function readTokens() external view returns ( + IStandardizedYield _SY, + IPPrincipalToken _PT, + IPYieldToken _YT + ); + + // Get maturity timestamp + function expiry() external view returns (uint256); + + // Check if market has matured + function isExpired() external view returns (bool); + + // Get PT to SY rate (TWAP) + function getPtToSyRate(uint32 duration) external view returns (uint256); + + // Get PT to Asset rate (TWAP) + function getPtToAssetRate(uint32 duration) external view returns (uint256); +} +``` + +### IPPrincipalToken Interface + +```solidity +import "@pendle/core-v2/contracts/interfaces/IPPrincipalToken.sol"; + +interface IPPrincipalToken is IERC20Metadata { + // Get the Standardized Yield token address + function SY() external view returns (address); + + // Get maturity timestamp (CRITICAL for amortization) + function expiry() external view returns (uint256); + + // Check if PT has matured + function isExpired() external view returns (bool); +} +``` + +### IStandardizedYield Interface + +```solidity +import "@pendle/core-v2/contracts/interfaces/IStandardizedYield.sol"; + +interface IStandardizedYield is IERC20Metadata { + enum AssetType { TOKEN, LIQUIDITY } + + // Get underlying asset information + function assetInfo() external view returns ( + AssetType assetType, + address assetAddress, + uint8 assetDecimals + ); + + // Get exchange rate (SY to underlying) + function exchangeRate() external view returns (uint256); +} +``` + +### Usage Example + +```solidity +// Get market info +IPMarket market = IPMarket(marketAddress); +(IStandardizedYield sy, IPPrincipalToken pt, ) = market.readTokens(); + +// Get maturity +uint256 maturity = pt.expiry(); + +// Get underlying asset +(, address underlyingAsset, uint8 decimals) = sy.assetInfo(); +``` + +--- + +## 2. OpenZeppelin Math.mulDiv + +### Import +```solidity +import "@openzeppelin/contracts/utils/math/Math.sol"; +``` + +### Rounding Options +```solidity +enum Rounding { + Floor, // Toward negative infinity (default) + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero +} +``` + +### Usage +```solidity +using Math for uint256; + +// Basic mulDiv - rounds down +uint256 result = x.mulDiv(y, denominator); + +// With explicit rounding +uint256 result = x.mulDiv(y, denominator, Math.Rounding.Ceil); +``` + +--- + +## 3. OpenZeppelin AccessControl + +### Import +```solidity +import "@openzeppelin/contracts/access/AccessControl.sol"; +``` + +### Implementation Pattern +```solidity +contract MyContract is AccessControl { + bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE"); + + constructor(address admin) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _grantRole(KEEPER_ROLE, admin); + } + + function restrictedFunction() external onlyRole(KEEPER_ROLE) { + // Only keepers can call + } + + function addKeeper(address keeper) external onlyRole(DEFAULT_ADMIN_ROLE) { + _grantRole(KEEPER_ROLE, keeper); + } +} +``` + +--- + +## 4. Struct Storage Patterns + +### Packed Struct (2 slots) +```solidity +struct Position { + uint128 ptAmount; // Slot 0 (16 bytes) + uint128 bookValue; // Slot 0 (16 bytes) + uint64 lastUpdateTime; // Slot 1 (8 bytes) + uint64 maturityTimestamp; // Slot 1 (8 bytes) + uint128 _reserved; // Slot 1 (16 bytes) +} +``` + +### Nested Mapping +```solidity +// vault => market => Position +mapping(address => mapping(address => Position)) public positions; +``` + +--- + +## 5. Event Patterns + +```solidity +// Maximum 3 indexed parameters +event PositionOpened( + address indexed vault, + address indexed market, + address indexed pt, + uint256 ptAmount, + uint256 bookValue, + uint256 maturityTimestamp +); +``` diff --git a/specs/pendle-pt-amortized-pricing/research/repo-analysis.md b/specs/pendle-pt-amortized-pricing/research/repo-analysis.md new file mode 100644 index 000000000..d3590151b --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/research/repo-analysis.md @@ -0,0 +1,142 @@ +# Repository Research Summary + +## Architecture & Structure + +### Core Oracle Files in v2-core + +| File Path | Description | +|-----------|-------------| +| `v2-core/src/interfaces/accounting/IYieldSourceOracle.sol` | Interface defining all methods a YieldSourceOracle must implement | +| `v2-core/src/accounting/oracles/AbstractYieldSourceOracle.sol` | Abstract base class with common functionality and batch methods | +| `v2-core/src/accounting/oracles/PendlePTYieldSourceOracle.sol` | Current Pendle PT oracle using mark-to-market TWAP pricing | + +### IYieldSourceOracle Interface + +**Required Methods:** +```solidity +// Core pricing methods +function decimals(address yieldSourceAddress) external view returns (uint8); +function getShareOutput(address yieldSourceAddress, address assetIn, uint256 assetsIn) external view returns (uint256); +function getWithdrawalShareOutput(address yieldSourceAddress, address assetIn, uint256 assetsIn) external view returns (uint256); +function getAssetOutput(address yieldSourceAddress, address assetIn, uint256 sharesIn) external view returns (uint256); +function getPricePerShare(address yieldSourceAddress) external view returns (uint256); + +// TVL methods +function getTVLByOwnerOfShares(address yieldSourceAddress, address ownerOfShares) external view returns (uint256); +function getBalanceOfOwner(address yieldSourceAddress, address ownerOfShares) external view returns (uint256); +function getTVL(address yieldSourceAddress) external view returns (uint256); +``` + +### Current PendlePTYieldSourceOracle + +```solidity +// Key constants +uint32 public immutable TWAP_DURATION; // 15 minutes default +uint256 private constant PRICE_DECIMALS = 18; + +// Core pricing - uses Pendle's TWAP oracle (mark-to-market) +function getPricePerShare(address market) public view override returns (uint256 price) { + price = IPMarket(market).getPtToAssetRate(TWAP_DURATION); +} +``` + +--- + +## Cost-Basis Tracking Patterns + +### BaseLedger.sol Pattern + +**State Variables:** +```solidity +// Tracks total shares per user per yield source +mapping(address user => mapping(address yieldSource => uint256 shares)) public usersAccumulatorShares; + +// Tracks total cost basis (in asset terms) per user per yield source +mapping(address user => mapping(address yieldSource => uint256 costBasis)) public usersAccumulatorCostBasis; +``` + +**Weighted Average Cost Basis Calculation:** +```solidity +function calculateCostBasisView(address user, address yieldSource, uint256 usedShares) + public view returns (uint256 costBasis, uint256 shares) +{ + uint256 accumulatorShares = usersAccumulatorShares[user][yieldSource]; + uint256 accumulatorCostBasis = usersAccumulatorCostBasis[user][yieldSource]; + + // Proportional cost basis calculation + costBasis = usedShares > 0 ? Math.mulDiv(accumulatorCostBasis, usedShares, accumulatorShares) : 0; +} +``` + +--- + +## Access Control Patterns - KEEPER_ROLE + +### SuperformGasOracle.sol Pattern + +```solidity +bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE"); + +contract SuperformGasOracle is AggregatorV3Interface, AccessControl { + constructor(int256 initialGasPrice, address admin_) { + _grantRole(DEFAULT_ADMIN_ROLE, admin_); + _grantRole(KEEPER_ROLE, admin_); + } + + function setGasPrice(int256 newGasPrice) external onlyRole(KEEPER_ROLE) { + // ... + } +} +``` + +--- + +## SuperVaultStrategy Integration + +### Yield Source Management + +```solidity +// Yield source to oracle mapping +mapping(address source => address oracle) private yieldSources; + +function manageYieldSource(address source, address oracle, YieldSourceAction actionType) external { + _isPrimaryManager(msg.sender); + _manageYieldSource(source, oracle, actionType); +} +``` + +### PPS Integration + +```solidity +function getStoredPPS() public view returns (uint256) { + return _getSuperVaultAggregator().getPPS(address(this)); +} +``` + +--- + +## Test Patterns + +### Fork Test Setup +```solidity +function test_PendlePtOracle_takeSnapshot() public { + uint256 ethFork = vm.createFork(vm.envString(ETHEREUM_RPC_URL_KEY), 22_579_300); + vm.selectFork(ethFork); + + address market = address(0x8539B41CA14148d1F7400d399723827a80579414); + PendlePTYieldSourceOracle tempOracle = new PendlePTYieldSourceOracle(address(ledgerConfig)); + // ... +} +``` + +### Access Control Tests +```solidity +function test_SetGasPrice_RevertsNonKeeper() public { + address nonKeeper = makeAddr("nonKeeper"); + vm.prank(nonKeeper); + vm.expectRevert( + abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, nonKeeper, KEEPER_ROLE) + ); + gasOracle.setGasPrice(50); +} +``` diff --git a/specs/pendle-pt-amortized-pricing/research/specflow-analysis.md b/specs/pendle-pt-amortized-pricing/research/specflow-analysis.md new file mode 100644 index 000000000..dccff6ca4 --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/research/specflow-analysis.md @@ -0,0 +1,100 @@ +# SpecFlow Analysis: Pendle PT Amortized Pricing Oracle + +## Critical Questions Requiring Clarification + +### 🔴 CRITICAL (Blocks Implementation) + +**Q1: How is maturity time T initialized on first purchase?** +- **Answer**: Read from PT contract via `IPPrincipalToken(pt).expiry()` where PT is obtained from `IPMarket(market).readTokens()` + +**Q2: What is the exact formula for updating B(t0) on subsequent purchases?** +- **Answer**: From SV-1095 proposal: + - First calculate current B(t): `B(t) = A - (A - B(t0)) × (T - t) / (T - t0)` + - New B(t0) = B(t) + (additionalPT × price) + - New A = A + additionalPT + - New t0 = t (current time) + +**Q3: How does the formula handle t = T and t > T?** +- **Answer**: Special case - if `t >= T`, return `B(T) = A` (face value). The formula naturally converges to A at maturity. + +**Q4: Should recordRedemption validate that ptAmount <= A?** +- **Answer**: Yes, require `ptAmount <= A`, revert with `INSUFFICIENT_POSITION` otherwise. + +**Q5: What are the exact parameter types for vault and market?** +- **Answer**: + - `vault`: address (SuperVault contract) + - `market`: address (Pendle Market address, not PT token) + - Market is used to derive PT via `readTokens()` + +**Q6: How is the Admin role initialized on deployment?** +- **Answer**: Constructor takes `admin` address parameter, grants `DEFAULT_ADMIN_ROLE` and `MANAGER_ROLE` to admin. + +**Q7: What units/decimals are ptAmount, sySpent, and B(t) in?** +- **Answer**: All use 18 decimals (standard). PT amount in PT decimals, sySpent/B(t) in SY decimals (typically 18). + +--- + +## Key Edge Cases + +| Scenario | Expected Behavior | +|----------|-------------------| +| First purchase | Initialize A, t0, B(t0), T from PT contract | +| Purchase at/after maturity | Revert with `MARKET_EXPIRED` | +| Redemption > holdings | Revert with `INSUFFICIENT_POSITION` | +| Query at maturity (t=T) | Return B(T) = A | +| Query after maturity (t>T) | Return B(T) = A (capped) | +| Query no position | Revert with `NO_POSITION` | +| Full redemption (A→0) | Keep state with A=0, subsequent queries return 0 | +| Zero amount purchase | Revert with `ZERO_AMOUNT` | + +--- + +## Events Required + +```solidity +event PositionOpened( + address indexed vault, + address indexed market, + uint256 ptAmount, + uint256 bookValue, + uint256 maturityTimestamp +); + +event PositionIncreased( + address indexed vault, + address indexed market, + uint256 additionalPt, + uint256 newTotalPt, + uint256 newBookValue +); + +event PositionReduced( + address indexed vault, + address indexed market, + uint256 redeemedPt, + uint256 remainingPt, + uint256 remainingBookValue +); +``` + +--- + +## Integration Flow + +``` +Strategy executes PT buy on Pendle + ↓ +Keeper monitors strategy transactions + ↓ +Keeper calls recordPurchase(vault, market, ptAmount, sySpent) + ↓ +Oracle stores: A, t0, B(t0), T + ↓ +Pricing service calls getBookValue(vault, market) + ↓ +Oracle calculates B(t) using amortization formula + ↓ +Pricing service applies Step 3 conversion (SY→Asset) + ↓ +Pricing service pushes PPS to aggregator +``` diff --git a/specs/pendle-pt-amortized-pricing/research/sv-1095-proposal.md b/specs/pendle-pt-amortized-pricing/research/sv-1095-proposal.md new file mode 100644 index 000000000..488760a97 --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/research/sv-1095-proposal.md @@ -0,0 +1,109 @@ +# SV-1095 - PT Pricing Proposal for the Boring Strategy + +**Source:** Internal research document by quant team + +## High Level Idea + +Pricing PTs with their market price is conservative (always marked to market) but has downsides: +- High volatility due to thin Pendle AMM/OB liquidity + +For the **Boring Strategy** (buy PT, hold to maturity), we use **linear discounting with amortized-cost accounting**. + +--- + +## Mathematical Framework + +### Single Purchase Formula + +$$ +\text{Value}(t) = P_0 + (1 - P_0) \cdot \frac{t - t_0}{T - t_0} +$$ + +Where: +- $P_0$ = purchase price +- $t_0$ = purchase time +- $T$ = maturity time + +### Multiple Purchases - Weighted Averages + +For purchases $(A_i, P_i, t_i)$: + +$$ +\tilde{P} = \frac{\sum_{i=1}^{n} A_i P_i}{\sum_{i=1}^{n} A_i} +$$ + +$$ +\tilde{t}_0 = \frac{\sum_{i=1}^{n} A_i t_i}{\sum_{i=1}^{n} A_i} +$$ + +--- + +## Inventory Pricing Framework (Recommended) + +### State Variables + +- $T$ = PT Maturity (param) +- $A$ = Total PT amount held +- $t_0$ = Last time $A$ changed +- $B(t_0)$ = Last book value update + +### Book Value Formula + +$$ +B(t; A, t_0, T) = A - (A - B(t_0)) \cdot \frac{T - t}{T - t_0} +$$ + +**Properties:** +- At $t = t_0$: $B(t_0) = B(t_0)$ ✓ +- At $t = T$: $B(T) = A$ (face value) ✓ +- Linear interpolation between + +--- + +## Update Rules + +### Initialization +When buying $A$ PTs at price $P$: +$$B(t_0) = A \cdot P$$ + +### Buying More PTs +When buying $\Delta A$ PTs at price $P$: +1. $B(t) \leftarrow B(t; A, t_0, T) + \Delta A \cdot P$ +2. $A \leftarrow A + \Delta A$ +3. $t_0 \leftarrow t$ + +### Selling PTs +When selling $\Delta A$ PTs at price $P$: + +First calculate cost basis: +$$c(t) = \frac{B(t)}{A}$$ + +Then update: +1. $B(t) \leftarrow B(t; A, t_0, T) - \Delta A \cdot c(t)$ +2. $A \leftarrow A - \Delta A$ +3. $t_0 \leftarrow t$ + +Realized PnL: +$$\text{PnL} = \Delta A \cdot (P - c(t))$$ + +--- + +## Numerical Example + +**Setup:** T = 100 + +| Trade | Time | Action | Price | A | B(t) | Notes | +|-------|------|--------|-------|---|------|-------| +| 1 | 0 | Buy 100 | 0.90 | 100 | 90 | Initial | +| 2 | 20 | Buy 50 | 0.92 | 150 | 138 | B(20)=92, +46 | +| 3 | 50 | Buy 25 | 0.95 | 175 | 166.25 | B(50)=142.5, +23.75 | +| 4 | 70 | Sell 60 | 0.96 | 115 | 111.55 | c=0.97, PnL=-0.6 | + +--- + +## Key Insight + +The **Book Value approach** is cleaner than tracking average price + average time: +- Directly tracks what matters for PPS calculation +- Natural handling of buys and sells +- Cost basis automatically derived as $B(t)/A$ diff --git a/specs/pendle-pt-amortized-pricing/spec.md b/specs/pendle-pt-amortized-pricing/spec.md new file mode 100644 index 000000000..018298923 --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/spec.md @@ -0,0 +1,147 @@ +# Pendle PT Amortized Pricing Oracle Spec + +## Metadata +- Project: v2-periphery +- Milestone: PT Pricing Improvements +- Linear Issue: SV-1095 +- Interview Date: 2026-01-21 +- Status: [x] Draft / [ ] Ready for Review / [ ] Approved + +## Summary + +Implement a new `PendlePTAmortizedOracle` contract that provides **amortized cost pricing** for Pendle PT positions in SuperVaults. This replaces volatile mark-to-market pricing with deterministic, linear pull-to-par pricing suitable for the "Boring Strategy" (hold-to-maturity). + +**Purpose:** Properly price the PT token subset of SuperVault Strategy total assets. Once priced, this value is added to other assets to get total assets, then divided by shares to get PPS. + +The oracle uses Book Value accounting: `B(t) = A - (A - B(t0)) × (T - t) / (T - t0)`, where the price linearly converges from purchase price to face value at maturity. + +## Requirements + +### Functional +1. **Track only 2 variables per vault/market:** `lastUpdateBookValue` (B(t0)) and `lastUpdateTime` (t0) +2. **Read on-demand:** `ptAmount` from `IERC20(PT).balanceOf(strategy)`, `maturityTime` from `IPrincipalToken(PT).expiry()` +3. Calculate amortized book value using linear pull-to-par formula +4. Support multiple PT markets with different maturities per vault +5. Record purchases and redemptions via authorized keeper role (updates tracked variables per update rules) +6. Return current book value for PPS calculation + +### Non-Functional +- Deterministic: Same result at same block height (validator network consensus) +- Transparent: Events for all state changes (Hypernative monitoring) +- Gas efficient: View functions < 20k gas +- Safe: OpenZeppelin AccessControl, Math.mulDiv, and SafeCast +- Input validation: Sanity checks on keeper inputs (sySpent ≤ ptAmount) + +## Technical Design + +### Architecture + +``` +┌─────────────────┐ ┌──────────────────────────┐ +│ SuperVault │ │ PendlePTAmortizedOracle │ +│ Strategy │────▶│ ─────────────────────── │ +└─────────────────┘ │ STORED (per vault/pt): │ + │ │ - lastUpdateBookValue │ + ▼ │ - lastUpdateTime │ +┌─────────────────┐ │ │ +│ Keeper │────▶│ READ ON-DEMAND: │ +│ (records txns) │ │ - ptAmount from ERC20 │ +└─────────────────┘ │ - maturityTime from PT │ + └──────────────────────────┘ + │ + ▼ + ┌──────────────────────────┐ + │ Strategy.totalAssets() │ + │ - getBookValue() for PT │ + │ - + other assets │ + │ - / shares = PPS │ + └──────────────────────────┘ +``` + +### Data Model + +```solidity +// Only 2 variables need tracking - the rest are read on-demand +struct BookValueState { + uint128 lastUpdateBookValue; // B(t0): Book value at last update + uint64 lastUpdateTime; // t0: Timestamp of last update +} + +mapping(address vault => mapping(address pt => BookValueState)) public bookValues; + +// Read on-demand: +// ptAmount (A) = IERC20(pt).balanceOf(strategy) +// maturityTime (T) = IPrincipalToken(pt).expiry() +``` + +### API + +```solidity +// Keeper functions (KEEPER_ROLE required) - update the 2 tracked variables +function recordPurchase(address vault, address strategy, address pt, uint256 sySpent) external; +function recordRedemption(address vault, address strategy, address pt, uint256 ptRedeemed) external; + +// View functions (public) +function getBookValue(address vault, address strategy, address pt) external view returns (uint256); +``` + +## Implementation Plan + +### Phase 1: Core Contract +- [ ] Create `PendlePTAmortizedOracle.sol` with minimal `BookValueState` storage +- [ ] Implement `_calculateBookValue()` with amortization formula (reads ptAmount & maturity on-demand) +- [ ] Implement `recordPurchase()` - updates lastUpdateBookValue and lastUpdateTime per update rules +- [ ] Implement `recordRedemption()` - updates with cost basis accounting per update rules +- [ ] Add AccessControl with KEEPER_ROLE and MANAGER_ROLE + +### Phase 2: View Functions & Events +- [ ] Implement `getBookValue()` - reads ptAmount from balanceOf, maturity from expiry() +- [ ] Add events: BookValueUpdated + +### Phase 3: Testing +- [ ] Unit tests for amortization math and edge cases +- [ ] Integration tests for full position lifecycle +- [ ] Fork tests against real Pendle markets + +## Test Plan +- [ ] Unit tests for: `_calculateBookValue` formula, update rules (buy/sell) +- [ ] Integration tests for: full lifecycle, access control +- [ ] Fork tests for: real Pendle PT token integration (balanceOf, expiry) + +## Risks & Mitigations +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|------------| +| Keeper records incorrect values | Medium | High | Event monitoring, sanity checks | +| Keeper fails to record | Medium | Medium | Alerts, TWAP fallback | +| Overflow in calculations | Low | High | OpenZeppelin Math.mulDiv | + +## Open Questions (Resolved) +| Question | Answer | Decided By | +|----------|--------|------------| +| Where should logic live? | New dedicated oracle | Cosmin | +| How to record purchases? | Keeper/executor call | Cosmin | +| Multi-market support? | Yes, per vault/market | Cosmin | +| Migration approach? | Fresh start | Cosmin | +| Fallback behavior? | Revert if no position | Cosmin | + +## Interview Notes +See: [interview-notes.md](./interview-notes.md) + +## Technical Details +See: [technical-spec.md](./technical-spec.md) + +## Research +See: [research/](./research/) +- [sv-1095-proposal.md](./research/sv-1095-proposal.md) - Mathematical framework +- [repo-analysis.md](./research/repo-analysis.md) - Existing patterns +- [best-practices.md](./research/best-practices.md) - Industry practices +- [specflow-analysis.md](./research/specflow-analysis.md) - Flow analysis + +--- + +## Approval +- [ ] Pod Leader Approved +- Approved date: ___ + +## Next Steps +After approval, run: `/superform:work specs/pendle-pt-amortized-pricing/technical-spec.md` diff --git a/specs/pendle-pt-amortized-pricing/technical-spec.md b/specs/pendle-pt-amortized-pricing/technical-spec.md new file mode 100644 index 000000000..e7f9563e3 --- /dev/null +++ b/specs/pendle-pt-amortized-pricing/technical-spec.md @@ -0,0 +1,392 @@ +# Pendle PT Amortized Pricing Oracle - Technical Specification + +## Overview + +A new oracle contract that provides **amortized cost pricing** for Pendle Principal Token (PT) positions held by SuperVaults. This replaces mark-to-market pricing (which causes PPS volatility) with a deterministic, linear pull-to-par pricing model suitable for the "Boring Strategy" (hold-to-maturity). + +## Problem Statement + +The current `PendlePTYieldSourceOracle` uses `getPtToAssetRate()` which returns: +- Mark-to-market pricing based on AMM supply/demand +- High volatility due to thin Pendle liquidity +- PPS swings even though PT converges to 1:1 at maturity + +For a hold-to-maturity strategy, this volatility is misleading and unnecessary. + +## Proposed Solution + +**Purpose:** Properly price the PT token subset of SuperVault Strategy total assets for PPS calculation. + +Implement **Book Value accounting** that: +1. **Stores only 2 variables:** `lastUpdateBookValue` (B(t0)) and `lastUpdateTime` (t0) +2. **Reads on-demand:** `ptAmount` from `IERC20(pt).balanceOf(strategy)`, `maturityTime` from `IPrincipalToken(pt).expiry()` +3. Calculates amortized value using linear interpolation to maturity +4. Emits events for monitoring + +--- + +## Technical Approach + +### Mathematical Framework + +**Book Value Formula** (from SV-1095): + +$$ +B(t) = A - (A - B(t_0)) \times \frac{T - t}{T - t_0} +$$ + +Where: +- `B(t)` = Book value at time t +- `A` = Total PT amount held (face value at maturity) +- `B(t0)` = Book value at last state update +- `t0` = Timestamp of last state update +- `T` = PT maturity timestamp +- `t` = Current timestamp (`block.timestamp`) + +**Properties:** +- At `t = t0`: `B(t0) = B(t0)` ✓ +- At `t = T`: `B(T) = A` (converges to face value) ✓ +- Linear interpolation between + +### State Structure + +```solidity +// Minimal storage - only track what can't be read from chain +struct BookValueState { + uint128 lastUpdateBookValue; // B(t0): Book value at last update + uint64 lastUpdateTime; // t0: Last state change timestamp +} +// Total: 1 storage slot (24 bytes) + +// Variables read on-demand from chain: +// ptAmount (A) = IERC20(pt).balanceOf(strategy) +// maturityTime (T) = IPrincipalToken(pt).expiry() +``` + +### Update Rules + +Only `lastUpdateBookValue` and `lastUpdateTime` are stored/updated. The keeper calls these functions when purchases/redemptions occur. + +**Initialization (First Purchase):** +``` +lastUpdateBookValue = sySpent +lastUpdateTime = block.timestamp +``` + +**Subsequent Purchase (Buying ΔA PTs for sySpent):** +``` +B_current = getBookValue() // B(t) at current time +lastUpdateBookValue = B_current + sySpent +lastUpdateTime = block.timestamp +``` + +**Redemption (Selling ΔA PTs):** +``` +A = IERC20(pt).balanceOf(strategy) // read current amount BEFORE redemption +B_current = getBookValue() // B(t) at current time +costBasis = B_current / A // Average cost per PT +lastUpdateBookValue = B_current - (ΔA × costBasis) +lastUpdateTime = block.timestamp +``` + +--- + +## Implementation + +### Contract: PendlePTAmortizedOracle.sol + +```solidity +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.30; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IPPrincipalToken} from "@pendle/interfaces/IPPrincipalToken.sol"; + +/// @title PendlePTAmortizedOracle +/// @author Superform Labs +/// @notice Provides amortized cost pricing for Pendle PT positions +/// @dev Uses Book Value accounting with linear pull-to-par amortization +/// @dev Only stores 2 variables; reads ptAmount and maturity from chain +contract PendlePTAmortizedOracle is AccessControl { + using Math for uint256; + using SafeCast for uint256; + + // ============ Constants ============ + + bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE"); + bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); + + // ============ Structs ============ + + /// @notice Minimal state - only what can't be read from chain + /// @dev Packed into 1 storage slot (24 bytes) + struct BookValueState { + uint128 lastUpdateBookValue; // B(t0): Book value at last update + uint64 lastUpdateTime; // t0: Timestamp of last update + } + + // ============ Storage ============ + + /// @notice Book value state per vault per strategy per PT + mapping(address vault => mapping(address strategy => mapping(address pt => BookValueState))) public bookValues; + + // ============ Events ============ + + event BookValueUpdated( + address indexed vault, + address indexed strategy, + address indexed pt, + uint256 newBookValue, + uint256 timestamp + ); + + // ============ Errors ============ + + error ZERO_ADDRESS(); + error ZERO_AMOUNT(); + error NO_POSITION(); + error MARKET_EXPIRED(); + error INSUFFICIENT_POSITION(); + error BOOK_VALUE_EXCEEDS_FACE_VALUE(); + + // ============ Constructor ============ + + constructor(address admin) { + if (admin == address(0)) revert ZERO_ADDRESS(); + + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _grantRole(MANAGER_ROLE, admin); + _setRoleAdmin(KEEPER_ROLE, MANAGER_ROLE); + } + + // ============ Keeper Functions ============ + + /// @notice Record a PT purchase - updates lastUpdateBookValue and lastUpdateTime + /// @param vault The SuperVault address + /// @param strategy The strategy address holding the PT + /// @param pt The PT token address + /// @param sySpent Amount of SY spent (book value increment) + function recordPurchase( + address vault, + address strategy, + address pt, + uint256 sySpent + ) external onlyRole(KEEPER_ROLE) { + if (vault == address(0) || strategy == address(0) || pt == address(0)) revert ZERO_ADDRESS(); + if (sySpent == 0) revert ZERO_AMOUNT(); + + uint256 maturity = IPPrincipalToken(pt).expiry(); + if (block.timestamp >= maturity) revert MARKET_EXPIRED(); + + BookValueState storage state = bookValues[vault][strategy][pt]; + + // Calculate current book value (if position exists) and add new purchase + uint256 newBookValue; + if (state.lastUpdateTime > 0) { + uint256 currentBookValue = _calculateBookValue(vault, strategy, pt); + newBookValue = currentBookValue + sySpent; + } else { + // First purchase + newBookValue = sySpent; + } + + // Sanity check: book value should not exceed face value (ptAmount) + // This catches keeper errors where sySpent is recorded larger than actual + uint256 ptAmount = IERC20(pt).balanceOf(strategy); + if (newBookValue > ptAmount) revert BOOK_VALUE_EXCEEDS_FACE_VALUE(); + + state.lastUpdateBookValue = newBookValue.toUint128(); + state.lastUpdateTime = block.timestamp.toUint64(); + + emit BookValueUpdated(vault, strategy, pt, newBookValue, block.timestamp); + } + + /// @notice Record a PT redemption - updates using cost basis accounting + /// @dev Must be called BEFORE the redemption changes balanceOf + /// @param vault The SuperVault address + /// @param strategy The strategy address holding the PT + /// @param pt The PT token address + /// @param ptRedeemed Amount of PT being redeemed + function recordRedemption( + address vault, + address strategy, + address pt, + uint256 ptRedeemed + ) external onlyRole(KEEPER_ROLE) { + if (vault == address(0) || strategy == address(0) || pt == address(0)) revert ZERO_ADDRESS(); + if (ptRedeemed == 0) revert ZERO_AMOUNT(); + + BookValueState storage state = bookValues[vault][strategy][pt]; + if (state.lastUpdateTime == 0) revert NO_POSITION(); + + // Read current PT amount BEFORE redemption + uint256 ptAmount = IERC20(pt).balanceOf(strategy); + if (ptRedeemed > ptAmount) revert INSUFFICIENT_POSITION(); + + uint256 currentBookValue = _calculateBookValue(vault, strategy, pt); + + // Cost basis accounting + uint256 costBasis = currentBookValue.mulDiv(ptRedeemed, ptAmount); + uint256 newBookValue = currentBookValue - costBasis; + + state.lastUpdateBookValue = newBookValue.toUint128(); + state.lastUpdateTime = block.timestamp.toUint64(); + + emit BookValueUpdated(vault, strategy, pt, newBookValue, block.timestamp); + } + + // ============ View Functions ============ + + /// @notice Get the current amortized book value for a position + /// @param vault The SuperVault address + /// @param strategy The strategy address holding the PT + /// @param pt The PT token address + /// @return bookValue Current amortized book value + function getBookValue( + address vault, + address strategy, + address pt + ) external view returns (uint256 bookValue) { + BookValueState memory state = bookValues[vault][strategy][pt]; + if (state.lastUpdateTime == 0) revert NO_POSITION(); + return _calculateBookValue(vault, strategy, pt); + } + + // ============ Admin Functions ============ + + function addKeeper(address keeper) external onlyRole(MANAGER_ROLE) { + _grantRole(KEEPER_ROLE, keeper); + } + + function removeKeeper(address keeper) external onlyRole(MANAGER_ROLE) { + _revokeRole(KEEPER_ROLE, keeper); + } + + // ============ Internal Functions ============ + + /// @notice Calculate current book value using amortization formula + /// @dev B(t) = A - (A - B(t0)) × (T - t) / (T - t0) + /// @dev Reads ptAmount and maturity from chain + function _calculateBookValue( + address vault, + address strategy, + address pt + ) internal view returns (uint256) { + BookValueState memory state = bookValues[vault][strategy][pt]; + + // Read from chain + uint256 A = IERC20(pt).balanceOf(strategy); // ptAmount + uint256 T = IPPrincipalToken(pt).expiry(); // maturityTime + uint256 B_t0 = state.lastUpdateBookValue; + uint256 t0 = state.lastUpdateTime; + + // Edge case: no PT held + if (A == 0) return 0; + + // At or after maturity, book value = face value (A) + if (block.timestamp >= T) { + return A; + } + + // Before any time has passed, book value = B(t0) + if (block.timestamp <= t0) { + return B_t0; + } + + // Linear amortization: B(t) = A - (A - B(t0)) × (T - t) / (T - t0) + uint256 timeRemaining = T - block.timestamp; + uint256 totalDuration = T - t0; + + uint256 unamortizedDiscount = (A - B_t0).mulDiv(timeRemaining, totalDuration); + + return A - unamortizedDiscount; + } +} +``` + +--- + +## Acceptance Criteria + +### Functional Requirements + +- [ ] Oracle stores only 2 variables per vault/strategy/pt: `lastUpdateBookValue` and `lastUpdateTime` +- [ ] Oracle reads `ptAmount` from `IERC20(pt).balanceOf(strategy)` on-demand +- [ ] Oracle reads `maturityTime` from `IPPrincipalToken(pt).expiry()` on-demand +- [ ] `recordPurchase()` updates book value state per update rules +- [ ] `recordRedemption()` updates book value state using cost basis accounting +- [ ] `getBookValue()` returns linearly amortized value converging to face value at maturity +- [ ] Access control: KEEPER_ROLE for recording, MANAGER_ROLE for keeper management + +### Non-Functional Requirements + +- [ ] **Deterministic**: Same B(t) at same block.timestamp across all validators +- [ ] **Transparent**: All state changes emit `BookValueUpdated` event +- [ ] **Gas efficient**: Minimal storage (1 slot), reads from chain +- [ ] **Safe math**: Uses OpenZeppelin Math.mulDiv and SafeCast + +### Edge Cases + +- [ ] At maturity (t = T): Returns B(T) = A (face value) +- [ ] After maturity (t > T): Returns B(T) = A (capped, no extrapolation) +- [ ] No position exists: Reverts with `NO_POSITION` +- [ ] Purchase after maturity: Reverts with `MARKET_EXPIRED` +- [ ] Zero amounts: Reverts with `ZERO_AMOUNT` +- [ ] Zero PT balance: Returns 0 +- [ ] Redemption exceeds holdings: Reverts with `INSUFFICIENT_POSITION` +- [ ] Book value exceeds face value: Reverts with `BOOK_VALUE_EXCEEDS_FACE_VALUE` + +--- + +## Test Plan + +### Unit Tests + +- [ ] `_calculateBookValue()` returns correct values at t0, mid-duration, and maturity +- [ ] Purchase update rule: B(t) + sySpent +- [ ] Redemption update rule: cost basis accounting +- [ ] All error conditions revert with correct errors +- [ ] SafeCast reverts on overflow + +### Integration Tests + +- [ ] Full lifecycle: purchase → query → purchase → query → redemption → query +- [ ] Access control: keeper can record, non-keeper cannot +- [ ] Event emissions match state changes + +### Fork Tests + +- [ ] Against real Pendle PT tokens on Ethereum mainnet +- [ ] Verify `balanceOf()` reads work correctly +- [ ] Verify `expiry()` reads work correctly + +--- + +## Dependencies & Prerequisites + +- OpenZeppelin Contracts (AccessControl, Math, SafeCast, IERC20) +- Pendle Core V2 interfaces (IPPrincipalToken for `expiry()`) +- Keeper infrastructure to monitor strategy transactions and call recording functions + +--- + +## Risks & Mitigations + +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|------------| +| Keeper records incorrect values | Medium | High | Event monitoring, sanity bounds checking | +| Keeper fails to record purchases | Medium | Medium | Monitoring alerts, fallback to TWAP | +| Integer overflow in calculations | Low | High | Use OpenZeppelin Math.mulDiv | +| Maturity timestamp manipulation | Very Low | High | Read from immutable PT contract | + +--- + +## References + +- [SV-1095 Proposal](/specs/pendle-pt-amortized-pricing/research/sv-1095-proposal.md) +- [Pendle Oracle Docs](https://docs.pendle.finance/pendle-v2/Developers/Oracles/) +- [Chaos Labs PT Risk Oracle](https://chaoslabs.xyz/posts/introducing-pendle-pt-risk-oracle) +- Current implementation: `v2-core/src/accounting/oracles/PendlePTYieldSourceOracle.sol` diff --git a/test/integration/SuperBank/SuperBankRevenueDistributionTests.t.sol b/test/integration/SuperBank/SuperBankRevenueDistributionTests.t.sol new file mode 100644 index 000000000..661026179 --- /dev/null +++ b/test/integration/SuperBank/SuperBankRevenueDistributionTests.t.sol @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.30; + +// testing +import { BaseSuperVaultTest } from "../SuperVault/BaseSuperVaultTest.t.sol"; +import { MockOdosRouterV2 } from "../../mocks/MockOdosRouterV2.sol"; + +// external +import { console2 } from "forge-std/console2.sol"; +import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; +import { Vm } from "forge-std/Vm.sol"; + +// superform +import { SuperBank } from "../../../src/SuperBank.sol"; +import { SuperGovernor } from "../../../src/SuperGovernor.sol"; +import { IHookExecutionData } from "../../../src/interfaces/IHookExecutionData.sol"; +import { FeeType } from "../../../src/interfaces/ISuperGovernor.sol"; +import { ISuperHookInspector } from "@superform-v2-core/src/interfaces/ISuperHook.sol"; + +// v2-core hooks +import { AcrossV3Helper } from "@superform-v2-core/lib/pigeon/src/across/AcrossV3Helper.sol"; +import { ApproveERC20Hook } from "@superform-v2-core/src/hooks/tokens/erc20/ApproveERC20Hook.sol"; +import { SwapOdosV2Hook } from "@superform-v2-core/src/hooks/swappers/odos/SwapOdosV2Hook.sol"; + +// mocks +import { MockUp } from "../../mocks/MockUp.sol"; + +/// @title SuperBankRevenueDistributionTests +/// @notice Integration tests for SuperBank revenue distribution, cross-chain bridging, and UP swapping +/// @dev Tests the production flow: REVENUE_SHARE → skim → bridge → swap +/// +/// NOTE: Time warps accumulate across helpers: +/// - _setRevenueShare: +7 days (governance timelock) +/// - _setFeeConfigToSuperBank: +1 week (fee config timelock) +/// - _setupFeesInSuperBank: +13 hours (skim timelock) +/// - _setupSuperBankHook: +7 days per hook (merkle root timelock) +/// Total time travel per test can exceed 14+ days. This is intentional for timelocks. +contract SuperBankRevenueDistributionTests is BaseSuperVaultTest { + // Core contracts + SuperBank public superBank; + + // Constants + uint256 constant REVENUE_SHARE_20_PERCENT = 2000; // 20% in BPS + + function setUp() public virtual override { + super.setUp(); + console2.log("--- SETUP SUPERBANK REVENUE DISTRIBUTION TESTS ---"); + + vm.selectFork(FORKS[ETH]); + + // Get SuperBank + superBank = SuperBank(payable(_getContract(ETH, SUPER_BANK_KEY))); + + console2.log("SuperBank address:", address(superBank)); + console2.log("Strategy address:", address(strategy)); + } + + /*////////////////////////////////////////////////////////////// + TEST 1: REVENUE_SHARE + SKIM + //////////////////////////////////////////////////////////////*/ + + /// @notice Test setting REVENUE_SHARE to 20% and skimming performance fees to SuperBank + function test_SetRevenueShareAndSkimFees() public { + console2.log("\n=== TEST 1: Set REVENUE_SHARE to 20% and Skim Fees ==="); + + uint256 depositAmount = 10_000e6; // 10k USDC + uint256 feesCollected = _setupFeesInSuperBank(depositAmount); + + console2.log("Fees collected by SuperBank:", feesCollected); + + // Verify revenue share was set correctly + uint256 currentRevenueShare = superGovernor.getFee(FeeType.REVENUE_SHARE); + assertEq(currentRevenueShare, REVENUE_SHARE_20_PERCENT, "Revenue share not set correctly"); + + // Verify fees actually went to SuperBank (strictly greater, not greater-or-equal) + assertGt(feesCollected, 0, "Fee collection cannot be zero"); + + console2.log("\n=== TEST 1 PASSED ==="); + } + + /*////////////////////////////////////////////////////////////// + TEST 2: REVENUE_SHARE + SKIM + BRIDGE + //////////////////////////////////////////////////////////////*/ + + /// @notice Test 1 + bridge funds from SuperBank on Ethereum to Base via Across + function test_SetRevenueShareSkimAndBridgeToBase() public { + console2.log("\n=== TEST 2: Set REVENUE_SHARE, Skim, and Bridge to Base ==="); + + // Setup fees in SuperBank using common helper + uint256 depositAmount = 10_000e6; + uint256 feesCollected = _setupFeesInSuperBank(depositAmount); + console2.log("Fees collected in SuperBank:", feesCollected); + + // Ensure we have funds to bridge (fallback if skim doesn't generate fees) + uint256 bridgeAmount = feesCollected > 0 ? feesCollected : 1000e6; + if (feesCollected == 0) { + deal(address(asset), address(superBank), bridgeAmount); + console2.log("Dealt USDC to SuperBank for bridging test:", bridgeAmount); + } + + // Setup hooks for SuperBank (Approve + Across) + address approveHook = hookAddresses[ETH][APPROVE_ERC20_HOOK_KEY]; + address acrossHook = hookAddresses[ETH][ACROSS_SEND_FUNDS_AND_EXECUTE_ON_DST_HOOK_KEY]; + address spokePoolV3 = SPOKE_POOL_V3_ADDRESSES[ETH]; + address baseUsdc = existingUnderlyingTokens[BASE][USDC_KEY]; + + // Get SuperBank address on Base and record balance + vm.selectFork(FORKS[BASE]); + address superBankBase = _getContract(BASE, SUPER_BANK_KEY); + uint256 baseSuperBankBalanceBefore = IERC20(baseUsdc).balanceOf(superBankBase); + vm.selectFork(FORKS[ETH]); + + // Create hook data for approve (approve SpokePool to transfer USDC) + bytes memory approveHookData = _createApproveHookData( + address(asset), // token to approve + spokePoolV3, // spender (Across SpokePool) + bridgeAmount, // amount + false // usePrevHookAmount + ); + + // Create hook data for Across bridge (no execution on destination) + bytes memory acrossHookData = _createAcrossV3ReceiveFundsNoExecution( + superBankBase, // recipient on Base + address(asset), // input token (ETH USDC) + baseUsdc, // output token (Base USDC) + bridgeAmount, // input amount + bridgeAmount * 99 / 100, // output amount (1% fee buffer) + BASE, // destination chain + false, // usePrevHookAmount + bytes("") // no message/execution on destination + ); + + // Setup hooks with their actual hook data + _setupSuperBankHook(approveHook, approveHookData); + _setupSuperBankHook(acrossHook, acrossHookData); + + // Bridge funds to Base via Across + address[] memory hooks = new address[](2); + hooks[0] = approveHook; + hooks[1] = acrossHook; + + bytes[] memory hookData = new bytes[](2); + hookData[0] = approveHookData; + hookData[1] = acrossHookData; + + bytes32[][] memory merkleProofs = new bytes32[][](2); + merkleProofs[0] = new bytes32[](0); // Single leaf, no proof needed + merkleProofs[1] = new bytes32[](0); + + uint256[] memory expectedOutputs = new uint256[](2); + expectedOutputs[0] = 0; // Approve hook returns 0 output + expectedOutputs[1] = 0; // Bridge hook returns 0 (bridge output is on destination) + + IHookExecutionData.HookExecutionData memory executionData = IHookExecutionData.HookExecutionData({ + hooks: hooks, + data: hookData, + merkleProofs: merkleProofs, + expectedAssetsOrSharesOut: expectedOutputs + }); + + // Record logs for Across helper + vm.recordLogs(); + + // Grant BANK_MANAGER_ROLE to this contract for testing + superGovernor.grantRole(superGovernor.BANK_MANAGER_ROLE(), address(this)); + + superBank.executeHooks(executionData); + Vm.Log[] memory logs = vm.getRecordedLogs(); + + // Process Across message to Base using pigeon + AcrossV3Helper(_getContract(ETH, ACROSS_V3_HELPER_KEY)).help( + SPOKE_POOL_V3_ADDRESSES[ETH], + SPOKE_POOL_V3_ADDRESSES[BASE], + ACROSS_RELAYER, + block.timestamp, + FORKS[BASE], + BASE, + ETH, + logs + ); + + // Verify funds arrived on Base + vm.selectFork(FORKS[BASE]); + uint256 baseSuperBankBalanceAfter = IERC20(baseUsdc).balanceOf(superBankBase); + + assertGt(baseSuperBankBalanceAfter, baseSuperBankBalanceBefore, "Base SuperBank should have received bridged funds"); + console2.log("Bridge result: received", baseSuperBankBalanceAfter - baseSuperBankBalanceBefore, "USDC on Base"); + + console2.log("=== TEST 2 PASSED ==="); + } + + /*////////////////////////////////////////////////////////////// + TEST 3: REVENUE_SHARE + SKIM + BRIDGE + SWAP + //////////////////////////////////////////////////////////////*/ + + // Struct to hold swap test state across phases + struct SwapTestState { + address baseUsdc; + address baseSuperBank; + uint256 bridgeAmount; + } + + /// @notice Test 1 + Test 2 + swap funds to UP on Base + /// @dev This test bridges USDC to Base, then executes a swap from USDC to UP on Base SuperBank + function test_SetRevenueShareSkimBridgeAndSwapToUP() public { + console2.log("\n=== TEST 3: Set REVENUE_SHARE, Skim, Bridge, and Swap to UP ==="); + + // Phase 1: Collect fees on ETH and bridge to Base + SwapTestState memory state = _phase1_CollectFeesAndBridge(); + + // Phase 2: Execute swap on Base + _phase2_ExecuteSwapOnBase(state); + + console2.log("\n=== TEST 3 PASSED ==="); + } + + /// @notice Phase 1: Collect fees on ETH and bridge to Base + function _phase1_CollectFeesAndBridge() internal returns (SwapTestState memory state) { + // Setup fees in SuperBank using common helper + uint256 depositAmount = 10_000e6; + uint256 feesCollected = _setupFeesInSuperBank(depositAmount); + + // Ensure we have funds to bridge (fallback if skim doesn't generate fees) + state.bridgeAmount = feesCollected > 0 ? feesCollected : 1000e6; + if (feesCollected == 0) { + deal(address(asset), address(superBank), state.bridgeAmount); + } + + state.baseUsdc = existingUnderlyingTokens[BASE][USDC_KEY]; + state.baseSuperBank = _getContract(BASE, SUPER_BANK_KEY); + + // Execute bridge + _executeBridgeToBase(state.bridgeAmount, state.baseSuperBank, state.baseUsdc); + } + + /// @notice Execute bridge from ETH to Base + function _executeBridgeToBase(uint256 bridgeAmount, address baseSuperBank, address baseUsdc) internal { + address approveHook = hookAddresses[ETH][APPROVE_ERC20_HOOK_KEY]; + address acrossHook = hookAddresses[ETH][ACROSS_SEND_FUNDS_AND_EXECUTE_ON_DST_HOOK_KEY]; + + bytes memory approveHookData = _createApproveHookData( + address(asset), SPOKE_POOL_V3_ADDRESSES[ETH], bridgeAmount, false + ); + bytes memory acrossHookData = _createAcrossV3ReceiveFundsNoExecution( + baseSuperBank, address(asset), baseUsdc, bridgeAmount, bridgeAmount * 99 / 100, BASE, false, bytes("") + ); + + _setupSuperBankHook(approveHook, approveHookData); + _setupSuperBankHook(acrossHook, acrossHookData); + + IHookExecutionData.HookExecutionData memory executionData = _createBridgeExecutionData( + approveHook, acrossHook, approveHookData, acrossHookData + ); + + vm.recordLogs(); + superGovernor.grantRole(superGovernor.BANK_MANAGER_ROLE(), address(this)); + superBank.executeHooks(executionData); + Vm.Log[] memory logs = vm.getRecordedLogs(); + + AcrossV3Helper(_getContract(ETH, ACROSS_V3_HELPER_KEY)).help( + SPOKE_POOL_V3_ADDRESSES[ETH], + SPOKE_POOL_V3_ADDRESSES[BASE], + ACROSS_RELAYER, + block.timestamp, + FORKS[BASE], + BASE, + ETH, + logs + ); + } + + /// @notice Create bridge execution data + function _createBridgeExecutionData( + address approveHook, + address acrossHook, + bytes memory approveHookData, + bytes memory acrossHookData + ) internal pure returns (IHookExecutionData.HookExecutionData memory) { + address[] memory hooks = new address[](2); + hooks[0] = approveHook; + hooks[1] = acrossHook; + + bytes[] memory hookData = new bytes[](2); + hookData[0] = approveHookData; + hookData[1] = acrossHookData; + + bytes32[][] memory merkleProofs = new bytes32[][](2); + merkleProofs[0] = new bytes32[](0); + merkleProofs[1] = new bytes32[](0); + + uint256[] memory expectedOutputs = new uint256[](2); + + return IHookExecutionData.HookExecutionData({ + hooks: hooks, + data: hookData, + merkleProofs: merkleProofs, + expectedAssetsOrSharesOut: expectedOutputs + }); + } + + /// @notice Phase 2: Execute swap on Base + function _phase2_ExecuteSwapOnBase(SwapTestState memory state) internal { + vm.selectFork(FORKS[BASE]); + + SuperBank baseSuperBankContract = SuperBank(payable(state.baseSuperBank)); + uint256 bridgedBalance = IERC20(state.baseUsdc).balanceOf(state.baseSuperBank); + assertGt(bridgedBalance, 0, "Should have received bridged funds"); + + // Deploy swap infrastructure + MockOdosRouterV2 router = new MockOdosRouterV2(); + MockUp upToken = new MockUp(address(this)); + ApproveERC20Hook approveHook = new ApproveERC20Hook(); + SwapOdosV2Hook swapHook = new SwapOdosV2Hook(address(router)); + + // Setup SuperGovernor on Base + SuperGovernor baseGov = SuperGovernor(address(baseSuperBankContract.SUPER_GOVERNOR())); + baseGov.registerHook(address(approveHook)); + baseGov.registerHook(address(swapHook)); + baseGov.grantRole(baseGov.BANK_MANAGER_ROLE(), address(this)); + + // Mint UP to router for swap output + uint256 expectedUp = bridgedBalance * 1e12; + upToken.mint(address(router), expectedUp); + + // Execute swap + _executeSwapOnBase(SwapExecutionParams({ + bank: baseSuperBankContract, + gov: baseGov, + usdc: state.baseUsdc, + upToken: address(upToken), + router: address(router), + approveHook: address(approveHook), + swapHook: address(swapHook), + swapAmount: bridgedBalance, + expectedUp: expectedUp + })); + } + + // Struct to reduce stack depth in swap execution + struct SwapExecutionParams { + SuperBank bank; + SuperGovernor gov; + address usdc; + address upToken; + address router; + address approveHook; + address swapHook; + uint256 swapAmount; + uint256 expectedUp; + } + + /// @notice Execute swap hooks on Base SuperBank + function _executeSwapOnBase(SwapExecutionParams memory p) internal { + bytes memory approveData = _createApproveHookData(p.usdc, p.router, p.swapAmount, false); + bytes memory swapData = _createSwapHookData(p.usdc, p.upToken, p.swapAmount, p.expectedUp); + + _setupSuperBankHookOnBase(p.gov, p.approveHook, approveData); + _setupSuperBankHookOnBase(p.gov, p.swapHook, swapData); + + IHookExecutionData.HookExecutionData memory execData = _createSwapExecutionData( + p.approveHook, p.swapHook, approveData, swapData + ); + + uint256 usdcBefore = IERC20(p.usdc).balanceOf(address(p.bank)); + uint256 upBefore = IERC20(p.upToken).balanceOf(address(p.bank)); + + p.bank.executeHooks(execData); + + _verifySwapResults(p.usdc, p.upToken, address(p.bank), usdcBefore, upBefore); + } + + /// @notice Verify swap results + function _verifySwapResults( + address usdc, + address upToken, + address bank, + uint256 usdcBefore, + uint256 upBefore + ) internal { + uint256 usdcAfter = IERC20(usdc).balanceOf(bank); + uint256 upAfter = IERC20(upToken).balanceOf(bank); + + assertLt(usdcAfter, usdcBefore, "USDC should have been swapped"); + assertGt(upAfter, upBefore, "UP balance should have increased"); + + console2.log("Swap complete: UP received", upAfter - upBefore); + } + + /// @notice Create swap hook data for Odos + function _createSwapHookData( + address inputToken, + address outputToken, + uint256 inputAmount, + uint256 outputQuote + ) internal pure returns (bytes memory) { + return abi.encodePacked( + inputToken, + inputAmount, + address(0), // executor + outputToken, + outputQuote, + outputQuote * 99 / 100, // minOut + false, // usePrevHookAmount + uint256(0), // pathDefinitionLength + bytes(""), // pathDefinition + address(0), // referralCode + uint32(0), // referralFee + false // compact + ); + } + + /// @notice Create swap execution data + function _createSwapExecutionData( + address approveHook, + address swapHook, + bytes memory approveData, + bytes memory swapData + ) internal pure returns (IHookExecutionData.HookExecutionData memory) { + address[] memory hooks = new address[](2); + hooks[0] = approveHook; + hooks[1] = swapHook; + + bytes[] memory hookData = new bytes[](2); + hookData[0] = approveData; + hookData[1] = swapData; + + bytes32[][] memory merkleProofs = new bytes32[][](2); + merkleProofs[0] = new bytes32[](0); + merkleProofs[1] = new bytes32[](0); + + uint256[] memory expectedOutputs = new uint256[](2); + + return IHookExecutionData.HookExecutionData({ + hooks: hooks, + data: hookData, + merkleProofs: merkleProofs, + expectedAssetsOrSharesOut: expectedOutputs + }); + } + + /// @notice Helper to setup hooks on Base SuperGovernor + function _setupSuperBankHookOnBase( + SuperGovernor baseGovernor, + address hook, + bytes memory hookDataForLeaf + ) internal { + _setupSuperBankHookWithGovernor(baseGovernor, hook, hookDataForLeaf); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL HELPERS + //////////////////////////////////////////////////////////////*/ + + /// @notice Common setup: configure revenue share, deposit, allocate, simulate yield, and skim fees + /// @param depositAmount Amount to deposit into SuperVault + /// @return feesCollected Amount of fees collected in SuperBank + function _setupFeesInSuperBank(uint256 depositAmount) internal returns (uint256 feesCollected) { + _setRevenueShare(REVENUE_SHARE_20_PERCENT); + _setFeeConfigToSuperBank(100); + _updateSuperVaultPPS(address(strategy), address(vault)); + + _deposit(depositAmount); + _depositFreeAssetsFromSingleAmount(depositAmount, address(fluidVault), address(aaveVault)); + + _updateSuperVaultPPS(address(strategy), address(vault)); + vm.warp(block.timestamp + 13 hours); + + // Simulate profit + deal(address(asset), address(strategy), 100e6); + _updateSuperVaultPPS(address(strategy), address(vault)); + + // Skim fees + uint256 balanceBefore = asset.balanceOf(address(superBank)); + vm.prank(MANAGER); + strategy.skimPerformanceFee(); + feesCollected = asset.balanceOf(address(superBank)) - balanceBefore; + } + + /// @notice Sets the REVENUE_SHARE fee via governance timelock + function _setRevenueShare(uint256 newRevenueShare) internal { + superGovernor.proposeFee(FeeType.REVENUE_SHARE, newRevenueShare); + vm.warp(block.timestamp + 7 days + 1); + superGovernor.executeFeeUpdate(FeeType.REVENUE_SHARE); + } + + /// @notice Sets fee configuration for the strategy with SuperBank as recipient + function _setFeeConfigToSuperBank(uint256 performanceFeeBps) internal { + vm.prank(MANAGER); + strategy.proposeVaultFeeConfigUpdate( + performanceFeeBps, + 0, // managementFeeBps + address(superBank) // recipient + ); + + vm.warp(block.timestamp + 1 weeks + 1); + + vm.prank(MANAGER); + strategy.executeVaultFeeConfigUpdate(); + } + + /// @notice Sets up a hook for SuperBank execution with proper merkle root (ETH chain) + function _setupSuperBankHook(address hook, bytes memory hookData) internal { + _setupSuperBankHookWithGovernor(superGovernor, hook, hookData); + } + + /// @notice Sets up a hook for SuperBank execution with proper merkle root (any chain) + function _setupSuperBankHookWithGovernor( + SuperGovernor governor, + address hook, + bytes memory hookData + ) internal { + bytes memory hookArgs = ISuperHookInspector(hook).inspect(hookData); + bytes32 leafHash = keccak256(bytes.concat(keccak256(abi.encode(hook, hookArgs)))); + + governor.proposeSuperBankHookMerkleRoot(hook, leafHash); + vm.warp(block.timestamp + 7 days + 1); + governor.executeSuperBankHookMerkleRootUpdate(hook); + } + +} diff --git a/test/integration/oracles/UpOracleUpdate.t.sol b/test/integration/oracles/UpOracleUpdate.t.sol new file mode 100644 index 000000000..901c2f041 --- /dev/null +++ b/test/integration/oracles/UpOracleUpdate.t.sol @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.30; + +import { Test } from "forge-std/Test.sol"; +import { console2 } from "forge-std/console2.sol"; + +import { SuperGovernor } from "../../../src/SuperGovernor.sol"; +import { SuperOracle } from "../../../src/oracles/SuperOracle.sol"; +import { FixedPriceOracle } from "../../../src/oracles/FixedPriceOracle.sol"; +import { ISuperOracle } from "../../../src/interfaces/oracles/ISuperOracle.sol"; +import { ISuperGovernor } from "../../../src/interfaces/ISuperGovernor.sol"; + +/// @title MockChainlinkUpOracle +/// @notice A mock Chainlink-compatible oracle that returns $1 per UP token +/// @dev Simulates what a real Chainlink UP/USD feed would look like +contract MockChainlinkUpOracle { + int256 private _answer; + uint8 private _decimals; + + constructor(int256 initialPrice, uint8 decimals_) { + _answer = initialPrice; + _decimals = decimals_; + } + + function decimals() external view returns (uint8) { + return _decimals; + } + + function description() external pure returns (string memory) { + return "UP / USD"; + } + + function version() external pure returns (uint256) { + return 1; + } + + function latestRoundData() + external + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, _answer, block.timestamp, block.timestamp, 1); + } + + function setPrice(int256 newPrice) external { + _answer = newPrice; + } +} + +/// @title UpOracleUpdateIntegrationTest +/// @notice Integration test for updating the UP token price oracle from FixedPriceOracle to a new Chainlink oracle +/// @dev Tests the full flow: +/// 1. Fork mainnet with real deployed contracts +/// 2. Deploy a new mock Chainlink oracle returning $1/UP +/// 3. Queue the oracle update via SuperGovernor +/// 4. Wait for timelock and execute the update +/// 5. Verify getQuoteFromProvider returns new price +/// 6. Simulate upkeep payment computation with new oracle +contract UpOracleUpdateIntegrationTest is Test { + // Production addresses from Ethereum-latest.json + address constant SUPER_GOVERNOR = 0xB5396ef2bF8CA360cEB4166b77AFb2bed20e74d4; + address constant SUPER_ORACLE = 0x8943128DbAb4279D561654dEED2930Bb975AA070; + address constant FIXED_PRICE_ORACLE = 0x66b30A0Dda7F868796ADC3d70232950D65F3565c; + address constant ECDSA_PPS_ORACLE = 0x366d88F03B8EF34eb49F32a927ff6e1609F694F2; + + // Chainlink oracle addresses (from trace analysis) + address constant CHAINLINK_GAS_ORACLE = 0x169E633A2D1E6c10dD91238Ba11c4A708dfEF37C; + address constant CHAINLINK_ETH_USD_ORACLE = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; + + // UP token address on mainnet (from SuperGovernor registry) + // We'll fetch this dynamically from the governor + address public upToken; + + // Oracle constants (must match SuperGovernor) + address constant NATIVE_TOKEN = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + address constant USD_TOKEN = address(840); + address constant GAS_QUOTE = address(uint160(uint256(keccak256("GAS_QUOTE")))); + address constant WEI_QUOTE = address(uint160(uint256(keccak256("WEI_QUOTE")))); + + // Provider identifiers + bytes32 constant PROVIDER_CHAINLINK = keccak256("CHAINLINK"); + bytes32 constant PROVIDER_SUPERFORM = keccak256("SUPERFORM"); + bytes32 constant AVERAGE_PROVIDER = keccak256("AVERAGE_PROVIDER"); + + // New UP price: $1 with 18 decimals (matches FixedPriceOracle format) + int256 constant NEW_UP_PRICE = 1e18; // $1.00 + uint8 constant UP_PRICE_DECIMALS = 18; + + // Timelock period (must match SuperOracleBase) + uint256 constant TIMELOCK_PERIOD = 1 weeks; + + // Contracts + SuperGovernor public governor; + SuperOracle public superOracle; + MockChainlinkUpOracle public newChainlinkOracle; + + // Test accounts - we'll impersonate the actual roles + address public oracleManager; + address public superGovernorRole; + + function setUp() public { + // Fork mainnet at latest block + vm.createSelectFork(vm.envString("ETHEREUM_RPC_URL")); + + // Load production contracts + governor = SuperGovernor(SUPER_GOVERNOR); + superOracle = SuperOracle(SUPER_ORACLE); + + // Get UP token address from governor registry + upToken = governor.getAddress(governor.UP()); + + // Get role holders from governor + // We need to find accounts with the appropriate roles + // For testing, we'll use the default admin which has all roles + superGovernorRole = _findRoleHolder(governor.SUPER_GOVERNOR_ROLE()); + oracleManager = _findRoleHolder(governor.ORACLE_MANAGER_ROLE()); + + console2.log("=== Production Contract Addresses ==="); + console2.log("SuperGovernor:", address(governor)); + console2.log("SuperOracle:", address(superOracle)); + console2.log("Current FixedPriceOracle:", FIXED_PRICE_ORACLE); + console2.log("UP Token:", upToken); + console2.log("Oracle Manager:", oracleManager); + console2.log("Super Governor Role:", superGovernorRole); + + // Deploy new mock Chainlink oracle for UP/USD at $1 + newChainlinkOracle = new MockChainlinkUpOracle(NEW_UP_PRICE, UP_PRICE_DECIMALS); + console2.log("New Mock Chainlink Oracle deployed at:", address(newChainlinkOracle)); + } + + /// @notice Helper to find an account with a specific role + /// @dev Uses vm.store to grant the role directly via storage manipulation + function _findRoleHolder(bytes32 role) internal returns (address) { + // Create a test address and grant it the role via storage manipulation + // This works because we're in a fork test + address testRoleHolder = makeAddr("roleHolder"); + + // Grant the role using vm.store + _grantRoleViaStorage(role, testRoleHolder); + + return testRoleHolder; + } + + /// @notice Grant a role by directly manipulating storage + /// @dev This works because we're in a fork test + function _grantRoleViaStorage(bytes32 role, address account) internal { + // AccessControl stores roles in: _roles[role].members[account] = true + // RoleData struct is: { mapping(address => bool) members; bytes32 adminRole; } + // Location: keccak256(account . keccak256(role . slot)) + // where slot = 0 for _roles mapping + + // First compute the slot for _roles[role] + bytes32 roleSlot = keccak256(abi.encode(role, uint256(0))); + // Then compute the slot for _roles[role].members[account] + bytes32 memberSlot = keccak256(abi.encode(account, roleSlot)); + + // Set the value to true (1) + vm.store(address(governor), memberSlot, bytes32(uint256(1))); + + // Verify it worked + require(governor.hasRole(role, account), "Failed to grant role via storage"); + } + + /// @notice Test querying current UP price from FixedPriceOracle + function test_CurrentUpPrice() public view { + console2.log("\n=== Current UP Price Test ==="); + + // Get current UP/USD price using the SUPERFORM provider + (uint256 quoteAmount, uint256 deviation, uint256 totalProviders, uint256 availableProviders) = + superOracle.getQuoteFromProvider(1e18, upToken, USD_TOKEN, PROVIDER_SUPERFORM); + + console2.log("Quote for 1 UP (1e18 wei) in USD:"); + console2.log(" Quote amount (USD):", quoteAmount); + console2.log(" Deviation:", deviation); + console2.log(" Total providers:", totalProviders); + console2.log(" Available providers:", availableProviders); + + // The current FixedPriceOracle should return the configured price + assertGt(quoteAmount, 0, "UP price should be > 0"); + } + + /// @notice Test the full oracle update flow + function test_UpdateUpOracleToChainlink() public { + console2.log("\n=== Oracle Update Flow Test ==="); + + // Step 1: Get current price before update + (uint256 oldQuote,,,) = superOracle.getQuoteFromProvider(1e18, upToken, USD_TOKEN, PROVIDER_SUPERFORM); + console2.log("Step 1: Current UP price (for 1 UP):", oldQuote); + + // Step 2: Queue oracle update via SuperGovernor + console2.log("\nStep 2: Queueing oracle update..."); + _queueOracleUpdate(); + + // Note: pendingUpdate struct with dynamic arrays can't be easily retrieved via the auto-generated getter + // We'll verify the update was queued by checking OracleUpdateQueued event or by executing and verifying + console2.log(" Oracle update queued successfully"); + + // Step 3: Warp time past timelock + console2.log("\nStep 3: Warping time past 1 week timelock..."); + vm.warp(block.timestamp + TIMELOCK_PERIOD + 1); + + // Step 4: Execute oracle update + console2.log("\nStep 4: Executing oracle update..."); + _executeOracleUpdate(); + + // Step 5: Verify new oracle is active + console2.log("\nStep 5: Verifying new oracle..."); + address configuredOracle = superOracle.getOracleAddress(upToken, USD_TOKEN, PROVIDER_SUPERFORM); + assertEq(configuredOracle, address(newChainlinkOracle), "Oracle should be updated to new Chainlink oracle"); + console2.log(" Configured oracle for UP/USD:", configuredOracle); + + // Step 6: Query new price + (uint256 newQuote,,,) = superOracle.getQuoteFromProvider(1e18, upToken, USD_TOKEN, PROVIDER_SUPERFORM); + console2.log("\nStep 6: New UP price query result:"); + console2.log(" Old price (for 1 UP):", oldQuote); + console2.log(" New price (for 1 UP):", newQuote); + + // With $1/UP and 18 decimals input, we expect ~1e6 output (USD has 6 decimals typically) + // But since USD_TOKEN is synthetic (address 840), it uses 8 decimals by convention + assertGt(newQuote, 0, "New quote should be > 0"); + } + + /// @notice Test upkeep payment computation with the new oracle + function test_UpkeepComputationWithNewOracle() public { + console2.log("\n=== Upkeep Computation Test ==="); + + // First update the oracle + _queueOracleUpdate(); + vm.warp(block.timestamp + TIMELOCK_PERIOD + 1); + _executeOracleUpdate(); + + // Set staleness for ALL feeds (including Chainlink feeds which become stale after time warp) + _setAllFeedsMaxStaleness(30 days); + + // Get upkeep cost with new oracle + uint256 upkeepCost = governor.getUpkeepCostPerSingleUpdate(ECDSA_PPS_ORACLE); + + console2.log("Upkeep cost per single update (in UP tokens):", upkeepCost); + + // With $1/UP, the upkeep cost should be roughly: + // gas_cost_in_usd / 1 = gas_cost_in_up_tokens + assertGt(upkeepCost, 0, "Upkeep cost should be > 0"); + + // Log the breakdown + console2.log("\n=== Upkeep Cost Breakdown ==="); + console2.log("ECDSA PPS Oracle:", ECDSA_PPS_ORACLE); + console2.log("Gas per entry:", governor.getGasInfo(ECDSA_PPS_ORACLE)); + console2.log("Upkeep cost in UP tokens:", upkeepCost); + } + + /// @notice Test comparing old vs new oracle upkeep costs + function test_CompareUpkeepCosts() public { + console2.log("\n=== Compare Upkeep Costs: Old vs New Oracle ==="); + + // Get upkeep cost with OLD oracle (FixedPriceOracle) + uint256 oldUpkeepCost = governor.getUpkeepCostPerSingleUpdate(ECDSA_PPS_ORACLE); + console2.log("Upkeep cost with OLD oracle (FixedPriceOracle):", oldUpkeepCost); + + // Update to new oracle + _queueOracleUpdate(); + vm.warp(block.timestamp + TIMELOCK_PERIOD + 1); + _executeOracleUpdate(); + + // Set staleness for ALL feeds (including Chainlink feeds which become stale after time warp) + _setAllFeedsMaxStaleness(30 days); + + // Get upkeep cost with NEW oracle (MockChainlinkUpOracle @ $1) + uint256 newUpkeepCost = governor.getUpkeepCostPerSingleUpdate(ECDSA_PPS_ORACLE); + console2.log("Upkeep cost with NEW oracle ($1/UP):", newUpkeepCost); + + // Calculate difference + if (newUpkeepCost > oldUpkeepCost) { + console2.log("Cost INCREASED by:", newUpkeepCost - oldUpkeepCost); + console2.log("Percentage increase:", ((newUpkeepCost - oldUpkeepCost) * 100) / oldUpkeepCost, "%"); + } else if (newUpkeepCost < oldUpkeepCost) { + console2.log("Cost DECREASED by:", oldUpkeepCost - newUpkeepCost); + console2.log("Percentage decrease:", ((oldUpkeepCost - newUpkeepCost) * 100) / oldUpkeepCost, "%"); + } else { + console2.log("Cost unchanged"); + } + } + + /// @notice Test that price changes in the new oracle affect upkeep computation + function test_PriceChangeAffectsUpkeep() public { + console2.log("\n=== Price Change Effect on Upkeep Test ==="); + + // Update to new oracle + _queueOracleUpdate(); + vm.warp(block.timestamp + TIMELOCK_PERIOD + 1); + _executeOracleUpdate(); + + // Set staleness for ALL feeds (including Chainlink feeds which become stale after time warp) + _setAllFeedsMaxStaleness(30 days); + + // Get upkeep at $1/UP + uint256 upkeepAt1Dollar = governor.getUpkeepCostPerSingleUpdate(ECDSA_PPS_ORACLE); + console2.log("Upkeep cost at $1/UP:", upkeepAt1Dollar); + + // Change price to $2/UP + newChainlinkOracle.setPrice(2e18); + uint256 upkeepAt2Dollars = governor.getUpkeepCostPerSingleUpdate(ECDSA_PPS_ORACLE); + console2.log("Upkeep cost at $2/UP:", upkeepAt2Dollars); + + // Change price to $0.50/UP + newChainlinkOracle.setPrice(0.5e18); + uint256 upkeepAtHalfDollar = governor.getUpkeepCostPerSingleUpdate(ECDSA_PPS_ORACLE); + console2.log("Upkeep cost at $0.50/UP:", upkeepAtHalfDollar); + + // Verify inverse relationship: higher UP price = fewer UP tokens needed for same USD cost + assertTrue(upkeepAt2Dollars < upkeepAt1Dollar, "Higher UP price should mean lower UP token cost"); + assertTrue(upkeepAtHalfDollar > upkeepAt1Dollar, "Lower UP price should mean higher UP token cost"); + + // Verify approximate 2x relationship + // At $2/UP, should need ~half the tokens; at $0.50/UP, should need ~2x tokens + console2.log("\nRatio checks:"); + console2.log("upkeepAt1Dollar / upkeepAt2Dollars:", upkeepAt1Dollar * 100 / upkeepAt2Dollars, "% (expect ~200%)"); + console2.log( + "upkeepAtHalfDollar / upkeepAt1Dollar:", upkeepAtHalfDollar * 100 / upkeepAt1Dollar, "% (expect ~200%)" + ); + } + + /// @notice Internal helper to queue oracle update + function _queueOracleUpdate() internal { + address[] memory bases = new address[](1); + address[] memory quotes = new address[](1); + bytes32[] memory providers = new bytes32[](1); + address[] memory feeds = new address[](1); + + bases[0] = upToken; + quotes[0] = USD_TOKEN; + providers[0] = PROVIDER_SUPERFORM; // Keep using SUPERFORM provider + feeds[0] = address(newChainlinkOracle); + + vm.prank(oracleManager); + governor.queueOracleUpdate(bases, quotes, providers, feeds); + } + + /// @notice Internal helper to execute oracle update + function _executeOracleUpdate() internal { + vm.prank(oracleManager); + governor.executeOracleUpdate(); + } + + /// @notice Helper to set staleness for all feeds after time warp + /// @dev This is needed because warping time makes Chainlink oracle data appear stale + function _setAllFeedsMaxStaleness(uint256 staleness) internal { + vm.startPrank(oracleManager); + + // First set default staleness + governor.setOracleMaxStaleness(staleness); + + // Set staleness for all feeds + address[] memory feeds = new address[](4); + feeds[0] = address(newChainlinkOracle); // New UP oracle + feeds[1] = CHAINLINK_GAS_ORACLE; // GAS -> WEI + feeds[2] = CHAINLINK_ETH_USD_ORACLE; // ETH -> USD + feeds[3] = FIXED_PRICE_ORACLE; // Old FixedPriceOracle (might still be checked) + + uint256[] memory stalenesses = new uint256[](4); + stalenesses[0] = staleness; + stalenesses[1] = staleness; + stalenesses[2] = staleness; + stalenesses[3] = staleness; + + governor.setOracleFeedMaxStalenessBatch(feeds, stalenesses); + + vm.stopPrank(); + } +} diff --git a/test/integration/pendle/DETHMarketMigration.t.sol b/test/integration/pendle/DETHMarketMigration.t.sol new file mode 100644 index 000000000..4401b759d --- /dev/null +++ b/test/integration/pendle/DETHMarketMigration.t.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +// external +import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import { UserOpData } from "modulekit/ModuleKit.sol"; +import { IPendleMarket } from "v2-core/src/vendor/pendle/IPendleMarket.sol"; +import { IPYieldToken } from "v2-core/src/vendor/pendle/IPYieldToken.sol"; +import { IStandardizedYield } from "v2-core/src/vendor/pendle/IStandardizedYield.sol"; +import { + IPendleRouterV4, + LimitOrderData, + FillOrderParams, + TokenInput, + TokenOutput, + ApproxParams, + SwapType, + SwapData +} from "v2-core/src/vendor/pendle/IPendleRouterV4.sol"; +import { console2 } from "forge-std/console2.sol"; + +// Superform +import { PendleUnifiedHook } from "v2-core/src/hooks/swappers/pendle/PendleUnifiedHook.sol"; +import { ISuperExecutor } from "v2-core/src/interfaces/ISuperExecutor.sol"; +import { MinimalBaseIntegrationTest } from "v2-core/test/integration/MinimalBaseIntegrationTest.t.sol"; + +/// @title DETHMarketMigrationTest +/// @notice Integration test for DETH Pendle market migration without swap +/// @dev Tests the scenario where: +/// 1. SuperVault has funds in DETH 29JAN2026 market (expired) +/// 2. Redeem PT+YT after expiry to get DETH directly in strategy +/// 3. Invest DETH into new 26APR2026 market WITHOUT swapping DETH -> WETH -> DETH +/// This avoids unnecessary swap fees and slippage by using DETH directly +contract DETHMarketMigrationTest is MinimalBaseIntegrationTest { + // DETH token address (underlying for Pendle markets) + address public constant DETH = 0x871aB8E36CaE9AF35c6A3488B049965233DeB7ed; + address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + // First market (29JAN2026) - will be expired + address public constant DETH_MARKET_OLD = 0x937c7868824ae53dB3b7C634de209FB7a74E362c; + address public constant PT_DETH_OLD = 0x8209b01357946A64a0793e9773F6F3Fe5A5F2526; + + // Second market (26APR2026) - will invest into this + address public constant DETH_MARKET_NEW = 0xaAAF90CBc7c8C38a08ca810c5e5f3C1D99a2b600; + address public constant PT_DETH_NEW = 0xE1D9b789da5B5375eACF66f036022B019A2Af307; + + // SuperVault WETH addresses (mainnet) + address public constant SUPERVAULT_WETH = 0xa036823b9A24F63c32553367bf181Ee04229c3AC; + address public constant SUPERVAULT_WETH_STRATEGY = 0x1199a6B2587Ed96446E76Dee3FB660bb8fCfd0b2; + + PendleUnifiedHook public pendleUnifiedHook; + + // Market tokens + address public syOld; + address public ptOld; + address public ytOld; + + address public syNew; + address public ptNew; + address public ytNew; + + function setUp() public override { + // Fork mainnet at current block + blockNumber = 0; + super.setUp(); + + // Deploy PendleUnifiedHook with real Pendle Router + pendleUnifiedHook = new PendleUnifiedHook(CHAIN_1_PENDLE_ROUTER); + + // Get tokens from OLD DETH market (29JAN2026) + (syOld, ptOld, ytOld) = IPendleMarket(DETH_MARKET_OLD).readTokens(); + + // Get tokens from NEW DETH market (26APR2026) + (syNew, ptNew, ytNew) = IPendleMarket(DETH_MARKET_NEW).readTokens(); + + // Log addresses for debugging + console2.log("OLD Market SY:", syOld); + console2.log("OLD Market PT:", ptOld); + console2.log("OLD Market YT:", ytOld); + console2.log("NEW Market SY:", syNew); + console2.log("NEW Market PT:", ptNew); + console2.log("NEW Market YT:", ytNew); + } + + /// @notice Test step 1 of migration: Redeem from expired market to get DETH directly + /// @dev This demonstrates that DETH (not WETH) is received from post-maturity redemption + function test_RedeemFromExpiredMarket_GetsDETH() public { + // Setup: Deal PT and YT from OLD market to account + uint256 redeemAmount = 10e18; // 10 PT+YT + deal(ptOld, accountEth, redeemAmount); + deal(ytOld, accountEth, redeemAmount); + + assertEq(IERC20(ptOld).balanceOf(accountEth), redeemAmount, "PT not dealt"); + assertEq(IERC20(ytOld).balanceOf(accountEth), redeemAmount, "YT not dealt"); + + // Record initial balances + uint256 dethBalanceBefore = IERC20(DETH).balanceOf(accountEth); + uint256 wethBalanceBefore = IERC20(WETH).balanceOf(accountEth); + console2.log("Initial DETH balance:", dethBalanceBefore); + console2.log("Initial WETH balance:", wethBalanceBefore); + + // Warp to AFTER the OLD market expiry + uint256 expiryOld = IPYieldToken(ytOld).expiry(); + vm.warp(expiryOld + 1 days); + console2.log("Warped to timestamp (after expiry):", block.timestamp); + + // Redeem from OLD market to get DETH (not WETH!) + bytes memory redeemHookData = _createPendleUnifiedRedeemHookData( + DETH_MARKET_OLD, // yieldSource is always the market + redeemAmount, + ytOld, + DETH, // tokenOut - we want DETH directly + DETH, // tokenRedeemSy - DETH is the valid SY output + 1, // minTokenOut + false // usePrevHookAmount + ); + + { + address[] memory hooks = new address[](1); + hooks[0] = address(pendleUnifiedHook); + + bytes[] memory data = new bytes[](1); + data[0] = redeemHookData; + + ISuperExecutor.ExecutorEntry memory entry = + ISuperExecutor.ExecutorEntry({ hooksAddresses: hooks, hooksData: data }); + + UserOpData memory userOpData = _getExecOps(instanceOnEth, superExecutorOnEth, abi.encode(entry)); + executeOp(userOpData); + } + + // Verify we received DETH (not WETH) + uint256 dethBalanceAfter = IERC20(DETH).balanceOf(accountEth); + uint256 wethBalanceAfter = IERC20(WETH).balanceOf(accountEth); + + console2.log("Final DETH balance:", dethBalanceAfter); + console2.log("Final WETH balance:", wethBalanceAfter); + console2.log("DETH received from redemption:", dethBalanceAfter - dethBalanceBefore); + + // Key assertions: + // 1. We received DETH (the underlying token) + assertGt(dethBalanceAfter, dethBalanceBefore, "Should receive DETH from redemption"); + // 2. We did NOT receive WETH (no swap happened) + assertEq(wethBalanceAfter, wethBalanceBefore, "Should NOT receive WETH - no swap needed"); + } + + /// @notice Test that both markets share the same SY and support DETH + /// @dev This proves the migration path is valid: OLD market DETH -> NEW market DETH + function test_MigrationPath_BothMarkets_SupportDETH() public view { + // Both markets should share the same SY (they're both DETH markets) + assertEq(syOld, syNew, "Both markets should use the same SY for DETH"); + + // DETH is a valid output from OLD market (for redemption) + bool dethValidOut = IStandardizedYield(syOld).isValidTokenOut(DETH); + assertTrue(dethValidOut, "DETH should be valid output from OLD market SY"); + + // DETH is a valid input for NEW market (for deposit) + bool dethValidIn = IStandardizedYield(syNew).isValidTokenIn(DETH); + assertTrue(dethValidIn, "DETH should be valid input for NEW market SY"); + + // WETH is NOT a valid output from the DETH SY + bool wethValidOut = IStandardizedYield(syOld).isValidTokenOut(WETH); + assertFalse(wethValidOut, "WETH should NOT be valid output from DETH SY"); + + console2.log("Shared SY address:", syOld); + console2.log("DETH valid out:", dethValidOut); + console2.log("DETH valid in:", dethValidIn); + console2.log("WETH valid out:", wethValidOut); + } + + /// @notice Test that DETH can be used directly as input for the new Pendle market + /// @dev Verifies that DETH is a valid tokenIn for the new market's SY + function test_DETH_Is_Valid_Input_For_NewMarket() public view { + bool dethValid = IStandardizedYield(syNew).isValidTokenIn(DETH); + assertTrue(dethValid, "DETH should be valid input for new market SY"); + + address[] memory tokensIn = IStandardizedYield(syNew).getTokensIn(); + console2.log("Number of valid input tokens:", tokensIn.length); + for (uint256 i = 0; i < tokensIn.length; i++) { + console2.log("tokenIn:", i, tokensIn[i]); + } + } + + /// @notice Test that DETH can be directly obtained from old market redemption + /// @dev Verifies that DETH is a valid tokenOut for the old market's SY + function test_DETH_Is_Valid_Output_From_OldMarket() public view { + bool dethValid = IStandardizedYield(syOld).isValidTokenOut(DETH); + assertTrue(dethValid, "DETH should be valid output from old market SY"); + + address[] memory tokensOut = IStandardizedYield(syOld).getTokensOut(); + console2.log("Number of valid output tokens:", tokensOut.length); + for (uint256 i = 0; i < tokensOut.length; i++) { + console2.log("tokenOut:", i, tokensOut[i]); + } + } + + /// @notice Test that both markets use the same SY (they share the DETH underlying) + /// @dev If both markets use the same SY, the migration is even simpler + function test_Markets_Share_Same_SY() public view { + // Note: Different markets may have different SY implementations even for the same underlying + // But they should both support DETH as input/output + console2.log("OLD market SY:", syOld); + console2.log("NEW market SY:", syNew); + + // Both should support DETH regardless of whether they share the same SY + bool oldSupportsDeth = IStandardizedYield(syOld).isValidTokenOut(DETH); + bool newSupportsDeth = IStandardizedYield(syNew).isValidTokenIn(DETH); + + assertTrue(oldSupportsDeth, "Old market SY should support DETH output"); + assertTrue(newSupportsDeth, "New market SY should support DETH input"); + } + + /// @notice Helper to create ApproveERC20Hook data + /// @dev Data layout: [address token][address spender][uint256 amount][bool usePrevHookAmount] + function _createApproveHookData( + address token, + address spender, + uint256 amount + ) + internal + pure + returns (bytes memory) + { + // ApproveERC20Hook data layout: [address token][address spender][uint256 amount][bool usePrevHookAmount] + return abi.encodePacked(token, spender, amount, false); + } + + /// @notice Helper to create PendleUnifiedHook data for redeemPyToToken (direct redemption) + function _createPendleUnifiedRedeemHookData( + address yieldSource, + uint256 amount, + address ytAddress, + address tokenOut, + address tokenRedeemSy, + uint256 minTokenOut, + bool usePrevHookAmount + ) + internal + view + returns (bytes memory) + { + // Create TokenOutput struct with no swap routing (direct redemption) + TokenOutput memory output = TokenOutput({ + tokenOut: tokenOut, + minTokenOut: minTokenOut, + tokenRedeemSy: tokenRedeemSy, + pendleSwap: address(0), + swapData: SwapData({ swapType: SwapType.NONE, extRouter: address(0), extCalldata: bytes(""), needScale: false }) + }); + + // Encode txData for redeemPyToToken + bytes memory txData = + abi.encodeWithSelector(IPendleRouterV4.redeemPyToToken.selector, accountEth, ytAddress, amount, output); + + // Pack hook data: [bytes32 placeholder][address yieldSource][bool usePrevHookAmount][uint256 value][bytes txData] + return abi.encodePacked( + bytes32(0), // placeholder + yieldSource, // yieldSource (always market address) + usePrevHookAmount, // usePrevHookAmount + uint256(0), // value (not used for redemptions) + txData + ); + } + + /// @notice Helper to create PendleUnifiedHook data for swapExactTokenForPt (buy PT with token) + /// @dev Uses swapExactTokenForPt which is supported by PendleUnifiedHook + function _createPendleUnifiedDepositHookData( + address yieldSource, + uint256 amount, + address, /* ytAddress - unused for swapExactTokenForPt */ + address tokenIn, + address tokenMintSy, + uint256 minPtOut, + bool usePrevHookAmount + ) + internal + view + returns (bytes memory) + { + // Create TokenInput struct with no swap routing (direct minting via market) + TokenInput memory input = TokenInput({ + tokenIn: tokenIn, + netTokenIn: amount, + tokenMintSy: tokenMintSy, + pendleSwap: address(0), + swapData: SwapData({ swapType: SwapType.NONE, extRouter: address(0), extCalldata: bytes(""), needScale: false }) + }); + + // Create ApproxParams for PT out estimation + ApproxParams memory guessPtOut = ApproxParams({ + guessMin: 0, + guessMax: type(uint256).max, + guessOffchain: 0, + maxIteration: 256, + eps: 1e15 // 0.1% + }); + + // Create empty LimitOrderData + LimitOrderData memory limit = LimitOrderData({ + limitRouter: address(0), + epsSkipMarket: 0, + normalFills: new FillOrderParams[](0), + flashFills: new FillOrderParams[](0), + optData: bytes("") + }); + + // Encode txData for swapExactTokenForPt + bytes memory txData = abi.encodeWithSelector( + IPendleRouterV4.swapExactTokenForPt.selector, + accountEth, // receiver + yieldSource, // market + minPtOut, // minPtOut + guessPtOut, // ApproxParams + input, // TokenInput + limit // LimitOrderData + ); + + // Pack hook data: [bytes32 placeholder][address yieldSource][bool usePrevHookAmount][uint256 value][bytes txData] + return abi.encodePacked( + bytes32(0), // placeholder + yieldSource, // yieldSource (always market address) + usePrevHookAmount, // usePrevHookAmount + uint256(0), // value + txData + ); + } +} diff --git a/test/unit/EdgeCaseCoverage.t.sol b/test/unit/EdgeCaseCoverage.t.sol new file mode 100644 index 000000000..66d146e39 --- /dev/null +++ b/test/unit/EdgeCaseCoverage.t.sol @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.30; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { SuperGovernor } from "../../src/SuperGovernor.sol"; +import { ISuperGovernor, FeeType } from "../../src/interfaces/ISuperGovernor.sol"; +import { SuperVaultAggregator } from "../../src/SuperVault/SuperVaultAggregator.sol"; +import { ISuperVaultAggregator } from "../../src/interfaces/SuperVault/ISuperVaultAggregator.sol"; +import { SuperVault } from "../../src/SuperVault/SuperVault.sol"; +import { SuperVaultStrategy } from "../../src/SuperVault/SuperVaultStrategy.sol"; +import { SuperVaultEscrow } from "../../src/SuperVault/SuperVaultEscrow.sol"; +import { ISuperVaultStrategy } from "../../src/interfaces/SuperVault/ISuperVaultStrategy.sol"; +import { ISuperVaultEscrow } from "../../src/interfaces/SuperVault/ISuperVaultEscrow.sol"; +import { SuperVaultAccountingLib } from "../../src/libraries/SuperVaultAccountingLib.sol"; +import { FixedPriceOracle } from "../../src/oracles/FixedPriceOracle.sol"; +import { ISuperVault } from "../../src/interfaces/SuperVault/ISuperVault.sol"; +import { PeripheryHelpers } from "../utils/PeripheryHelpers.sol"; +import { MockERC20 } from "../mocks/MockERC20.sol"; +import { MockUp } from "../mocks/MockUp.sol"; +import { MockSuperOracle } from "../mocks/MockSuperOracle.sol"; + +/// @title EdgeCaseCoverageTest +/// @notice Edge case tests for remaining coverage gaps +contract EdgeCaseCoverageTest is PeripheryHelpers { + SuperGovernor internal superGovernor; + SuperVaultAggregator internal superVaultAggregator; + SuperVault internal vault; + SuperVaultStrategy internal strategy; + MockERC20 internal asset; + + address internal sGovernor; + address internal governor; + address internal treasury; + address internal user; + address internal manager; + address internal superBank; + address internal superOracle; + address internal upToken; + + function setUp() public { + sGovernor = _deployAccount(0x1, "SuperGovernor"); + governor = _deployAccount(0x2, "Governor"); + treasury = _deployAccount(0x3, "Treasury"); + user = _deployAccount(0x4, "User"); + manager = _deployAccount(0x5, "Manager"); + superOracle = address(new MockSuperOracle(1e18)); + + asset = new MockERC20("Asset", "ASSET", 18); + + superGovernor = new SuperGovernor(sGovernor, governor, governor, governor, governor, governor, treasury, false); + + address vaultImpl = address(new SuperVault(address(superGovernor))); + address strategyImpl = address(new SuperVaultStrategy(address(superGovernor))); + address escrowImpl = address(new SuperVaultEscrow()); + + superVaultAggregator = new SuperVaultAggregator(address(superGovernor), vaultImpl, strategyImpl, escrowImpl); + + upToken = address(new MockUp(address(this))); + superBank = makeAddr("superBank"); + vm.startPrank(sGovernor); + superGovernor.setAddress(superGovernor.UP(), upToken); + superGovernor.setAddress(superGovernor.UPKEEP_TOKEN(), upToken); + superGovernor.setAddress(superGovernor.SUPER_BANK(), superBank); + superGovernor.setAddress(superGovernor.SUPER_ORACLE(), superOracle); + superGovernor.setAddress(superGovernor.SUPER_VAULT_AGGREGATOR(), address(superVaultAggregator)); + vm.stopPrank(); + + vm.prank(manager); + (address vaultAddress, address strategyAddress,) = superVaultAggregator.createVault( + ISuperVaultAggregator.VaultCreationParams({ + asset: address(asset), + name: "Test Vault", + symbol: "TV", + mainManager: manager, + secondaryManagers: new address[](0), + minUpdateInterval: 5, + maxStaleness: 300, + feeConfig: ISuperVaultStrategy.FeeConfig({ + performanceFeeBps: 1000, + managementFeeBps: 0, + recipient: manager + }) + }) + ); + + vault = SuperVault(vaultAddress); + strategy = SuperVaultStrategy(payable(strategyAddress)); + } + + // ========================================================================= + // SuperVaultAggregator: onlyPPSOracle modifier (line 101-104) + // ========================================================================= + function test_ForwardPPS_RevertsOnNonPPSOracle() public { + address[] memory strategies = new address[](1); + strategies[0] = address(strategy); + uint256[] memory ppss = new uint256[](1); + ppss[0] = 1e18; + uint256[] memory timestamps = new uint256[](1); + timestamps[0] = block.timestamp; + + vm.prank(user); // user is not the PPS oracle + vm.expectRevert(ISuperVaultAggregator.UNAUTHORIZED_PPS_ORACLE.selector); + superVaultAggregator.forwardPPS( + ISuperVaultAggregator.ForwardPPSArgs({ + strategies: strategies, + ppss: ppss, + timestamps: timestamps, + updateAuthority: user + }) + ); + } + + // ========================================================================= + // SuperVaultAggregator: updatePPSAfterSkim - PPS_MUST_DECREASE (line 321) + // ========================================================================= + function test_UpdatePPSAfterSkim_RevertsOnPPSNotDecreasing() public { + uint256 currentPPS = superVaultAggregator.getPPS(address(strategy)); + assertGt(currentPPS, 0); + + // Try to set newPPS >= currentPPS (should revert) + vm.prank(address(strategy)); + vm.expectRevert(ISuperVaultAggregator.PPS_MUST_DECREASE_AFTER_SKIM.selector); + superVaultAggregator.updatePPSAfterSkim(currentPPS, 100e18); + } + + function test_UpdatePPSAfterSkim_RevertsOnPPSIncrease() public { + uint256 currentPPS = superVaultAggregator.getPPS(address(strategy)); + + vm.prank(address(strategy)); + vm.expectRevert(ISuperVaultAggregator.PPS_MUST_DECREASE_AFTER_SKIM.selector); + superVaultAggregator.updatePPSAfterSkim(currentPPS + 1, 100e18); + } + + // ========================================================================= + // SuperVaultAggregator: updatePPSAfterSkim - PPS_DEDUCTION_TOO_LARGE (line 332) + // ========================================================================= + function test_UpdatePPSAfterSkim_RevertsOnDeductionTooLarge() public { + uint256 currentPPS = superVaultAggregator.getPPS(address(strategy)); + + // Set newPPS very low (e.g., 1 wei) - this should trigger PPS_DEDUCTION_TOO_LARGE + // MAX_PERFORMANCE_FEE is 5100 (51%), so minAllowedPPS = currentPPS * 4900 / 10000 = ~49% of current + // Setting to 1 wei is way below that + vm.prank(address(strategy)); + vm.expectRevert(ISuperVaultAggregator.PPS_DEDUCTION_TOO_LARGE.selector); + superVaultAggregator.updatePPSAfterSkim(1, 100e18); + } + + // ========================================================================= + // SuperGovernor: getActivePPSOracle revert NO_ACTIVE_PPS_ORACLE (line 739) + // ========================================================================= + function test_GetActivePPSOracle_RevertsWhenNotSet() public { + // Deploy a fresh SuperGovernor without PPS oracle set + SuperGovernor freshGovernor = + new SuperGovernor(sGovernor, governor, governor, governor, governor, governor, treasury, false); + + vm.expectRevert(ISuperGovernor.NO_ACTIVE_PPS_ORACLE.selector); + freshGovernor.getActivePPSOracle(); + } + + // ========================================================================= + // SuperGovernor: getAddress revert CONTRACT_NOT_FOUND (line 669) + // ========================================================================= + function test_GetAddress_RevertsOnNotFound() public { + vm.expectRevert(ISuperGovernor.CONTRACT_NOT_FOUND.selector); + superGovernor.getAddress(keccak256("NON_EXISTENT_KEY")); + } + + // ========================================================================= + // SuperVaultAccountingLib: calculateAverageWithdrawPrice edge case + // When both currentMaxWithdraw and requestedShares lead to newTotalShares == 0 + // ========================================================================= + function test_CalculateAverageWithdrawPrice_ZeroShares() public pure { + // When currentMaxWithdraw == 0 and requestedShares == 0 + // newTotalShares == 0, so return 0 + uint256 result = SuperVaultAccountingLib.calculateAverageWithdrawPrice( + 0, // currentMaxWithdraw + 0, // currentAverageWithdrawPrice + 0, // requestedShares + 0, // fulfilledAssets + 1e18 // precision + ); + assertEq(result, 0); + } + + function test_CalculateAverageWithdrawPrice_WithExistingPosition() public pure { + // currentMaxWithdraw = 1000, currentAverageWithdrawPrice = 1e18 + // requestedShares = 500, fulfilledAssets = 500 + uint256 result = SuperVaultAccountingLib.calculateAverageWithdrawPrice( + 1000e18, // currentMaxWithdraw + 1e18, // currentAverageWithdrawPrice + 500e18, // requestedShares + 500e18, // fulfilledAssets + 1e18 // precision + ); + assertGt(result, 0); + } + + function test_CalculateAverageWithdrawPrice_ZeroCurrentMaxWithdraw() public pure { + // When currentMaxWithdraw == 0 but requestedShares > 0 + // existingShares = 0, existingAssets = 0 + // newTotalShares = 0 + 100e18 = 100e18 + // newTotalAssets = 0 + 200e18 = 200e18 + // result = 200e18 * 1e18 / 100e18 = 2e18 + uint256 result = SuperVaultAccountingLib.calculateAverageWithdrawPrice( + 0, // currentMaxWithdraw + 0, // currentAverageWithdrawPrice + 100e18, // requestedShares + 200e18, // fulfilledAssets + 1e18 // precision + ); + assertEq(result, 2e18); + } + + // ========================================================================= + // SuperVaultAccountingLib: computeMinNetOut + // ========================================================================= + function test_ComputeMinNetOut_BasicCalculation() public pure { + // requestedShares = 100e18, averageRequestPPS = 1e18, slippageBps = 50 (0.5%) + uint256 result = SuperVaultAccountingLib.computeMinNetOut( + 100e18, // requestedShares + 1e18, // averageRequestPPS + 50, // slippageBps + 1e18 // precision + ); + // expected = 100e18 * (10000 - 50) / 10000 = 100e18 * 9950 / 10000 = 99.5e18 + assertEq(result, 99.5e18); + } + + // ========================================================================= + // FixedPriceOracle: phaseAggregators branch (line 164-166) + // ========================================================================= + function test_FixedPriceOracle_PhaseAggregators_Phase1() public { + FixedPriceOracle oracle = new FixedPriceOracle(1e8, 8, address(this)); + assertEq(oracle.phaseAggregators(1), address(oracle)); + } + + function test_FixedPriceOracle_PhaseAggregators_NonPhase1() public { + FixedPriceOracle oracle = new FixedPriceOracle(1e8, 8, address(this)); + assertEq(oracle.phaseAggregators(0), address(0)); + assertEq(oracle.phaseAggregators(2), address(0)); + } + + function test_FixedPriceOracle_Constructor_RevertsOnZeroPrice() public { + vm.expectRevert(FixedPriceOracle.INVALID_PRICE.selector); + new FixedPriceOracle(0, 8, address(this)); + } + + function test_FixedPriceOracle_Constructor_RevertsOnNegativePrice() public { + vm.expectRevert(FixedPriceOracle.INVALID_PRICE.selector); + new FixedPriceOracle(-1, 8, address(this)); + } + + function test_FixedPriceOracle_LatestRoundData() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = + oracle.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 42e8); + assertEq(startedAt, block.timestamp); + assertEq(updatedAt, block.timestamp); + assertEq(answeredInRound, 1); + } + + function test_FixedPriceOracle_GetRoundData() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + (uint80 roundId, int256 answer,,, uint80 answeredInRound) = oracle.getRoundData(5); + assertEq(roundId, 5); + assertEq(answer, 42e8); + assertEq(answeredInRound, 5); + } + + function test_FixedPriceOracle_LatestAnswer() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + assertEq(oracle.latestAnswer(), uint256(42e8)); + } + + function test_FixedPriceOracle_GetTimestamp() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + assertEq(oracle.getTimestamp(99), block.timestamp); + } + + function test_FixedPriceOracle_PhaseId() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + assertEq(oracle.phaseId(), 1); + } + + function test_FixedPriceOracle_Version() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + assertEq(oracle.version(), 1); + } + + function test_FixedPriceOracle_Description() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + assertEq(oracle.description(), "Fixed Price Oracle"); + } + + function test_FixedPriceOracle_Decimals() public { + FixedPriceOracle oracle = new FixedPriceOracle(42e8, 8, address(this)); + assertEq(oracle.decimals(), 8); + } + + function test_FixedPriceOracle_SetPrice() public { + FixedPriceOracle oracle = new FixedPriceOracle(1e8, 8, address(this)); + oracle.setPrice(2e8); + assertEq(oracle.latestAnswer(), 2e8); + } + + function test_FixedPriceOracle_SetPrice_RevertsOnZero() public { + FixedPriceOracle oracle = new FixedPriceOracle(1e8, 8, address(this)); + vm.expectRevert(FixedPriceOracle.INVALID_PRICE.selector); + oracle.setPrice(0); + } + + function test_FixedPriceOracle_SetDecimals() public { + FixedPriceOracle oracle = new FixedPriceOracle(1e8, 8, address(this)); + oracle.setDecimals(18); + assertEq(oracle.decimals(), 18); + } + + // ========================================================================= + // SuperVaultEscrow: onlyVault modifier revert (line 30) + // ========================================================================= + function test_SuperVaultEscrow_OnlyVault_RevertsOnUnauthorized() public { + address escrow = vault.escrow(); + + vm.prank(user); + vm.expectRevert(ISuperVaultEscrow.UNAUTHORIZED.selector); + ISuperVaultEscrow(escrow).escrowShares(user, 100e18); + + vm.prank(user); + vm.expectRevert(ISuperVaultEscrow.UNAUTHORIZED.selector); + ISuperVaultEscrow(escrow).returnShares(user, 100e18); + + vm.prank(user); + vm.expectRevert(ISuperVaultEscrow.UNAUTHORIZED.selector); + ISuperVaultEscrow(escrow).returnAssets(user, 100e18); + } + + // ========================================================================= + // SuperVaultStrategy: initialize revert - fee>0 + zero recipient (line 129) + // ========================================================================= + function test_CreateVault_RevertsOnFeeWithZeroRecipient() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.ZERO_ADDRESS.selector); + superVaultAggregator.createVault( + ISuperVaultAggregator.VaultCreationParams({ + asset: address(asset), + name: "Bad Vault", + symbol: "BV", + mainManager: manager, + secondaryManagers: new address[](0), + minUpdateInterval: 5, + maxStaleness: 300, + feeConfig: ISuperVaultStrategy.FeeConfig({ + performanceFeeBps: 1000, + managementFeeBps: 0, + recipient: address(0) // zero recipient with fee > 0 should revert + }) + }) + ); + } + + // ========================================================================= + // SuperVaultStrategy: cancelRedeemRequest when already pending (line 1010) + // ========================================================================= + function test_RequestRedeem_RevertsWhenCancelPending() public { + // Setup: deposit and request redeem with only some shares + uint256 depositAmount = 1000e18; + asset.mint(user, depositAmount); + vm.startPrank(user); + asset.approve(address(vault), depositAmount); + vault.deposit(depositAmount, user); + uint256 shares = vault.balanceOf(user); + + // Request half the shares + vault.requestRedeem(shares / 2, user, user); + + // Cancel the redeem request + vault.cancelRedeemRequest(0, user); + + // Can't re-request while cancel is pending (strategy checks pendingCancelRedeemRequest) + vm.expectRevert(ISuperVault.CANCELLATION_REDEEM_REQUEST_PENDING.selector); + vault.requestRedeem(shares / 4, user, user); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVaultStrategy: handleOperations4626Deposit with veto (line 166) + // ========================================================================= + function test_DepositRevertsWhenGlobalHooksRootVetoed() public { + // Veto the global hooks root (governor has GUARDIAN_ROLE in our setup) + vm.prank(governor); + superGovernor.setGlobalHooksRootVetoStatus(true); + + // Deposit should now revert + uint256 depositAmount = 100e18; + asset.mint(user, depositAmount); + vm.startPrank(user); + asset.approve(address(vault), depositAmount); + vm.expectRevert(ISuperVaultStrategy.OPERATIONS_BLOCKED_BY_VETO.selector); + vault.deposit(depositAmount, user); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVaultStrategy: mint reverts when veto is active (line 214) + // ========================================================================= + function test_MintRevertsWhenGlobalHooksRootVetoed() public { + vm.prank(governor); + superGovernor.setGlobalHooksRootVetoStatus(true); + + uint256 mintAmount = 100e18; + asset.mint(user, mintAmount * 2); + vm.startPrank(user); + asset.approve(address(vault), mintAmount * 2); + vm.expectRevert(ISuperVaultStrategy.OPERATIONS_BLOCKED_BY_VETO.selector); + vault.mint(mintAmount, user); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVaultStrategy: _isPrimaryManager revert with secondary manager + // ========================================================================= + // ========================================================================= + // SuperVaultStrategy: double cancel revert (line 1010) + // ========================================================================= + function test_CancelRedeemRequest_RevertsOnDoubleCancelAtStrategy() public { + // Deposit + uint256 depositAmount = 1000e18; + asset.mint(user, depositAmount); + vm.startPrank(user); + asset.approve(address(vault), depositAmount); + vault.deposit(depositAmount, user); + uint256 shares = vault.balanceOf(user); + + // Request redeem with half shares + vault.requestRedeem(shares / 2, user, user); + + // First cancel succeeds (sets pendingCancelRedeemRequest = true) + vault.cancelRedeemRequest(0, user); + + // Second cancel should revert from strategy: pendingCancelRedeemRequest is already true + vm.expectRevert(ISuperVaultStrategy.CANCELLATION_REDEEM_REQUEST_PENDING.selector); + vault.cancelRedeemRequest(0, user); + vm.stopPrank(); + } + + function test_ManageYieldSource_RevertsForSecondaryManager() public { + address secondaryManager = makeAddr("secondary"); + + // Add secondary manager to strategy + vm.prank(manager); + superVaultAggregator.addSecondaryManager(address(strategy), secondaryManager); + + // Secondary manager should NOT be able to call primary-manager-only functions + vm.prank(secondaryManager); + vm.expectRevert(ISuperVaultStrategy.MANAGER_NOT_AUTHORIZED.selector); + strategy.manageYieldSource(makeAddr("source"), makeAddr("oracle"), ISuperVaultStrategy.YieldSourceAction.Add); + } +} diff --git a/test/unit/SuperVaultBatchOperator.t.sol b/test/unit/SuperVaultBatchOperator.t.sol new file mode 100644 index 000000000..8e8429a0f --- /dev/null +++ b/test/unit/SuperVaultBatchOperator.t.sol @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.30; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; + +import { SuperGovernor } from "../../src/SuperGovernor.sol"; +import { ISuperGovernor } from "../../src/interfaces/ISuperGovernor.sol"; +import { SuperVaultAggregator } from "../../src/SuperVault/SuperVaultAggregator.sol"; +import { ISuperVaultAggregator } from "../../src/interfaces/SuperVault/ISuperVaultAggregator.sol"; +import { SuperVault } from "../../src/SuperVault/SuperVault.sol"; +import { SuperVaultStrategy } from "../../src/SuperVault/SuperVaultStrategy.sol"; +import { SuperVaultEscrow } from "../../src/SuperVault/SuperVaultEscrow.sol"; +import { ISuperVaultStrategy } from "../../src/interfaces/SuperVault/ISuperVaultStrategy.sol"; +import { SuperVaultBatchOperator } from "../../src/SuperVault/SuperVaultBatchOperator.sol"; +import { ISuperVaultBatchOperator } from "../../src/interfaces/SuperVault/ISuperVaultBatchOperator.sol"; +import { PeripheryHelpers } from "../utils/PeripheryHelpers.sol"; +import { MockERC20 } from "../mocks/MockERC20.sol"; +import { MockUp } from "../mocks/MockUp.sol"; +import { MockSuperOracle } from "../mocks/MockSuperOracle.sol"; + +import "forge-std/console2.sol"; + +/// @title SuperVaultBatchOperatorTest +/// @notice Unit tests for SuperVaultBatchOperator contract +contract SuperVaultBatchOperatorTest is PeripheryHelpers { + SuperGovernor internal superGovernor; + SuperVaultAggregator internal superVaultAggregator; + SuperVault internal vault; + SuperVaultStrategy internal strategy; + SuperVaultBatchOperator internal batchOperator; + MockERC20 internal asset; + + // Roles & Addresses + address internal sGovernor; + address internal governor; + address internal treasury; + address internal user; + address internal manager; + address internal admin; + address internal operator; + address internal superBank; + address internal superOracle; + address internal upToken; + + function setUp() public { + sGovernor = _deployAccount(0x1, "SuperGovernor"); + governor = _deployAccount(0x2, "Governor"); + treasury = _deployAccount(0x3, "Treasury"); + user = _deployAccount(0x4, "User"); + manager = _deployAccount(0x5, "Manager"); + admin = _deployAccount(0x6, "Admin"); + operator = _deployAccount(0x7, "Operator"); + superOracle = address(new MockSuperOracle(1e18)); + + asset = new MockERC20("Asset", "ASSET", 18); + + superGovernor = new SuperGovernor(sGovernor, governor, governor, governor, governor, governor, treasury, false); + + address vaultImpl = address(new SuperVault(address(superGovernor))); + address strategyImpl = address(new SuperVaultStrategy(address(superGovernor))); + address escrowImpl = address(new SuperVaultEscrow()); + + superVaultAggregator = new SuperVaultAggregator(address(superGovernor), vaultImpl, strategyImpl, escrowImpl); + + upToken = address(new MockUp(address(this))); + superBank = makeAddr("superBank"); + vm.startPrank(sGovernor); + superGovernor.setAddress(superGovernor.UP(), upToken); + superGovernor.setAddress(superGovernor.UPKEEP_TOKEN(), upToken); + superGovernor.setAddress(superGovernor.SUPER_BANK(), superBank); + superGovernor.setAddress(superGovernor.SUPER_ORACLE(), superOracle); + superGovernor.setAddress(superGovernor.SUPER_VAULT_AGGREGATOR(), address(superVaultAggregator)); + vm.stopPrank(); + + vm.prank(manager); + (address vaultAddress, address strategyAddress,) = superVaultAggregator.createVault( + ISuperVaultAggregator.VaultCreationParams({ + asset: address(asset), + name: "Test Vault", + symbol: "TV", + mainManager: manager, + secondaryManagers: new address[](0), + minUpdateInterval: 5, + maxStaleness: 300, + feeConfig: ISuperVaultStrategy.FeeConfig({ + performanceFeeBps: 1000, managementFeeBps: 0, recipient: manager + }) + }) + ); + + vault = SuperVault(vaultAddress); + strategy = SuperVaultStrategy(payable(strategyAddress)); + + // Deploy batch operator + batchOperator = new SuperVaultBatchOperator(admin, operator); + } + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR TESTS + //////////////////////////////////////////////////////////////*/ + + function test_Constructor_SetsRolesCorrectly() public view { + assertTrue(batchOperator.hasRole(batchOperator.DEFAULT_ADMIN_ROLE(), admin)); + assertTrue(batchOperator.hasRole(batchOperator.OPERATOR_ROLE(), operator)); + } + + function test_Constructor_RevertsOnZeroAdminAddress() public { + vm.expectRevert(ISuperVaultBatchOperator.ZERO_ADMIN_ADDRESS.selector); + new SuperVaultBatchOperator(address(0), operator); + } + + function test_Constructor_RevertsOnZeroOperatorAddress() public { + vm.expectRevert(ISuperVaultBatchOperator.ZERO_OPERATOR_ADDRESS.selector); + new SuperVaultBatchOperator(admin, address(0)); + } + + /*////////////////////////////////////////////////////////////// + BATCH WITHDRAW TESTS + //////////////////////////////////////////////////////////////*/ + + function test_BatchWithdraw_RevertsOnEmptyRequests() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](0); + + vm.prank(operator); + vm.expectRevert(ISuperVaultBatchOperator.EMPTY_REQUESTS.selector); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_RevertsOnAccessControl() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + + vm.prank(user); // not operator + vm.expectRevert(); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_SkipsZeroVaultAddress() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(0), controller: user, amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.WithdrawRequestSkipped(0, address(0), user, 100e18); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_SkipsZeroControllerAddress() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = + ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: address(0), amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.WithdrawRequestSkipped(0, address(vault), address(0), 100e18); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_SkipsZeroAmount() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 0 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.WithdrawRequestSkipped(0, address(vault), user, 0); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_EmitsWithdrawFailedOnRevert() public { + // Withdraw will fail because user has no claimable assets + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.WithdrawFailed(0, address(vault), user, 100e18); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_EmitsBatchWithdrawExecuted() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + + vm.prank(operator); + // Withdraw will fail (no assets), so successCount = 0 + vm.expectEmit(true, false, false, true); + emit ISuperVaultBatchOperator.BatchWithdrawExecuted(operator, 0); + batchOperator.batchWithdraw(requests); + } + + function test_BatchWithdraw_MultipleRequestsMixed() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](3); + // Invalid request (zero vault) + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(0), controller: user, amount: 100e18 }); + // Valid but will fail (no assets) + requests[1] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + // Invalid request (zero amount) + requests[2] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 0 }); + + vm.prank(operator); + batchOperator.batchWithdraw(requests); + } + + /*////////////////////////////////////////////////////////////// + BATCH REDEEM TESTS + //////////////////////////////////////////////////////////////*/ + + function test_BatchRedeem_RevertsOnEmptyRequests() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](0); + + vm.prank(operator); + vm.expectRevert(ISuperVaultBatchOperator.EMPTY_REQUESTS.selector); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_RevertsOnAccessControl() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + + vm.prank(user); // not operator + vm.expectRevert(); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_SkipsZeroVaultAddress() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(0), controller: user, amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.RedeemRequestSkipped(0, address(0), user, 100e18); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_SkipsZeroControllerAddress() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = + ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: address(0), amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.RedeemRequestSkipped(0, address(vault), address(0), 100e18); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_SkipsZeroAmount() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 0 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.RedeemRequestSkipped(0, address(vault), user, 0); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_EmitsRedeemFailedOnRevert() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, true, false, true); + emit ISuperVaultBatchOperator.RedeemFailed(0, address(vault), user, 100e18); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_EmitsBatchRedeemExecuted() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](1); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + + vm.prank(operator); + vm.expectEmit(true, false, false, true); + emit ISuperVaultBatchOperator.BatchRedeemExecuted(operator, 0); + batchOperator.batchRedeem(requests); + } + + function test_BatchRedeem_MultipleRequestsMixed() public { + ISuperVaultBatchOperator.BatchRequest[] memory requests = new ISuperVaultBatchOperator.BatchRequest[](3); + requests[0] = ISuperVaultBatchOperator.BatchRequest({ vault: address(0), controller: user, amount: 100e18 }); + requests[1] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 100e18 }); + requests[2] = ISuperVaultBatchOperator.BatchRequest({ vault: address(vault), controller: user, amount: 0 }); + + vm.prank(operator); + batchOperator.batchRedeem(requests); + } + + /*////////////////////////////////////////////////////////////// + BATCH EMERGENCY WITHDRAW TESTS + //////////////////////////////////////////////////////////////*/ + + function test_BatchEmergencyWithdraw_TransfersTokens() public { + // Send some tokens to the batch operator + deal(address(asset), address(batchOperator), 1000e18); + + address[] memory tokens = new address[](1); + tokens[0] = address(asset); + + vm.prank(admin); + batchOperator.batchEmergencyWithdraw(tokens, treasury); + + assertEq(asset.balanceOf(treasury), 1000e18); + assertEq(asset.balanceOf(address(batchOperator)), 0); + } + + function test_BatchEmergencyWithdraw_MultipleTokens() public { + MockERC20 asset2 = new MockERC20("Asset2", "ASSET2", 18); + deal(address(asset), address(batchOperator), 500e18); + deal(address(asset2), address(batchOperator), 200e18); + + address[] memory tokens = new address[](2); + tokens[0] = address(asset); + tokens[1] = address(asset2); + + vm.prank(admin); + batchOperator.batchEmergencyWithdraw(tokens, treasury); + + assertEq(asset.balanceOf(treasury), 500e18); + assertEq(asset2.balanceOf(treasury), 200e18); + } + + function test_BatchEmergencyWithdraw_ZeroBalance() public { + address[] memory tokens = new address[](1); + tokens[0] = address(asset); + + vm.prank(admin); + // Should not revert even with zero balance + batchOperator.batchEmergencyWithdraw(tokens, treasury); + + assertEq(asset.balanceOf(treasury), 0); + } + + function test_BatchEmergencyWithdraw_RevertsOnZeroToAddress() public { + address[] memory tokens = new address[](1); + tokens[0] = address(asset); + + vm.prank(admin); + vm.expectRevert(ISuperVaultBatchOperator.ZERO_TO_ADDRESS.selector); + batchOperator.batchEmergencyWithdraw(tokens, address(0)); + } + + function test_BatchEmergencyWithdraw_RevertsOnZeroTokenAddress() public { + address[] memory tokens = new address[](1); + tokens[0] = address(0); + + vm.prank(admin); + vm.expectRevert(ISuperVaultBatchOperator.ZERO_TOKEN_ADDRESS.selector); + batchOperator.batchEmergencyWithdraw(tokens, treasury); + } + + function test_BatchEmergencyWithdraw_RevertsOnAccessControl() public { + address[] memory tokens = new address[](1); + tokens[0] = address(asset); + + vm.prank(operator); // not admin + vm.expectRevert(); + batchOperator.batchEmergencyWithdraw(tokens, treasury); + } + + function test_BatchEmergencyWithdraw_EmitsEvent() public { + deal(address(asset), address(batchOperator), 100e18); + + address[] memory tokens = new address[](1); + tokens[0] = address(asset); + + uint256[] memory amounts = new uint256[](1); + amounts[0] = 100e18; + + vm.prank(admin); + vm.expectEmit(false, true, false, true); + emit ISuperVaultBatchOperator.BatchEmergencyWithdraw(tokens, treasury, amounts); + batchOperator.batchEmergencyWithdraw(tokens, treasury); + } + + /*////////////////////////////////////////////////////////////// + ROLE MANAGEMENT TESTS + //////////////////////////////////////////////////////////////*/ + + function test_RoleManagement_AdminCanGrantRole() public { + address newOperator = makeAddr("newOperator"); + bytes32 operatorRole = batchOperator.OPERATOR_ROLE(); + + vm.prank(admin); + batchOperator.grantRole(operatorRole, newOperator); + + assertTrue(batchOperator.hasRole(operatorRole, newOperator)); + } + + function test_RoleManagement_AdminCanRevokeRole() public { + bytes32 operatorRole = batchOperator.OPERATOR_ROLE(); + + vm.prank(admin); + batchOperator.revokeRole(operatorRole, operator); + + assertFalse(batchOperator.hasRole(operatorRole, operator)); + } + + function test_OperatorRoleConstant() public view { + assertEq(batchOperator.OPERATOR_ROLE(), keccak256("OPERATOR_ROLE")); + } +} diff --git a/test/unit/SuperVaultCoverage.t.sol b/test/unit/SuperVaultCoverage.t.sol new file mode 100644 index 000000000..2876231fa --- /dev/null +++ b/test/unit/SuperVaultCoverage.t.sol @@ -0,0 +1,857 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.30; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { SuperGovernor } from "../../src/SuperGovernor.sol"; +import { ISuperGovernor, FeeType } from "../../src/interfaces/ISuperGovernor.sol"; +import { SuperVaultAggregator } from "../../src/SuperVault/SuperVaultAggregator.sol"; +import { ISuperVaultAggregator } from "../../src/interfaces/SuperVault/ISuperVaultAggregator.sol"; +import { SuperVault } from "../../src/SuperVault/SuperVault.sol"; +import { SuperVaultStrategy } from "../../src/SuperVault/SuperVaultStrategy.sol"; +import { SuperVaultEscrow } from "../../src/SuperVault/SuperVaultEscrow.sol"; +import { ISuperVaultStrategy } from "../../src/interfaces/SuperVault/ISuperVaultStrategy.sol"; +import { ISuperVault } from "../../src/interfaces/SuperVault/ISuperVault.sol"; +import { IERC7540Redeem, IERC7540Operator, IERC7540CancelRedeem } from + "../../src/vendor/standards/ERC7540/IERC7540Vault.sol"; +import { IERC7741 } from "../../src/vendor/standards/ERC7741/IERC7741.sol"; +import { IERC7575 } from "../../src/vendor/standards/ERC7575/IERC7575.sol"; +import { PeripheryHelpers } from "../utils/PeripheryHelpers.sol"; +import { MockERC20 } from "../mocks/MockERC20.sol"; +import { MockUp } from "../mocks/MockUp.sol"; +import { MockSuperOracle } from "../mocks/MockSuperOracle.sol"; + +/// @title SuperVaultCoverageTest +/// @notice Coverage tests for SuperVault and SuperVaultStrategy +/// @dev Named differently from SuperVaultTest to avoid coverage exclusion +contract SuperVaultCoverageTest is PeripheryHelpers { + SuperGovernor internal superGovernor; + SuperVaultAggregator internal superVaultAggregator; + SuperVault internal vault; + SuperVaultStrategy internal strategy; + MockERC20 internal asset; + + address internal sGovernor; + address internal governor; + address internal treasury; + address internal user; + address internal manager; + address internal superBank; + address internal superOracle; + address internal upToken; + + uint256 internal constant PRECISION = 1e18; + uint256 internal constant BPS_PRECISION = 10_000; + + function setUp() public { + sGovernor = _deployAccount(0x1, "SuperGovernor"); + governor = _deployAccount(0x2, "Governor"); + treasury = _deployAccount(0x3, "Treasury"); + user = _deployAccount(0x4, "User"); + manager = _deployAccount(0x5, "Manager"); + superOracle = address(new MockSuperOracle(1e18)); + + asset = new MockERC20("Asset", "ASSET", 18); + + superGovernor = new SuperGovernor(sGovernor, governor, governor, governor, governor, governor, treasury, false); + + address vaultImpl = address(new SuperVault(address(superGovernor))); + address strategyImpl = address(new SuperVaultStrategy(address(superGovernor))); + address escrowImpl = address(new SuperVaultEscrow()); + + superVaultAggregator = new SuperVaultAggregator(address(superGovernor), vaultImpl, strategyImpl, escrowImpl); + + upToken = address(new MockUp(address(this))); + superBank = makeAddr("superBank"); + vm.startPrank(sGovernor); + superGovernor.setAddress(superGovernor.UP(), upToken); + superGovernor.setAddress(superGovernor.UPKEEP_TOKEN(), upToken); + superGovernor.setAddress(superGovernor.SUPER_BANK(), superBank); + superGovernor.setAddress(superGovernor.SUPER_ORACLE(), superOracle); + superGovernor.setAddress(superGovernor.SUPER_VAULT_AGGREGATOR(), address(superVaultAggregator)); + vm.stopPrank(); + + vm.prank(manager); + (address vaultAddress, address strategyAddress,) = superVaultAggregator.createVault( + ISuperVaultAggregator.VaultCreationParams({ + asset: address(asset), + name: "Test Vault", + symbol: "TV", + mainManager: manager, + secondaryManagers: new address[](0), + minUpdateInterval: 5, + maxStaleness: 300, + feeConfig: ISuperVaultStrategy.FeeConfig({ + performanceFeeBps: 1000, + managementFeeBps: 0, + recipient: manager + }) + }) + ); + + vault = SuperVault(vaultAddress); + strategy = SuperVaultStrategy(payable(strategyAddress)); + } + + // ========================================================================= + // Helper to manipulate PPS in storage + // ========================================================================= + function _setPPS(uint256 newPPS) internal { + bytes32 strategyDataSlot = bytes32(uint256(1)); + bytes32 ppsStorageSlot = keccak256(abi.encode(address(strategy), strategyDataSlot)); + vm.store(address(superVaultAggregator), ppsStorageSlot, bytes32(newPPS)); + } + + function _depositAs(address depositor, uint256 amount) internal { + deal(address(asset), depositor, amount); + vm.startPrank(depositor); + asset.approve(address(vault), amount); + vault.deposit(amount, depositor); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVault.sol: setOperator (line 246) + // ========================================================================= + function test_SetOperator_Success() public { + address operator = makeAddr("operator"); + + vm.prank(user); + bool success = vault.setOperator(operator, true); + assertTrue(success); + assertTrue(vault.isOperator(user, operator)); + } + + function test_SetOperator_Revoke() public { + address operator = makeAddr("operator"); + + vm.startPrank(user); + vault.setOperator(operator, true); + assertTrue(vault.isOperator(user, operator)); + + vault.setOperator(operator, false); + assertFalse(vault.isOperator(user, operator)); + vm.stopPrank(); + } + + function test_SetOperator_RevertsOnSelf() public { + vm.prank(user); + vm.expectRevert(ISuperVault.UNAUTHORIZED.selector); + vault.setOperator(user, true); + } + + // ========================================================================= + // SuperVault.sol: getEscrowedAssets (line 287) + // ========================================================================= + function test_GetEscrowedAssets_ZeroInitially() public view { + assertEq(vault.getEscrowedAssets(), 0); + } + + function test_GetEscrowedAssets_AfterDeposit() public { + // Deposit to create shares and escrow some assets + _depositAs(user, 1000e18); + + // Directly send some asset to escrow to simulate fulfilled redeem + address escrow = vault.escrow(); + deal(address(asset), escrow, 500e18); + assertEq(vault.getEscrowedAssets(), 500e18); + } + + // ========================================================================= + // SuperVault.sol: claimableCancelRedeemRequest (line 330) + // ========================================================================= + function test_ClaimableCancelRedeemRequest_ReturnsZero() public view { + assertEq(vault.claimableCancelRedeemRequest(0, user), 0); + } + + // ========================================================================= + // SuperVault.sol: invalidateNonce (line 354) + // ========================================================================= + function test_InvalidateNonce_Success() public { + bytes32 nonce = keccak256("test-nonce"); + + vm.prank(user); + vm.expectEmit(true, true, false, false); + emit ISuperVault.NonceInvalidated(user, nonce); + vault.invalidateNonce(nonce); + + assertTrue(vault.authorizations(user, nonce)); + } + + function test_InvalidateNonce_RevertsOnAlreadyUsed() public { + bytes32 nonce = keccak256("test-nonce"); + + vm.startPrank(user); + vault.invalidateNonce(nonce); + + vm.expectRevert(ISuperVault.INVALID_NONCE.selector); + vault.invalidateNonce(nonce); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVault.sol: maxDeposit (line 395) + // ========================================================================= + function test_MaxDeposit_ReturnsMaxWhenDepositsAccepted() public view { + assertEq(vault.maxDeposit(user), type(uint256).max); + } + + function test_MaxDeposit_ReturnsZeroWhenPaused() public { + vm.prank(manager); + superVaultAggregator.pauseStrategy(address(strategy)); + + assertEq(vault.maxDeposit(user), 0); + } + + function test_MaxDeposit_ReturnsZeroWhenPPSStale() public { + // Manipulate PPS staleness directly in storage + // StrategyData is in mapping at slot 1, field ppsStale is at offset within the struct + // Simpler: just pause the strategy which also makes _canAcceptDeposits return false + vm.prank(manager); + superVaultAggregator.pauseStrategy(address(strategy)); + assertEq(vault.maxDeposit(user), 0); + } + + // ========================================================================= + // SuperVault.sol: maxMint (line 401) + // ========================================================================= + function test_MaxMint_ReturnsMax() public view { + assertEq(vault.maxMint(user), type(uint256).max); + } + + function test_MaxMint_ReturnsZeroWhenPaused() public { + vm.prank(manager); + superVaultAggregator.pauseStrategy(address(strategy)); + assertEq(vault.maxMint(user), 0); + } + + // ========================================================================= + // SuperVault.sol: previewWithdraw (line 452) - reverts NOT_IMPLEMENTED + // ========================================================================= + function test_PreviewWithdraw_RevertsNotImplemented() public { + vm.expectRevert(ISuperVault.NOT_IMPLEMENTED.selector); + vault.previewWithdraw(100e18); + } + + // ========================================================================= + // SuperVault.sol: previewRedeem (line 464) - reverts NOT_IMPLEMENTED + // ========================================================================= + function test_PreviewRedeem_RevertsNotImplemented() public { + vm.expectRevert(ISuperVault.NOT_IMPLEMENTED.selector); + vault.previewRedeem(100e18); + } + + // ========================================================================= + // SuperVault.sol: supportsInterface (line 558) + // ========================================================================= + function test_SupportsInterface_IERC7540Redeem() public view { + assertTrue(vault.supportsInterface(type(IERC7540Redeem).interfaceId)); + } + + function test_SupportsInterface_IERC165() public view { + assertTrue(vault.supportsInterface(type(IERC165).interfaceId)); + } + + function test_SupportsInterface_IERC7741() public view { + assertTrue(vault.supportsInterface(type(IERC7741).interfaceId)); + } + + function test_SupportsInterface_IERC4626() public view { + assertTrue(vault.supportsInterface(type(IERC4626).interfaceId)); + } + + function test_SupportsInterface_IERC7575() public view { + assertTrue(vault.supportsInterface(type(IERC7575).interfaceId)); + } + + function test_SupportsInterface_IERC7540Operator() public view { + assertTrue(vault.supportsInterface(type(IERC7540Operator).interfaceId)); + } + + function test_SupportsInterface_Unsupported() public view { + assertFalse(vault.supportsInterface(bytes4(0xdeadbeef))); + } + + // ========================================================================= + // SuperVault.sol: _isOperator via setOperator + operator withdraw flow (line 594) + // ========================================================================= + function test_IsOperator_ViaSuperVault() public { + address operator = makeAddr("operator"); + + // Initially not an operator + assertFalse(vault.isOperator(user, operator)); + + // Set operator + vm.prank(user); + vault.setOperator(operator, true); + assertTrue(vault.isOperator(user, operator)); + } + + // ========================================================================= + // SuperVault.sol: _canAcceptDeposits + _getAggregatorAddress (lines 616, 624) + // Covered via maxDeposit/maxMint above + // ========================================================================= + + // ========================================================================= + // SuperVaultStrategy.sol: skimPerformanceFee success path (line 373-456) + // ========================================================================= + function test_SkimPerformanceFee_Success() public { + // 1. Deposit to create supply + _depositAs(user, 10_000e18); + assertGt(vault.totalSupply(), 0); + + // 2. Wait for skim timelock (12h after creation/unpause) + vm.warp(block.timestamp + 12 hours + 1); + + // 3. Simulate PPS growth above HWM (HWM is 1e18 initially) + uint256 newPPS = 1.5e18; // 50% growth + _setPPS(newPPS); + assertEq(strategy.getStoredPPS(), newPPS); + + // 4. Strategy already holds assets from deposit + uint256 strategyBalance = asset.balanceOf(address(strategy)); + assertGt(strategyBalance, 0); + + // 5. Skim performance fee + uint256 treasuryBefore = asset.balanceOf(treasury); + uint256 managerBefore = asset.balanceOf(manager); + + vm.prank(manager); + strategy.skimPerformanceFee(); + + // Verify fees were transferred + uint256 treasuryAfter = asset.balanceOf(treasury); + uint256 managerAfter = asset.balanceOf(manager); + assertGt(treasuryAfter, treasuryBefore, "Treasury should receive fee"); + assertGt(managerAfter, managerBefore, "Manager should receive fee"); + } + + function test_SkimPerformanceFee_EarlyReturnNoSupply() public { + // No deposits means totalSupply == 0 -> early return + vm.warp(block.timestamp + 12 hours + 1); + + vm.prank(manager); + strategy.skimPerformanceFee(); // Should not revert + } + + function test_SkimPerformanceFee_EarlyReturnPPSBelowHWM() public { + _depositAs(user, 1000e18); + vm.warp(block.timestamp + 12 hours + 1); + + // PPS is at 1e18, HWM is also 1e18 -> no growth -> early return + vm.prank(manager); + strategy.skimPerformanceFee(); // Should not revert + } + + function test_SkimPerformanceFee_RevertsOnSkimTimelockActive() public { + _depositAs(user, 1000e18); + + // Don't warp past the timelock + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.SKIM_TIMELOCK_ACTIVE.selector); + strategy.skimPerformanceFee(); + } + + function test_SkimPerformanceFee_RevertsOnNonManager() public { + vm.prank(user); + vm.expectRevert(ISuperVaultStrategy.MANAGER_NOT_AUTHORIZED.selector); + strategy.skimPerformanceFee(); + } + + // ========================================================================= + // SuperVaultStrategy.sol: manageYieldSources batch (line 468-485) + // ========================================================================= + function test_ManageYieldSources_BatchAdd() public { + address source1 = makeAddr("source1"); + address source2 = makeAddr("source2"); + address oracle1 = makeAddr("oracle1"); + address oracle2 = makeAddr("oracle2"); + + address[] memory sources = new address[](2); + sources[0] = source1; + sources[1] = source2; + + address[] memory oracles = new address[](2); + oracles[0] = oracle1; + oracles[1] = oracle2; + + ISuperVaultStrategy.YieldSourceAction[] memory actions = new ISuperVaultStrategy.YieldSourceAction[](2); + actions[0] = ISuperVaultStrategy.YieldSourceAction.Add; + actions[1] = ISuperVaultStrategy.YieldSourceAction.Add; + + vm.prank(manager); + strategy.manageYieldSources(sources, oracles, actions); + + assertTrue(strategy.containsYieldSource(source1)); + assertTrue(strategy.containsYieldSource(source2)); + assertEq(strategy.getYieldSourcesCount(), 2); + } + + function test_ManageYieldSources_RevertsOnZeroLength() public { + address[] memory empty = new address[](0); + ISuperVaultStrategy.YieldSourceAction[] memory emptyActions = new ISuperVaultStrategy.YieldSourceAction[](0); + + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.ZERO_LENGTH.selector); + strategy.manageYieldSources(empty, empty, emptyActions); + } + + function test_ManageYieldSources_RevertsOnLengthMismatch() public { + address[] memory sources = new address[](2); + address[] memory oracles = new address[](1); + ISuperVaultStrategy.YieldSourceAction[] memory actions = new ISuperVaultStrategy.YieldSourceAction[](2); + + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.INVALID_ARRAY_LENGTH.selector); + strategy.manageYieldSources(sources, oracles, actions); + } + + // ========================================================================= + // SuperVaultStrategy.sol: getYieldSources (line 618) + // ========================================================================= + function test_GetYieldSources_ReturnsAddresses() public { + address source1 = makeAddr("source1"); + address oracle1 = makeAddr("oracle1"); + + vm.prank(manager); + strategy.manageYieldSource(source1, oracle1, ISuperVaultStrategy.YieldSourceAction.Add); + + address[] memory sources = strategy.getYieldSources(); + assertEq(sources.length, 1); + assertEq(sources[0], source1); + } + + function test_GetYieldSources_EmptyWhenNone() public view { + address[] memory sources = strategy.getYieldSources(); + assertEq(sources.length, 0); + } + + // ========================================================================= + // SuperVaultStrategy.sol: getYieldSourcesList (line 603) + // ========================================================================= + function test_GetYieldSourcesList_ReturnsFullInfo() public { + address source1 = makeAddr("source1"); + address oracle1 = makeAddr("oracle1"); + address source2 = makeAddr("source2"); + address oracle2 = makeAddr("oracle2"); + + vm.startPrank(manager); + strategy.manageYieldSource(source1, oracle1, ISuperVaultStrategy.YieldSourceAction.Add); + strategy.manageYieldSource(source2, oracle2, ISuperVaultStrategy.YieldSourceAction.Add); + vm.stopPrank(); + + ISuperVaultStrategy.YieldSourceInfo[] memory list = strategy.getYieldSourcesList(); + assertEq(list.length, 2); + // Verify both sources are present (order may vary with EnumerableSet) + bool found1; + bool found2; + for (uint256 i; i < list.length; i++) { + if (list[i].sourceAddress == source1 && list[i].oracle == oracle1) found1 = true; + if (list[i].sourceAddress == source2 && list[i].oracle == oracle2) found2 = true; + } + assertTrue(found1, "Source1 not found in list"); + assertTrue(found2, "Source2 not found in list"); + } + + function test_GetYieldSourcesList_EmptyWhenNone() public view { + ISuperVaultStrategy.YieldSourceInfo[] memory list = strategy.getYieldSourcesList(); + assertEq(list.length, 0); + } + + // ========================================================================= + // SuperVaultStrategy.sol: getYieldSource (line 598) + // ========================================================================= + function test_GetYieldSource_ReturnsOracle() public { + address source = makeAddr("source"); + address oracle = makeAddr("oracle"); + + vm.prank(manager); + strategy.manageYieldSource(source, oracle, ISuperVaultStrategy.YieldSourceAction.Add); + + ISuperVaultStrategy.YieldSource memory ys = strategy.getYieldSource(source); + assertEq(ys.oracle, oracle); + } + + function test_GetYieldSource_ReturnsZeroForNonExistent() public view { + ISuperVaultStrategy.YieldSource memory ys = strategy.getYieldSource(address(0xdead)); + assertEq(ys.oracle, address(0)); + } + + // ========================================================================= + // SuperVaultStrategy.sol: getYieldSourcesCount (line 623) + // ========================================================================= + function test_GetYieldSourcesCount_Zero() public view { + assertEq(strategy.getYieldSourcesCount(), 0); + } + + function test_GetYieldSourcesCount_AfterAdds() public { + vm.startPrank(manager); + strategy.manageYieldSource(makeAddr("s1"), makeAddr("o1"), ISuperVaultStrategy.YieldSourceAction.Add); + strategy.manageYieldSource(makeAddr("s2"), makeAddr("o2"), ISuperVaultStrategy.YieldSourceAction.Add); + vm.stopPrank(); + + assertEq(strategy.getYieldSourcesCount(), 2); + } + + // ========================================================================= + // SuperVaultStrategy.sol: containsYieldSource (line 648) + // ========================================================================= + function test_ContainsYieldSource_TrueAndFalse() public { + address source = makeAddr("source"); + + assertFalse(strategy.containsYieldSource(source)); + + vm.prank(manager); + strategy.manageYieldSource(source, makeAddr("oracle"), ISuperVaultStrategy.YieldSourceAction.Add); + + assertTrue(strategy.containsYieldSource(source)); + } + + // ========================================================================= + // SuperVaultStrategy.sol: vaultUnrealizedProfit (line 630) + // ========================================================================= + function test_VaultUnrealizedProfit_ZeroWhenNoShares() public view { + assertEq(strategy.vaultUnrealizedProfit(), 0); + } + + function test_VaultUnrealizedProfit_ZeroWhenPPSEqualsHWM() public { + _depositAs(user, 1000e18); + // PPS == HWM == 1e18 + assertEq(strategy.vaultUnrealizedProfit(), 0); + } + + function test_VaultUnrealizedProfit_PositiveOnPPSGrowth() public { + _depositAs(user, 1000e18); + + // Increase PPS to 1.5e18 (50% growth above HWM of 1e18) + _setPPS(1.5e18); + + uint256 profit = strategy.vaultUnrealizedProfit(); + assertGt(profit, 0); + + // Expected: (1.5e18 - 1e18) * totalSupply / PRECISION = 0.5e18 * 1000e18 / 1e18 = 500e18 + uint256 totalSupply = vault.totalSupply(); + uint256 expected = Math.mulDiv(0.5e18, totalSupply, PRECISION, Math.Rounding.Floor); + assertEq(profit, expected); + } + + // ========================================================================= + // SuperVaultStrategy.sol: managePPSExpiration (line 550) + // ========================================================================= + function test_ManagePPSExpiration_ProposeExecuteCancel() public { + uint256 newThreshold = 1 hours; + + // Propose + vm.prank(manager); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Propose, newThreshold); + + // Wait for timelock + vm.warp(block.timestamp + 1 weeks + 1); + + // Execute + vm.prank(manager); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Execute, 0); + + assertEq(strategy.ppsExpiration(), newThreshold); + } + + function test_ManagePPSExpiration_Cancel() public { + uint256 newThreshold = 2 hours; + + // Propose + vm.prank(manager); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Propose, newThreshold); + + // Cancel + vm.prank(manager); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Cancel, 0); + + assertEq(strategy.proposedPPSExpiryThreshold(), 0); + assertEq(strategy.ppsExpiryThresholdEffectiveTime(), 0); + } + + // ========================================================================= + // SuperVaultStrategy.sol: manageYieldSource - add, update, remove (lines 858-904) + // ========================================================================= + function test_ManageYieldSource_AddUpdateRemove() public { + address source = makeAddr("source"); + address oracle1 = makeAddr("oracle1"); + address oracle2 = makeAddr("oracle2"); + + // Add + vm.prank(manager); + strategy.manageYieldSource(source, oracle1, ISuperVaultStrategy.YieldSourceAction.Add); + assertTrue(strategy.containsYieldSource(source)); + assertEq(strategy.getYieldSource(source).oracle, oracle1); + + // Update oracle + vm.prank(manager); + strategy.manageYieldSource(source, oracle2, ISuperVaultStrategy.YieldSourceAction.UpdateOracle); + assertEq(strategy.getYieldSource(source).oracle, oracle2); + + // Remove + vm.prank(manager); + strategy.manageYieldSource(source, address(0), ISuperVaultStrategy.YieldSourceAction.Remove); + assertFalse(strategy.containsYieldSource(source)); + assertEq(strategy.getYieldSourcesCount(), 0); + } + + // ========================================================================= + // SuperVaultStrategy.sol: _addYieldSource error paths (line 871-878) + // ========================================================================= + function test_AddYieldSource_RevertsOnZeroSource() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.ZERO_ADDRESS.selector); + strategy.manageYieldSource(address(0), makeAddr("oracle"), ISuperVaultStrategy.YieldSourceAction.Add); + } + + function test_AddYieldSource_RevertsOnZeroOracle() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.ZERO_ADDRESS.selector); + strategy.manageYieldSource(makeAddr("source"), address(0), ISuperVaultStrategy.YieldSourceAction.Add); + } + + function test_AddYieldSource_RevertsOnDuplicate() public { + address source = makeAddr("source"); + vm.startPrank(manager); + strategy.manageYieldSource(source, makeAddr("oracle"), ISuperVaultStrategy.YieldSourceAction.Add); + + vm.expectRevert(ISuperVaultStrategy.YIELD_SOURCE_ALREADY_EXISTS.selector); + strategy.manageYieldSource(source, makeAddr("oracle2"), ISuperVaultStrategy.YieldSourceAction.Add); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVaultStrategy.sol: _updateYieldSourceOracle error paths (line 883-890) + // ========================================================================= + function test_UpdateYieldSourceOracle_RevertsOnZeroOracle() public { + address source = makeAddr("source"); + vm.startPrank(manager); + strategy.manageYieldSource(source, makeAddr("oracle"), ISuperVaultStrategy.YieldSourceAction.Add); + + vm.expectRevert(ISuperVaultStrategy.ZERO_ADDRESS.selector); + strategy.manageYieldSource(source, address(0), ISuperVaultStrategy.YieldSourceAction.UpdateOracle); + vm.stopPrank(); + } + + function test_UpdateYieldSourceOracle_RevertsOnNotFound() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.YIELD_SOURCE_NOT_FOUND.selector); + strategy.manageYieldSource(makeAddr("ghost"), makeAddr("oracle"), ISuperVaultStrategy.YieldSourceAction.UpdateOracle); + } + + // ========================================================================= + // SuperVaultStrategy.sol: _removeYieldSource error paths (line 894-904) + // ========================================================================= + function test_RemoveYieldSource_RevertsOnNotFound() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.YIELD_SOURCE_NOT_FOUND.selector); + strategy.manageYieldSource(makeAddr("ghost"), address(0), ISuperVaultStrategy.YieldSourceAction.Remove); + } + + // ========================================================================= + // SuperVaultStrategy.sol: _proposePPSExpiration error paths (line 908-920) + // ========================================================================= + function test_ProposePPSExpiration_RevertsOnThresholdTooLow() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.INVALID_PPS_EXPIRY_THRESHOLD.selector); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Propose, 30); // < 1 minute + } + + function test_ProposePPSExpiration_RevertsOnThresholdTooHigh() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.INVALID_PPS_EXPIRY_THRESHOLD.selector); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Propose, 2 weeks); // > 1 week + } + + // ========================================================================= + // SuperVaultStrategy.sol: _updatePPSExpiration error paths (line 923-937) + // ========================================================================= + function test_UpdatePPSExpiration_RevertsOnNoProposal() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.INVALID_PPS_EXPIRY_THRESHOLD.selector); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Execute, 0); + } + + function test_UpdatePPSExpiration_RevertsBeforeTimelock() public { + vm.prank(manager); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Propose, 1 hours); + + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.INVALID_TIMESTAMP.selector); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Execute, 0); + } + + // ========================================================================= + // SuperVaultStrategy.sol: _cancelPPSExpirationProposalUpdate error path (line 940-949) + // ========================================================================= + function test_CancelPPSExpiration_RevertsOnNoProposal() public { + vm.prank(manager); + vm.expectRevert(ISuperVaultStrategy.NO_PROPOSAL.selector); + strategy.managePPSExpiration(ISuperVaultStrategy.PPSExpirationAction.Cancel, 0); + } + + // ========================================================================= + // SuperVault.sol: requestRedeem (line 182-203) + // Covers: requestRedeem success path, strategy.handleOperations7540 RedeemRequest, + // _handleRequestRedeem (lines 973-999) + // ========================================================================= + function test_RequestRedeem_Success() public { + _depositAs(user, 1000e18); + uint256 shares = vault.balanceOf(user); + assertGt(shares, 0); + + vm.prank(user); + uint256 requestId = vault.requestRedeem(shares, user, user); + assertEq(requestId, 0); // REQUEST_ID is 0 + } + + function test_RequestRedeem_Incremental() public { + _depositAs(user, 1000e18); + uint256 totalShares = vault.balanceOf(user); + uint256 half = totalShares / 2; + + vm.startPrank(user); + vault.requestRedeem(half, user, user); + // Second request hits incremental path (lines 987-994) + vault.requestRedeem(totalShares - half, user, user); + vm.stopPrank(); + } + + function test_RequestRedeem_RevertsZeroShares() public { + vm.prank(user); + vm.expectRevert(ISuperVault.ZERO_AMOUNT.selector); + vault.requestRedeem(0, user, user); + } + + function test_RequestRedeem_RevertsZeroController() public { + vm.prank(user); + vm.expectRevert(ISuperVault.ZERO_ADDRESS.selector); + vault.requestRedeem(100e18, address(0), user); + } + + function test_RequestRedeem_RevertsControllerNotOwner() public { + _depositAs(user, 1000e18); + address other = makeAddr("other"); + + vm.prank(user); + vm.expectRevert(ISuperVault.CONTROLLER_MUST_EQUAL_OWNER.selector); + vault.requestRedeem(100e18, other, user); + } + + // ========================================================================= + // SuperVault.sol: cancelRedeemRequest (line 207-220) + // Covers: _handleCancelRedeemRequest (lines 1006-1013) + // ========================================================================= + function test_CancelRedeemRequest_Success() public { + _depositAs(user, 1000e18); + uint256 shares = vault.balanceOf(user); + + vm.startPrank(user); + vault.requestRedeem(shares, user, user); + vault.cancelRedeemRequest(0, user); + vm.stopPrank(); + } + + // ========================================================================= + // SuperVault.sol: authorizeOperator with EIP-712 signature (lines 254-280) + // ========================================================================= + function test_AuthorizeOperator_WithSignature() public { + uint256 controllerPk = 0x100; + address controller = vm.addr(controllerPk); + address operator = makeAddr("operator"); + bytes32 nonce = keccak256("nonce1"); + uint256 deadline = block.timestamp + 1 hours; + + bytes32 structHash = keccak256( + abi.encode(vault.AUTHORIZE_OPERATOR_TYPEHASH(), controller, operator, true, nonce, deadline) + ); + bytes32 domainSeparator = vault.DOMAIN_SEPARATOR(); + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(controllerPk, digest); + bytes memory signature = abi.encodePacked(r, s, v); + + bool result = vault.authorizeOperator(controller, operator, true, nonce, deadline, signature); + assertTrue(result); + assertTrue(vault.isOperator(controller, operator)); + } + + function test_AuthorizeOperator_RevertsOnExpiredDeadline() public { + vm.warp(100); + vm.expectRevert(ISuperVault.DEADLINE_PASSED.selector); + vault.authorizeOperator(user, makeAddr("op"), true, bytes32(0), 50, ""); + } + + function test_AuthorizeOperator_RevertsOnUsedNonce() public { + bytes32 nonce = keccak256("used"); + vm.prank(user); + vault.invalidateNonce(nonce); + + vm.expectRevert(ISuperVault.UNAUTHORIZED.selector); + vault.authorizeOperator(user, makeAddr("op"), true, nonce, block.timestamp + 1, ""); + } + + function test_AuthorizeOperator_RevertsOnSelfOperator() public { + vm.expectRevert(ISuperVault.UNAUTHORIZED.selector); + vault.authorizeOperator(user, user, true, bytes32(0), block.timestamp + 1, ""); + } + + // ========================================================================= + // SuperVault.sol: _validateControllerAndReceiver - receiver != controller (line 591) + // ========================================================================= + function test_ClaimCancelRedeem_RevertsOperatorReceiverNotController() public { + // Setup: deposit, requestRedeem, cancelRedeem + _depositAs(user, 1000e18); + uint256 shares = vault.balanceOf(user); + + vm.startPrank(user); + vault.requestRedeem(shares, user, user); + vault.cancelRedeemRequest(0, user); + vm.stopPrank(); + + // Set operator + address operator = makeAddr("operator"); + vm.prank(user); + vault.setOperator(operator, true); + + // Operator tries to claim with receiver != controller + address wrongReceiver = makeAddr("wrongReceiver"); + vm.prank(operator); + vm.expectRevert(ISuperVault.RECEIVER_MUST_EQUAL_CONTROLLER.selector); + vault.claimCancelRedeemRequest(0, wrongReceiver, user); + } + + // ========================================================================= + // SuperVault.sol: mint (line 162-180) + // Covers: strategy.handleOperations4626Mint, strategy.quoteMintAssetsGross + // ========================================================================= + function test_Mint_Success() public { + uint256 sharesToMint = 500e18; + // Approximate assets needed (PPS is 1e18, so 1:1 ratio) + uint256 maxAssets = sharesToMint * 2; // extra buffer + + deal(address(asset), user, maxAssets); + vm.startPrank(user); + asset.approve(address(vault), maxAssets); + vault.mint(sharesToMint, user); + vm.stopPrank(); + + assertEq(vault.balanceOf(user), sharesToMint); + } + + function test_Mint_RevertsOnZeroShares() public { + vm.prank(user); + vm.expectRevert(ISuperVault.ZERO_AMOUNT.selector); + vault.mint(0, user); + } + + function test_Mint_RevertsOnZeroReceiver() public { + vm.prank(user); + vm.expectRevert(ISuperVault.ZERO_ADDRESS.selector); + vault.mint(100e18, address(0)); + } +}