diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..4cbef881 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +node_modules +artifacts +cache +types +forge-out +lib diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 28c888b5..d16776de 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -40,8 +40,8 @@ jobs: - name: Run forge unit tests run: forge test --match-test test_U -vv - - name: Run forge integration tests - run: forge test --match-test _live_ --fork-url ${{ secrets.MAINNET_TESTS_FORK }} --chain-id 1337 -vv + # - name: Run forge integration tests + # run: forge test --match-test _live_ --fork-url ${{ secrets.MAINNET_TESTS_FORK }} --chain-id 1337 -vv - name: Perform checks run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f13a85d8..a201857c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,7 @@ on: branches: - "main" - "next" + - "abi" env: HUSKY: 0 @@ -15,35 +16,33 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: cache: "yarn" node-version-file: ".nvmrc" + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + - name: Configure access to private npm packages run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc # prepare script runs before publish, and it needs husky - name: Install dependencies run: | + forge install yarn install --frozen-lockfile - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Run forge build - run: forge build - timeout-minutes: 10 - - - name: Build dist + - name: Build run: yarn build - name: Semantic Release - uses: cycjimmy/semantic-release-action@v3 + uses: cycjimmy/semantic-release-action@v4 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 19b55a71..082b2dcb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,23 @@ -/node_modules -/forge-out -.DS_Store -cache +# Dependencies +node_modules/ + +# Compiler files +cache/ +out/ +dist/ +**/*.generated.* +**/generated/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file .env -npm-root -types -dist \ No newline at end of file + +# Logs +*.log diff --git a/.gitmodules b/.gitmodules index 888d42dc..2f4bb229 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,15 @@ -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std +[submodule "lib/@gearbox-protocol/sdk-gov"] + path = lib/@gearbox-protocol/sdk-gov + url = https://github.com/Gearbox-protocol/sdk-gov +[submodule "lib/@gearbox-protocol/core-v3"] + path = lib/@gearbox-protocol/core-v3 + url = https://github.com/Gearbox-protocol/core-v3 +[submodule "lib/@gearbox-protocol/oracles-v3"] + path = lib/@gearbox-protocol/oracles-v3 + url = https://github.com/Gearbox-protocol/oracles-v3 +[submodule "lib/@1inch/solidity-utils"] + path = lib/@1inch/solidity-utils + url = https://github.com/1inch/solidity-utils +[submodule "lib/@1inch/farming"] + path = lib/@1inch/farming + url = https://github.com/1inch/farming diff --git a/.husky/commit-msg b/.husky/commit-msg index 4974c35b..a78cc751 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - npx commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit index 36af2198..2312dc58 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - npx lint-staged diff --git a/.nvmrc b/.nvmrc index b6a7d89c..2bd5a0a9 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16 +22 diff --git a/.prettierignore b/.prettierignore index d9cf9ffc..b02b5760 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,5 @@ artifacts cache types forge-out +lib +dist \ No newline at end of file diff --git a/.releaserc.json b/.releaserc.json index cc2b0ec0..4928a7ef 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -7,12 +7,23 @@ "name": "next", "channel": "next", "prerelease": "next" + }, + { + "name": "abi", + "channel": "abi", + "prerelease": "abi" } ], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", - "@semantic-release/github" + [ + "@semantic-release/github", + { + "successComment": false, + "failTitle": false + } + ] ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 6fa1e227..2aa709ed 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,14 +5,12 @@ "[solidity]": { "editor.defaultFormatter": "JuanBlanco.solidity" }, - "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.tabSize": 4, - "eslint.validate": ["javascript", "typescript"], "files.eol": "\n", "solidity.formatter": "forge", "solidity.packageDefaultDependenciesContractsDirectory": "contracts", - "solidity.packageDefaultDependenciesDirectory": "node_modules", - "solidity.compileUsingRemoteVersion": "v0.8.17" + "solidity.packageDefaultDependenciesDirectory": "lib", + "solidity.compileUsingRemoteVersion": "v0.8.23" } diff --git a/config_scripts/daiMainnetScript.ts b/config_scripts/daiMainnetScript.ts deleted file mode 100644 index be06691e..00000000 --- a/config_scripts/daiMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - daiConfigMainnet, - PoolV3CoreConfigurator, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(daiConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/ghoMainnetScript.ts b/config_scripts/ghoMainnetScript.ts deleted file mode 100644 index b8d34af0..00000000 --- a/config_scripts/ghoMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - ghoConfigMainnet, - PoolV3CoreConfigurator, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(ghoConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/test_daiMainnetScript.ts b/config_scripts/test_daiMainnetScript.ts deleted file mode 100644 index 64b33075..00000000 --- a/config_scripts/test_daiMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - testDaiConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(testDaiConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/test_usdcMainnetScript.ts b/config_scripts/test_usdcMainnetScript.ts deleted file mode 100644 index e091329e..00000000 --- a/config_scripts/test_usdcMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - testUsdcConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(testUsdcConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/test_wethArbitrumScript.ts b/config_scripts/test_wethArbitrumScript.ts deleted file mode 100644 index 91b26cc4..00000000 --- a/config_scripts/test_wethArbitrumScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - testWethConfigArbitrum, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(testWethConfigArbitrum); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/test_wethMainnetScript.ts b/config_scripts/test_wethMainnetScript.ts deleted file mode 100644 index 3725211f..00000000 --- a/config_scripts/test_wethMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - testWethConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(testWethConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/usdcArbitrumScript.ts b/config_scripts/usdcArbitrumScript.ts deleted file mode 100644 index 8466b5dd..00000000 --- a/config_scripts/usdcArbitrumScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - usdcConfigArbitrum, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(usdcConfigArbitrum); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/usdcMainnetScript.ts b/config_scripts/usdcMainnetScript.ts deleted file mode 100644 index 88a96f31..00000000 --- a/config_scripts/usdcMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - usdcConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(usdcConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/usdcOptimismScript.ts b/config_scripts/usdcOptimismScript.ts deleted file mode 100644 index 31d55a81..00000000 --- a/config_scripts/usdcOptimismScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - usdcConfigOptimism, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(usdcConfigOptimism); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/usdtMainnetScript.ts b/config_scripts/usdtMainnetScript.ts deleted file mode 100644 index 945bad93..00000000 --- a/config_scripts/usdtMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - usdtConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(usdtConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/wbtcMainnetScript.ts b/config_scripts/wbtcMainnetScript.ts deleted file mode 100644 index d6e68ac4..00000000 --- a/config_scripts/wbtcMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - wbtcConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(wbtcConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/wethArbitrumScript.ts b/config_scripts/wethArbitrumScript.ts deleted file mode 100644 index c56ca1ec..00000000 --- a/config_scripts/wethArbitrumScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - wethConfigArbitrum, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(wethConfigArbitrum); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/wethMainnetScript.ts b/config_scripts/wethMainnetScript.ts deleted file mode 100644 index a32fd7b4..00000000 --- a/config_scripts/wethMainnetScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - wethConfigMainnet, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(wethConfigMainnet); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/config_scripts/wethOptimismScript.ts b/config_scripts/wethOptimismScript.ts deleted file mode 100644 index da71ac7a..00000000 --- a/config_scripts/wethOptimismScript.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - PoolV3CoreConfigurator, - wethConfigOptimism, -} from "@gearbox-protocol/sdk-gov"; - -const poolCfg = PoolV3CoreConfigurator.new(wethConfigOptimism); -console.error(poolCfg.toString()); - -console.log(poolCfg.deployConfig()); diff --git a/contracts/adapters/AbstractAdapter.sol b/contracts/adapters/AbstractAdapter.sol index c8510d50..9895ba25 100644 --- a/contracts/adapters/AbstractAdapter.sol +++ b/contracts/adapters/AbstractAdapter.sol @@ -1,22 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; +import {PoolV3} from "@gearbox-protocol/core-v3/contracts/pool/PoolV3.sol"; import {CallerNotCreditFacadeException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; import {ACLTrait} from "@gearbox-protocol/core-v3/contracts/traits/ACLTrait.sol"; +import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol"; /// @title Abstract adapter /// @dev Inheriting adapters MUST use provided internal functions to perform all operations with credit accounts -abstract contract AbstractAdapter is IAdapter, ACLTrait { +abstract contract AbstractAdapter is IAdapter, ACLTrait, SanityCheckTrait { /// @notice Credit manager the adapter is connected to address public immutable override creditManager; - /// @notice Address provider contract - address public immutable override addressProvider; - /// @notice Address of the contract the adapter is interacting with address public immutable override targetContract; @@ -24,11 +23,10 @@ abstract contract AbstractAdapter is IAdapter, ACLTrait { /// @param _creditManager Credit manager to connect the adapter to /// @param _targetContract Address of the adapted contract constructor(address _creditManager, address _targetContract) - ACLTrait(ICreditManagerV3(_creditManager).addressProvider()) + ACLTrait(PoolV3(ICreditManagerV3(_creditManager).pool()).acl()) nonZeroAddress(_targetContract) { creditManager = _creditManager; - addressProvider = ICreditManagerV3(_creditManager).addressProvider(); targetContract = _targetContract; } @@ -72,43 +70,13 @@ abstract contract AbstractAdapter is IAdapter, ACLTrait { return ICreditManagerV3(creditManager).execute(callData); } - /// @dev Executes a swap operation without input token approval - /// Reverts if active credit account is not set or any of passed tokens is not registered as collateral - /// @param tokenIn Input token that credit account spends in the call - /// @param tokenOut Output token that credit account receives after the call - /// @param callData Data to call the target contract with - /// @param disableTokenIn Whether `tokenIn` should be disabled after the call - /// (for operations that spend the entire account's balance of the input token) - /// @return tokensToEnable Bit mask of tokens that should be enabled after the call - /// @return tokensToDisable Bit mask of tokens that should be disabled after the call - /// @return result Call result - function _executeSwapNoApprove(address tokenIn, address tokenOut, bytes memory callData, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable, bytes memory result) - { - tokensToEnable = _getMaskOrRevert(tokenOut); - uint256 tokenInMask = _getMaskOrRevert(tokenIn); - if (disableTokenIn) tokensToDisable = tokenInMask; - result = _execute(callData); - } - /// @dev Executes a swap operation with maximum input token approval, and revokes approval after the call /// Reverts if active credit account is not set or any of passed tokens is not registered as collateral /// @param tokenIn Input token that credit account spends in the call - /// @param tokenOut Output token that credit account receives after the call /// @param callData Data to call the target contract with - /// @param disableTokenIn Whether `tokenIn` should be disabled after the call - /// (for operations that spend the entire account's balance of the input token) - /// @return tokensToEnable Bit mask of tokens that should be enabled after the call - /// @return tokensToDisable Bit mask of tokens that should be disabled after the call /// @return result Call result /// @custom:expects Credit manager reverts when trying to approve non-collateral token - function _executeSwapSafeApprove(address tokenIn, address tokenOut, bytes memory callData, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable, bytes memory result) - { - tokensToEnable = _getMaskOrRevert(tokenOut); - if (disableTokenIn) tokensToDisable = _getMaskOrRevert(tokenIn); + function _executeSwapSafeApprove(address tokenIn, bytes memory callData) internal returns (bytes memory result) { _approveToken(tokenIn, type(uint256).max); result = _execute(callData); _approveToken(tokenIn, 1); diff --git a/contracts/adapters/aave/AaveV2_LendingPoolAdapter.sol b/contracts/adapters/aave/AaveV2_LendingPoolAdapter.sol deleted file mode 100644 index ebaf8620..00000000 --- a/contracts/adapters/aave/AaveV2_LendingPoolAdapter.sol +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; - -import {ILendingPool} from "../../integrations/aave/ILendingPool.sol"; -import {IAaveV2_LendingPoolAdapter} from "../../interfaces/aave/IAaveV2_LendingPoolAdapter.sol"; - -/// @title Aave V2 LendingPool adapter -/// @notice Implements logic allowing CAs to interact with Aave's lending pool -contract AaveV2_LendingPoolAdapter is AbstractAdapter, IAaveV2_LendingPoolAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.AAVE_V2_LENDING_POOL; - uint16 public constant override _gearboxAdapterVersion = 3_00; - - /// @notice Constructor - /// @param _creditManager Credit manager address - /// @param _lendingPool Lending pool address - constructor(address _creditManager, address _lendingPool) - AbstractAdapter(_creditManager, _lendingPool) // U:[AAVE2-1] - {} - - /// @dev Returns aToken address for given underlying token - function _aToken(address underlying) internal view returns (address) { - return ILendingPool(targetContract).getReserveData(underlying).aTokenAddress; - } - - // -------- // - // DEPOSITS // - // -------- // - - /// @notice Deposit underlying tokens into Aave in exchange for aTokens - /// @param asset Address of underlying token to deposit - /// @param amount Amount of underlying tokens to deposit - /// @dev Last two parameters are ignored as `onBehalfOf` can only be credit account, - /// and `referralCode` is set to zero - function deposit(address asset, uint256 amount, address, uint16) - external - override - creditFacadeOnly // U:[AAVE2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address creditAccount = _creditAccount(); // U:[AAVE2-3] - (tokensToEnable, tokensToDisable) = _deposit(creditAccount, asset, amount, false); // U:[AAVE2-3] - } - - /// @notice Deposit all underlying tokens except a specified amount into Aave in exchange for aTokens - /// @param asset Address of underlying token to deposit - /// @param leftoverAmount Amount of asset to leave at the end of operation - function depositDiff(address asset, uint256 leftoverAmount) - external - override - creditFacadeOnly // U:[AAVE2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address creditAccount = _creditAccount(); // U:[AAVE2-4] - - uint256 amount = IERC20(asset).balanceOf(creditAccount); // U:[AAVE2-4] - if (amount <= leftoverAmount) return (0, 0); - unchecked { - amount -= leftoverAmount; // U:[AAVE2-4] - } - - (tokensToEnable, tokensToDisable) = _deposit(creditAccount, asset, amount, leftoverAmount <= 1); // U:[AAVE2-4] - } - - /// @dev Internal implementation of all deposit functions - /// - using `_executeSwap` because need to check if tokens are recognized by the system - /// - underlying is approved before the call because lending pool needs permission to transfer it - /// - aToken is enabled after the call - /// - underlying is only disabled when depositing the entire balance - function _deposit(address creditAccount, address asset, uint256 amount, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - asset, - _aToken(asset), - abi.encodeCall(ILendingPool.deposit, (asset, amount, creditAccount, 0)), - disableTokenIn - ); // U:[AAVE2-3,4] - } - - // ----------- // - // WITHDRAWALS // - // ----------- // - - /// @notice Withdraw underlying tokens from Aave and burn aTokens - /// @param asset Address of underlying token to deposit - /// @param amount Amount of underlying tokens to withdraw - /// If `type(uint256).max`, will withdraw the full amount - /// @dev Last parameter is ignored because underlying recepient can only be credit account - function withdraw(address asset, uint256 amount, address) - external - override - creditFacadeOnly // U:[AAVE2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address creditAccount = _creditAccount(); // U:[AAVE2-5A,5B] - if (amount == type(uint256).max) { - (tokensToEnable, tokensToDisable) = _withdrawDiff(creditAccount, asset, 1); // U:[AAVE2-5B] - } else { - (tokensToEnable, tokensToDisable) = _withdraw(creditAccount, asset, amount); // U:[AAVE2-5A] - } - } - - /// @notice Burn all aTokens except the specified amount and convert to underlying - /// @param asset Address of underlying token to withdraw - /// @param leftoverAmount Amount of asset to leave after the operation - function withdrawDiff(address asset, uint256 leftoverAmount) - external - override - creditFacadeOnly // U:[AAVE2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address creditAccount = _creditAccount(); // U:[AAVE2-6] - (tokensToEnable, tokensToDisable) = _withdrawDiff(creditAccount, asset, leftoverAmount); // U:[AAVE2-6] - } - - /// @dev Internal implementation of `withdraw` functionality - /// - using `_executeSwap` because need to check if tokens are recognized by the system - /// - aToken is not approved before the call because lending pool doesn't need permission to burn it - /// - underlying is enabled after the call - /// - aToken is not disabled because operation doesn't spend the entire balance - function _withdraw(address creditAccount, address asset, uint256 amount) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable,) = - _executeSwapNoApprove(_aToken(asset), asset, _encodeWithdraw(creditAccount, asset, amount), false); // U:[AAVE2-5A] - } - - /// @dev Internal implementation of `withdrawDiff` functionality - /// - using `_executeSwap` because need to check if tokens are recognized by the system - /// - aToken is not approved before the call because lending pool doesn't need permission to burn it - /// - underlying is enabled after the call - /// - aToken is disabled if the leftover is 0 or 1 - function _withdrawDiff(address creditAccount, address asset, uint256 leftoverAmount) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address aToken = _aToken(asset); - uint256 amount = IERC20(aToken).balanceOf(creditAccount); // U:[AAVE2-5B,6] - if (amount <= leftoverAmount) return (0, 0); - unchecked { - amount -= leftoverAmount; // U:[AAVE2-5B,6] - } - - (tokensToEnable, tokensToDisable,) = - _executeSwapNoApprove(aToken, asset, _encodeWithdraw(creditAccount, asset, amount), leftoverAmount <= 1); // U:[AAVE2-5B,6] - } - - /// @dev Returns calldata for `ILendingPool.withdraw` call - function _encodeWithdraw(address creditAccount, address asset, uint256 amount) - internal - pure - returns (bytes memory callData) - { - callData = abi.encodeCall(ILendingPool.withdraw, (asset, amount, creditAccount)); - } -} diff --git a/contracts/adapters/aave/AaveV2_WrappedATokenAdapter.sol b/contracts/adapters/aave/AaveV2_WrappedATokenAdapter.sol deleted file mode 100644 index 11e3ec3f..00000000 --- a/contracts/adapters/aave/AaveV2_WrappedATokenAdapter.sol +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; - -import {WrappedAToken} from "../../helpers/aave/AaveV2_WrappedAToken.sol"; -import {IAaveV2_WrappedATokenAdapter} from "../../interfaces/aave/IAaveV2_WrappedATokenAdapter.sol"; - -/// @title Aave V2 Wrapped aToken adapter -/// @notice Implements logic allowing CAs to convert between waTokens, aTokens and underlying tokens -contract AaveV2_WrappedATokenAdapter is AbstractAdapter, IAaveV2_WrappedATokenAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.AAVE_V2_WRAPPED_ATOKEN; - uint16 public constant override _gearboxAdapterVersion = 3_00; - - /// @notice Underlying aToken - address public immutable override aToken; - - /// @notice Underlying token - address public immutable override underlying; - - /// @notice Collateral token mask of waToken in the credit manager - uint256 public immutable override waTokenMask; - - /// @notice Collateral token mask of aToken in the credit manager - uint256 public immutable override aTokenMask; - - /// @notice Collateral token mask of underlying token in the credit manager - uint256 public immutable override tokenMask; - - /// @notice Constructor - /// @param _creditManager Credit manager address - /// @param _waToken Wrapped aToken address - constructor(address _creditManager, address _waToken) - AbstractAdapter(_creditManager, _waToken) // U:[AAVE2W-1] - { - waTokenMask = _getMaskOrRevert(targetContract); // U:[AAVE2W-1] - - aToken = WrappedAToken(targetContract).aToken(); // U:[AAVE2W-1] - aTokenMask = _getMaskOrRevert(aToken); // U:[AAVE2W-1] - - underlying = WrappedAToken(targetContract).underlying(); // U:[AAVE2W-1] - tokenMask = _getMaskOrRevert(underlying); // U:[AAVE2W-1] - } - - // -------- // - // DEPOSITS // - // -------- // - - /// @notice Deposit given amount of aTokens - /// @param assets Amount of aTokens to deposit in exchange for waTokens - function deposit(uint256 assets) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _deposit(assets, false); // U:[AAVE2W-3] - } - - /// @notice Deposit all aTokens except the specified amount - /// @param leftoverAssets Amount of aTokens to leave after the operation - function depositDiff(uint256 leftoverAssets) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _depositDiff(false, leftoverAssets); // U:[AAVE2W-4] - } - - /// @notice Deposit given amount underlying tokens - /// @param assets Amount of underlying tokens to deposit in exchange for waTokens - function depositUnderlying(uint256 assets) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _deposit(assets, true); // U:[AAVE2W-5] - } - - /// @notice Deposit all underlying tokens except the specified amount - /// @param leftoverAssets Amount of underlying to leave after the operation - function depositDiffUnderlying(uint256 leftoverAssets) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _depositDiff(true, leftoverAssets); // U:[AAVE2W-6] - } - - /// @dev Internal implementation of `deposit` and `depositUnderlying` - /// - underlying / aAoken is approved because waToken contract needs permission to transfer it - /// - waToken is enabled after the call - /// - underlying / aToken is not disabled after the call because operation doesn't spend the entire balance - function _deposit(uint256 assets, bool fromUnderlying) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address tokenIn = fromUnderlying ? underlying : aToken; - - _approveToken(tokenIn, type(uint256).max); // U:[AAVE2W-3,5] - _execute(_encodeDeposit(assets, fromUnderlying)); // U:[AAVE2W-3,5] - _approveToken(tokenIn, 1); // U:[AAVE2W-3,5] - (tokensToEnable, tokensToDisable) = (waTokenMask, 0); // U:[AAVE2W-3,5] - } - - /// @dev Internal implementation of `depositDiff` and `depositDiffUnderlying` - /// - underlying / aAoken is approved because wrapped aToken contract needs permission to transfer it - /// - waToken is enabled after the call - /// - underlying / aToken is disabled after the call if the leftover amount is 0 or 1 - function _depositDiff(bool fromUnderlying, uint256 leftoverAmount) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address creditAccount = _creditAccount(); // U:[AAVE2W-4,6] - address tokenIn = fromUnderlying ? underlying : aToken; - - uint256 assets = IERC20(tokenIn).balanceOf(creditAccount); // U:[AAVE2W-4,6] - if (assets <= leftoverAmount) return (0, 0); - unchecked { - assets -= leftoverAmount; // U:[AAVE2W-4,6] - } - - _approveToken(tokenIn, type(uint256).max); // U:[AAVE2W-4,6] - _execute(_encodeDeposit(assets, fromUnderlying)); // U:[AAVE2W-4,6] - _approveToken(tokenIn, 1); // U:[AAVE2W-4,6] - (tokensToEnable, tokensToDisable) = - (waTokenMask, leftoverAmount > 1 ? 0 : fromUnderlying ? tokenMask : aTokenMask); // U:[AAVE2W-4,6] - } - - /// @dev Returns data for `WrappedAToken`'s `deposit` or `depositUnderlying` call - function _encodeDeposit(uint256 assets, bool fromUnderlying) internal pure returns (bytes memory callData) { - callData = fromUnderlying - ? abi.encodeCall(WrappedAToken.depositUnderlying, (assets)) - : abi.encodeCall(WrappedAToken.deposit, (assets)); - } - - // ----------- // - // WITHDRAWALS // - // ----------- // - - /// @notice Withdraw given amount of waTokens for aTokens - /// @param shares Amount of waTokens to burn in exchange for aTokens - function withdraw(uint256 shares) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _withdraw(shares, false); // U:[AAVE2W-7] - } - - /// @notice Withdraw all waTokens to aTokens except the specified amount - function withdrawDiff(uint256 leftoverShares) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _withdrawDiff(false, leftoverShares); // U:[AAVE2W-8] - } - - /// @notice Withdraw given amount of waTokens for underlying tokens - /// @param shares Amount of waTokens to burn in exchange for underlying tokens - function withdrawUnderlying(uint256 shares) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _withdraw(shares, true); // U:[AAVE2W-9] - } - - /// @notice Withdraw all waTokens to underlying tokens except the specified amount - function withdrawDiffUnderlying(uint256 leftoverShares) - external - override - creditFacadeOnly // U:[AAVE2W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _withdrawDiff(true, leftoverShares); // U:[AAVE2W-10] - } - - /// @dev Internal implementation of `withdraw` and `withdrawUnderlying` - /// - waToken is not approved because it doesn't need permission to burn share tokens - /// - underlying / aToken is enabled after the call - /// - waToken is not disabled after the call because operation doesn't spend the entire balance - function _withdraw(uint256 shares, bool toUnderlying) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _execute(_encodeWithdraw(shares, toUnderlying)); // U:[AAVE2W-7,9] - (tokensToEnable, tokensToDisable) = (toUnderlying ? tokenMask : aTokenMask, 0); // U:[AAVE2W-7,9] - } - - /// @dev Internal implementation of `withdrawDiff` and `withdrawDiffUnderlying` - /// - waToken is not approved because it doesn't need permission to burn share tokens - /// - underlying / aToken is enabled after the call - /// - waToken is disabled after the call if the leftover amount is 0 or 1 - function _withdrawDiff(bool toUnderlying, uint256 leftoverAmount) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - address creditAccount = _creditAccount(); // U:[AAVE2W-8,10] - - uint256 shares = IERC20(targetContract).balanceOf(creditAccount); // U:[AAVE2W-8,10] - if (shares <= leftoverAmount) return (0, 0); - unchecked { - shares -= leftoverAmount; // U:[AAVE2W-8,10] - } - - _execute(_encodeWithdraw(shares, toUnderlying)); // U:[AAVE2W-8,10] - (tokensToEnable, tokensToDisable) = - (toUnderlying ? tokenMask : aTokenMask, leftoverAmount <= 1 ? waTokenMask : 0); // U:[AAVE2W-8,10] - } - - /// @dev Returns data for `WrappedAToken`'s `withdraw` or `withdrawUnderlying` call - function _encodeWithdraw(uint256 shares, bool toUnderlying) internal pure returns (bytes memory callData) { - callData = toUnderlying - ? abi.encodeCall(WrappedAToken.withdrawUnderlying, (shares)) - : abi.encodeCall(WrappedAToken.withdraw, (shares)); - } -} diff --git a/contracts/adapters/balancer/BalancerV2VaultAdapter.sol b/contracts/adapters/balancer/BalancerV2VaultAdapter.sol index 2c425c8d..d97100d5 100644 --- a/contracts/adapters/balancer/BalancerV2VaultAdapter.sol +++ b/contracts/adapters/balancer/BalancerV2VaultAdapter.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {BitMask} from "@gearbox-protocol/core-v3/contracts/libraries/BitMask.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IAsset} from "../../integrations/balancer/IAsset.sol"; import { @@ -28,14 +28,18 @@ import { /// @title Balancer V2 Vault adapter /// @notice Implements logic allowing CAs to swap through and LP in Balancer vaults contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { + using EnumerableSet for EnumerableSet.Bytes32Set; using BitMask for uint256; - AdapterType public constant override _gearboxAdapterType = AdapterType.BALANCER_VAULT; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::BALANCER_VAULT"; + uint256 public constant override version = 3_10; /// @notice Mapping from poolId to status of the pool: whether it is not supported, fully supported or swap-only mapping(bytes32 => PoolStatus) public override poolStatus; + /// @dev Set of pool ids with "ALLOW" and "SWAP_ONLY" status + EnumerableSet.Bytes32Set internal _supportedPoolIds; + /// @notice Constructor /// @param _creditManager Credit manager address /// @param _vault Balancer vault address @@ -64,26 +68,24 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - if (poolStatus[singleSwap.poolId] == PoolStatus.NOT_ALLOWED) { + PoolStatus pStatus = poolStatus[singleSwap.poolId]; + if (pStatus != PoolStatus.ALLOWED && pStatus != PoolStatus.SWAP_ONLY) { revert PoolNotSupportedException(); // U:[BAL2-3] } address creditAccount = _creditAccount(); // U:[BAL2-3] address tokenIn = address(singleSwap.assetIn); - address tokenOut = address(singleSwap.assetOut); FundManagement memory fundManagement = _getDefaultFundManagement(creditAccount); // U:[BAL2-3] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - tokenIn, - tokenOut, - abi.encodeCall(IBalancerV2Vault.swap, (singleSwap, fundManagement, limit, deadline)), - false + _executeSwapSafeApprove( + tokenIn, abi.encodeCall(IBalancerV2Vault.swap, (singleSwap, fundManagement, limit, deadline)) ); // U:[BAL2-3] + + return true; } /// @notice Swaps the entire balance of a token for another token within a single pool, except the specified amount @@ -100,16 +102,17 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - address creditAccount = _creditAccount(); // U:[BAL2-4] - - if (poolStatus[singleSwapDiff.poolId] == PoolStatus.NOT_ALLOWED) { + PoolStatus pStatus = poolStatus[singleSwapDiff.poolId]; + if (pStatus != PoolStatus.ALLOWED && pStatus != PoolStatus.SWAP_ONLY) { revert PoolNotSupportedException(); // U:[BAL2-4] } + address creditAccount = _creditAccount(); // U:[BAL2-4] + uint256 amount = IERC20(address(singleSwapDiff.assetIn)).balanceOf(creditAccount); // U:[BAL2-4] - if (amount <= singleSwapDiff.leftoverAmount) return (0, 0); + if (amount <= singleSwapDiff.leftoverAmount) return false; unchecked { amount -= singleSwapDiff.leftoverAmount; // U:[BAL2-4] @@ -118,9 +121,8 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { FundManagement memory fundManagement = _getDefaultFundManagement(creditAccount); // U:[BAL2-4] // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( address(singleSwapDiff.assetIn), - address(singleSwapDiff.assetOut), abi.encodeCall( IBalancerV2Vault.swap, ( @@ -136,9 +138,10 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { (amount * limitRateRAY) / RAY, deadline ) - ), - singleSwapDiff.leftoverAmount <= 1 + ) ); // U:[BAL2-4] + + return true; } /// @notice Performs a multi-hop swap through several Balancer pools @@ -167,13 +170,12 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - unchecked { - for (uint256 i; i < swaps.length; ++i) { - if (poolStatus[swaps[i].poolId] == PoolStatus.NOT_ALLOWED) { - revert PoolNotSupportedException(); // U:[BAL2-5] - } + for (uint256 i; i < swaps.length; ++i) { + PoolStatus pStatus = poolStatus[swaps[i].poolId]; + if (pStatus != PoolStatus.ALLOWED && pStatus != PoolStatus.SWAP_ONLY) { + revert PoolNotSupportedException(); // U:[BAL2-5] } } @@ -183,16 +185,11 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { _approveAssets(assets, limits, type(uint256).max); // U:[BAL2-5] - int256[] memory assetDeltas = abi.decode( - _execute( - abi.encodeCall(IBalancerV2Vault.batchSwap, (kind, swaps, assets, fundManagement, limits, deadline)) - ), - (int256[]) - ); // U:[BAL2-5] + _execute(abi.encodeCall(IBalancerV2Vault.batchSwap, (kind, swaps, assets, fundManagement, limits, deadline))); // U:[BAL2-5] _approveAssets(assets, limits, 1); // U:[BAL2-5] - (tokensToEnable, tokensToDisable) = (_getTokensToEnable(assets, assetDeltas), 0); // U:[BAL2-5] + return true; } // --------- // @@ -214,7 +211,7 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { if (poolStatus[poolId] != PoolStatus.ALLOWED) { revert PoolNotSupportedException(); // U:[BAL2-6] @@ -222,14 +219,12 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { address creditAccount = _creditAccount(); // U:[BAL2-6] - (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); - request.fromInternalBalance = false; // U:[BAL2-6] _approveAssets(request.assets, request.maxAmountsIn, type(uint256).max); // U:[BAL2-6] _execute(abi.encodeCall(IBalancerV2Vault.joinPool, (poolId, creditAccount, creditAccount, request))); // U:[BAL2-6] _approveAssets(request.assets, request.maxAmountsIn, 1); // U:[BAL2-6] - (tokensToEnable, tokensToDisable) = (_getMaskOrRevert(bpt), 0); // U:[BAL2-6] + return true; } /// @notice Deposits single asset as liquidity into a Balancer pool @@ -242,7 +237,7 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { if (poolStatus[poolId] != PoolStatus.ALLOWED) { revert PoolNotSupportedException(); // U:[BAL2-7] @@ -250,23 +245,19 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { address creditAccount = _creditAccount(); // U:[BAL2-7] - (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); - - // calling `_executeSwap` because we need to check if BPT is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( address(assetIn), - bpt, abi.encodeCall( IBalancerV2Vault.joinPool, ( poolId, creditAccount, creditAccount, - _getJoinSingleAssetRequest(poolId, assetIn, amountIn, minAmountOut, bpt) + _getJoinSingleAssetRequest(poolId, assetIn, amountIn, minAmountOut) ) - ), - false + ) ); // U:[BAL2-7] + return true; } /// @notice Deposits the entire balance of given asset, except a specified amount, as liquidity into a Balancer pool @@ -279,44 +270,39 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - address creditAccount = _creditAccount(); // U:[BAL2-8] - if (poolStatus[poolId] != PoolStatus.ALLOWED) { revert PoolNotSupportedException(); // U:[BAL2-8] } + address creditAccount = _creditAccount(); // U:[BAL2-8] + uint256 amount = IERC20(address(assetIn)).balanceOf(creditAccount); // U:[BAL2-8] - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; // U:[BAL2-8] } - (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); - uint256 amountOutMin = (amount * minRateRAY) / RAY; // U:[BAL2-8] - JoinPoolRequest memory request = _getJoinSingleAssetRequest(poolId, assetIn, amount, amountOutMin, bpt); // U:[BAL2-8] + JoinPoolRequest memory request = _getJoinSingleAssetRequest(poolId, assetIn, amount, amountOutMin); // U:[BAL2-8] - // calling `_executeSwap` because we need to check if BPT is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - address(assetIn), - bpt, - abi.encodeCall(IBalancerV2Vault.joinPool, (poolId, creditAccount, creditAccount, request)), - leftoverAmount <= 1 + _executeSwapSafeApprove( + address(assetIn), abi.encodeCall(IBalancerV2Vault.joinPool, (poolId, creditAccount, creditAccount, request)) ); // U:[BAL2-8] + + return true; } /// @dev Internal function that builds a `JoinPoolRequest` struct for one-sided deposits - function _getJoinSingleAssetRequest( - bytes32 poolId, - IAsset assetIn, - uint256 amountIn, - uint256 minAmountOut, - address bpt - ) internal view returns (JoinPoolRequest memory request) { + function _getJoinSingleAssetRequest(bytes32 poolId, IAsset assetIn, uint256 amountIn, uint256 minAmountOut) + internal + view + returns (JoinPoolRequest memory request) + { (IERC20[] memory tokens,,) = IBalancerV2Vault(targetContract).getPoolTokens(poolId); + (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); uint256 len = tokens.length; @@ -324,17 +310,15 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { request.maxAmountsIn = new uint256[](tokens.length); uint256 bptIndex = tokens.length; - unchecked { - for (uint256 i; i < len; ++i) { - request.assets[i] = IAsset(address(tokens[i])); + for (uint256 i; i < len; ++i) { + request.assets[i] = IAsset(address(tokens[i])); - if (request.assets[i] == assetIn) { - request.maxAmountsIn[i] = amountIn; // U:[BAL2-7,8] - } + if (request.assets[i] == assetIn) { + request.maxAmountsIn[i] = amountIn; // U:[BAL2-7,8] + } - if (address(request.assets[i]) == bpt) { - bptIndex = i; - } + if (address(request.assets[i]) == bpt) { + bptIndex = i; } } @@ -359,19 +343,18 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - address creditAccount = _creditAccount(); // U:[BAL2-9] + if (poolStatus[poolId] == PoolStatus.NOT_ALLOWED) { + revert PoolNotSupportedException(); // U:[BAL2-9] + } - (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); + address creditAccount = _creditAccount(); // U:[BAL2-9] request.toInternalBalance = false; // U:[BAL2-9] _execute(abi.encodeCall(IBalancerV2Vault.exitPool, (poolId, creditAccount, payable(creditAccount), request))); // U:[BAL2-9] - - _getMaskOrRevert(bpt); // U:[BAL2-9] - (tokensToEnable, tokensToDisable) = - (_getTokensToEnable(request.assets, _getBalancesFilter(creditAccount, request.assets)), 0); // U:[BAL2-9] + return true; } /// @notice Withdraws liquidity from a Balancer pool, burning BPT and receiving a single asset @@ -383,16 +366,17 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (poolStatus[poolId] == PoolStatus.NOT_ALLOWED) { + revert PoolNotSupportedException(); // U:[BAL2-10] + } + address creditAccount = _creditAccount(); // U:[BAL2-10] (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); - // calling `_executeSwap` because we need to check if asset is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapNoApprove( - bpt, - address(assetOut), + _execute( abi.encodeCall( IBalancerV2Vault.exitPool, ( @@ -401,9 +385,9 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { payable(creditAccount), _getExitSingleAssetRequest(poolId, assetOut, amountIn, minAmountOut, bpt) ) - ), - false + ) ); // U:[BAL2-10] + return true; } /// @notice Withdraws all liquidity from a Balancer pool except the specified amount, burning BPT and receiving a single asset @@ -415,14 +399,18 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { external override creditFacadeOnly // U:[BAL2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (poolStatus[poolId] == PoolStatus.NOT_ALLOWED) { + revert PoolNotSupportedException(); // U:[BAL2-11] + } + address creditAccount = _creditAccount(); // U:[BAL2-11] (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); uint256 amount = IERC20(bpt).balanceOf(creditAccount); // U:[BAL2-11] - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; // U:[BAL2-11] @@ -431,13 +419,8 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { uint256 amountOutMin = (amount * minRateRAY) / RAY; // U:[BAL2-11] ExitPoolRequest memory request = _getExitSingleAssetRequest(poolId, assetOut, amount, amountOutMin, bpt); // U:[BAL2-11] - // calling `_executeSwap` because we need to check if asset is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapNoApprove( - bpt, - address(assetOut), - abi.encodeCall(IBalancerV2Vault.exitPool, (poolId, creditAccount, payable(creditAccount), request)), - leftoverAmount <= 1 - ); // U:[BAL2-11] + _execute(abi.encodeCall(IBalancerV2Vault.exitPool, (poolId, creditAccount, payable(creditAccount), request))); // U:[BAL2-11] + return true; } /// @dev Internal function that builds an `ExitPoolRequest` struct for one-sided withdrawals @@ -457,18 +440,16 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { uint256 tokenIndex = tokens.length; uint256 bptIndex = tokens.length; - unchecked { - for (uint256 i; i < len; ++i) { - request.assets[i] = IAsset(address(tokens[i])); + for (uint256 i; i < len; ++i) { + request.assets[i] = IAsset(address(tokens[i])); - if (request.assets[i] == assetOut) { - request.minAmountsOut[i] = minAmountOut; // U:[BAL2-10,11] - tokenIndex = i; - } + if (request.assets[i] == assetOut) { + request.minAmountsOut[i] = minAmountOut; // U:[BAL2-10,11] + tokenIndex = i; + } - if (address(request.assets[i]) == bpt) { - bptIndex = i; - } + if (address(request.assets[i]) == bpt) { + bptIndex = i; } } @@ -477,6 +458,27 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { request.userData = abi.encode(uint256(0), amountIn, tokenIndex); } + // ---- // + // DATA // + // ---- // + + /// @notice Returns the set of all supported pool IDs + function supportedPoolIds() public view returns (bytes32[] memory poolIds) { + return _supportedPoolIds.values(); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + bytes32[] memory supportedIDs = supportedPoolIds(); + PoolStatus[] memory supportedPoolStatus = new PoolStatus[](supportedIDs.length); + + for (uint256 i = 0; i < supportedIDs.length; ++i) { + supportedPoolStatus[i] = poolStatus[supportedIDs[i]]; + } + + serializedData = abi.encode(creditManager, targetContract, supportedIDs, supportedPoolStatus); + } + // ------- // // HELPERS // // ------- // @@ -485,54 +487,16 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { function _approveAssets(IAsset[] memory assets, int256[] memory filter, uint256 amount) internal { uint256 len = assets.length; - unchecked { - for (uint256 i; i < len; ++i) { - if (filter[i] > 1) _approveToken(address(assets[i]), amount); - } + for (uint256 i; i < len; ++i) { + if (filter[i] > 1) _approveToken(address(assets[i]), amount); } } /// @dev Internal function that changes approval for a batch of assets in the vault (overloading) function _approveAssets(IAsset[] memory assets, uint256[] memory filter, uint256 amount) internal { uint256 len = assets.length; - - unchecked { - for (uint256 i = 0; i < len; ++i) { - if (filter[i] > 1) _approveToken(address(assets[i]), amount); - } - } - } - - /// @dev Returns mask of all tokens that should be enabled, based on balances / balance changes - function _getTokensToEnable(IAsset[] memory assets, int256[] memory filter) - internal - view - returns (uint256 tokensToEnable) - { - uint256 len = assets.length; - - unchecked { - for (uint256 i; i < len; ++i) { - if (filter[i] < -1) tokensToEnable = tokensToEnable.enable(_getMaskOrRevert(address(assets[i]))); - } - } - } - - /// @dev Internal function that creates a filter based on CA token balances - function _getBalancesFilter(address creditAccount, IAsset[] memory assets) - internal - view - returns (int256[] memory filter) - { - uint256 len = assets.length; - - filter = new int256[](len); - - for (uint256 i = 0; i < len;) { - filter[i] = -int256(IERC20(address(assets[i])).balanceOf(creditAccount)); - unchecked { - ++i; - } + for (uint256 i = 0; i < len; ++i) { + if (filter[i] > 1) _approveToken(address(assets[i]), amount); } } @@ -554,20 +518,16 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { return array; } - len = len - 1; + len--; res = new uint256[](len); - for (uint256 i = 0; i < len;) { + for (uint256 i = 0; i < len; ++i) { if (i < index) { res[i] = array[i]; } else { res[i] = array[i + 1]; } - - unchecked { - ++i; - } } } @@ -582,8 +542,32 @@ contract BalancerV2VaultAdapter is AbstractAdapter, IBalancerV2VaultAdapter { configuratorOnly // U:[BAL2-12] { if (poolStatus[poolId] != newStatus) { + if ( + newStatus == PoolStatus.ALLOWED || newStatus == PoolStatus.SWAP_ONLY + || newStatus == PoolStatus.WITHDRAWAL_ONLY + ) { + _verifyPoolAssets(poolId); + _supportedPoolIds.add(poolId); + } else { + _supportedPoolIds.remove(poolId); + } + poolStatus[poolId] = newStatus; // U:[BAL2-12] emit SetPoolStatus(poolId, newStatus); // U:[BAL2-12] } } + + /// @dev Verifies that assets in the pool are valid collaterals before adding the pool to supported list + function _verifyPoolAssets(bytes32 poolId) internal view { + (IERC20[] memory tokens,,) = IBalancerV2Vault(targetContract).getPoolTokens(poolId); + (address bpt,) = IBalancerV2Vault(targetContract).getPool(poolId); + + uint256 len = tokens.length; + + for (uint256 i = 0; i < len; ++i) { + if (address(tokens[i]) != bpt) _getMaskOrRevert(address(tokens[i])); + } + + _getMaskOrRevert(bpt); + } } diff --git a/contracts/adapters/balancer/BalancerV3RouterAdapter.sol b/contracts/adapters/balancer/BalancerV3RouterAdapter.sol index fde9f2ce..a59c344a 100644 --- a/contracts/adapters/balancer/BalancerV3RouterAdapter.sol +++ b/contracts/adapters/balancer/BalancerV3RouterAdapter.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IBalancerV3Router} from "../../integrations/balancer/IBalancerV3Router.sol"; import {IBalancerV3Pool} from "../../integrations/balancer/IBalancerV3Pool.sol"; @@ -19,8 +19,8 @@ import {IBalancerV3RouterAdapter} from "../../interfaces/balancer/IBalancerV3Rou contract BalancerV3RouterAdapter is AbstractAdapter, IBalancerV3RouterAdapter { using EnumerableSet for EnumerableSet.AddressSet; - AdapterType public constant override _gearboxAdapterType = AdapterType.BALANCER_V3_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::BALANCER_V3_ROUTER"; + uint256 public constant override version = 3_10; /// @dev Set of all pools that are currently allowed EnumerableSet.AddressSet internal _allowedPools; @@ -47,18 +47,17 @@ contract BalancerV3RouterAdapter is AbstractAdapter, IBalancerV3RouterAdapter { uint256 deadline, bool, bytes calldata - ) external override creditFacadeOnly returns (uint256 tokensToEnable, uint256 tokensToDisable) { + ) external override creditFacadeOnly returns (bool) { if (!isPoolAllowed(pool)) revert InvalidPoolException(); - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( address(tokenIn), - address(tokenOut), abi.encodeCall( IBalancerV3Router.swapSingleTokenExactIn, (pool, tokenIn, tokenOut, exactAmountIn, minAmountOut, deadline, false, "") - ), - false + ) ); + return true; } /// @notice Swaps all balance of input token for output token through a single pool, except the specified amount @@ -75,26 +74,25 @@ contract BalancerV3RouterAdapter is AbstractAdapter, IBalancerV3RouterAdapter { uint256 leftoverAmount, uint256 rateMinRAY, uint256 deadline - ) external override creditFacadeOnly returns (uint256 tokensToEnable, uint256 tokensToDisable) { + ) external override creditFacadeOnly returns (bool) { if (!isPoolAllowed(pool)) revert InvalidPoolException(); address creditAccount = _creditAccount(); uint256 amount = tokenIn.balanceOf(creditAccount); - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; } - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( address(tokenIn), - address(tokenOut), abi.encodeCall( IBalancerV3Router.swapSingleTokenExactIn, (pool, tokenIn, tokenOut, amount, (amount * rateMinRAY) / RAY, deadline, false, "") - ), - leftoverAmount <= 1 + ) ); + return true; } // ------------- // @@ -107,7 +105,7 @@ contract BalancerV3RouterAdapter is AbstractAdapter, IBalancerV3RouterAdapter { } /// @notice Returns the list of all pools that were ever allowed in this adapter - function getAllowedPools() external view override returns (address[] memory pools) { + function getAllowedPools() public view override returns (address[] memory pools) { return _allowedPools.values(); } @@ -126,6 +124,14 @@ contract BalancerV3RouterAdapter is AbstractAdapter, IBalancerV3RouterAdapter { address pool = pools[i]; bool status = statuses[i]; + if (status) { + // Verify that all tokens in the pool are valid collaterals + IERC20[] memory tokens = IBalancerV3Pool(pool).getTokens(); + for (uint256 j; j < tokens.length; ++j) { + _getMaskOrRevert(address(tokens[j])); + } + } + if (status) { _allowedPools.add(pool); } else { @@ -135,4 +141,13 @@ contract BalancerV3RouterAdapter is AbstractAdapter, IBalancerV3RouterAdapter { } } } + + // ---- // + // DATA // + // ---- // + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, getAllowedPools()); + } } diff --git a/contracts/adapters/camelot/CamelotV3Adapter.sol b/contracts/adapters/camelot/CamelotV3Adapter.sol index 5db2c83d..c658ef07 100644 --- a/contracts/adapters/camelot/CamelotV3Adapter.sol +++ b/contracts/adapters/camelot/CamelotV3Adapter.sol @@ -1,26 +1,27 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {ICamelotV3Router} from "../../integrations/camelot/ICamelotV3Router.sol"; import {BytesLib} from "../../integrations/uniswap/BytesLib.sol"; -import {ICamelotV3Adapter, CamelotV3PoolStatus} from "../../interfaces/camelot/ICamelotV3Adapter.sol"; +import {ICamelotV3Adapter, CamelotV3PoolStatus, CamelotV3Pool} from "../../interfaces/camelot/ICamelotV3Adapter.sol"; /// @title Camelot V3 Router adapter /// @notice Implements logic allowing CAs to perform swaps via Camelot V3 contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { + using EnumerableSet for EnumerableSet.Bytes32Set; using BytesLib for bytes; - AdapterType public constant override _gearboxAdapterType = AdapterType.CAMELOT_V3_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::CAMELOT_V3_ROUTER"; + uint256 public constant override version = 3_10; /// @dev The length of the bytes encoded address uint256 private constant ADDR_SIZE = 20; @@ -37,8 +38,11 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { /// @dev The length of the path with 3 hops uint256 private constant PATH_4_LENGTH = 4 * ADDR_SIZE; - /// @dev Mapping from (token0, token1) to whether the pool can be traded through the adapter - mapping(address => mapping(address => bool)) internal _poolStatus; + /// @dev Mapping from hash(token0, token1) to respective tuple + mapping(bytes32 => CamelotV3Pool) internal _hashToPool; + + /// @dev Set of hashes of (token0, token1) for all supported pools + EnumerableSet.Bytes32Set internal _supportedPoolHashes; /// @notice Constructor /// @param _creditManager Credit manager address @@ -52,9 +56,10 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _exactInputSingleInternal(params, false); // U: [CAMV3-3] + _exactInputSingleInternal(params, false); // U: [CAMV3-3] + return true; } /// @notice Swaps given amount of input token for output token through a single pool, supporting fee on transfer tokens @@ -64,16 +69,18 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _exactInputSingleInternal(params, true); // U: [CAMV3-3A] + _exactInputSingleInternal(params, true); // U: [CAMV3-3A] + return true; } /// @dev Internal logic for `exactInputSingle` and `exactInputSingleSupportingFeeOnTransferTokens` function _exactInputSingleInternal(ICamelotV3Router.ExactInputSingleParams calldata params, bool isFeeOnTransfer) internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) { + if (!isPoolAllowed(params.tokenIn, params.tokenOut)) revert InvalidPathException(); + address creditAccount = _creditAccount(); ICamelotV3Router.ExactInputSingleParams memory paramsUpdate = params; @@ -83,8 +90,7 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { ? abi.encodeCall(ICamelotV3Router.exactInputSingleSupportingFeeOnTransferTokens, (paramsUpdate)) : abi.encodeCall(ICamelotV3Router.exactInputSingle, (paramsUpdate)); - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove(params.tokenIn, params.tokenOut, callData, false); + _executeSwapSafeApprove(params.tokenIn, callData); } /// @notice Swaps all balance of input token for output token through a single pool, except the specified amount @@ -93,9 +99,9 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _exactDiffInputSingleInternal(params, false); // U: [CAMV3-4] + return _exactDiffInputSingleInternal(params, false); // U: [CAMV3-4] } /// @notice Swaps all balance of input token for output token through a single pool, except the specified amount @@ -104,20 +110,22 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _exactDiffInputSingleInternal(params, true); // U: [CAMV3-4A] + return _exactDiffInputSingleInternal(params, true); // U: [CAMV3-4A] } /// @dev Internal logic for `exactDiffInputSingle` and `exactDiffInputSingleSupportingFeeOnTransferTokens` function _exactDiffInputSingleInternal(ExactDiffInputSingleParams calldata params, bool isFeeOnTransfer) internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (!isPoolAllowed(params.tokenIn, params.tokenOut)) revert InvalidPathException(); + address creditAccount = _creditAccount(); uint256 amount = IERC20(params.tokenIn).balanceOf(creditAccount); - if (amount <= params.leftoverAmount) return (0, 0); + if (amount <= params.leftoverAmount) return false; unchecked { amount -= params.leftoverAmount; } @@ -136,9 +144,8 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { ? abi.encodeCall(ICamelotV3Router.exactInputSingleSupportingFeeOnTransferTokens, (paramsUpdate)) : abi.encodeCall(ICamelotV3Router.exactInputSingle, (paramsUpdate)); - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = - _executeSwapSafeApprove(params.tokenIn, params.tokenOut, callData, params.leftoverAmount <= 1); + _executeSwapSafeApprove(params.tokenIn, callData); + return true; } /// @notice Swaps given amount of input token for output token through multiple pools @@ -149,20 +156,18 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); - (bool valid, address tokenIn, address tokenOut) = _validatePath(params.path); + (bool valid, address tokenIn,) = _validatePath(params.path); if (!valid) revert InvalidPathException(); ICamelotV3Router.ExactInputParams memory paramsUpdate = params; paramsUpdate.recipient = creditAccount; - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - tokenIn, tokenOut, abi.encodeCall(ICamelotV3Router.exactInput, (paramsUpdate)), false - ); // U: [CAMV3-5] + _executeSwapSafeApprove(tokenIn, abi.encodeCall(ICamelotV3Router.exactInput, (paramsUpdate))); // U: [CAMV3-5] + return true; } /// @notice Swaps all balance of input token for output token through multiple pools, except the specified amount @@ -172,15 +177,15 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); - (bool valid, address tokenIn, address tokenOut) = _validatePath(params.path); + (bool valid, address tokenIn,) = _validatePath(params.path); if (!valid) revert InvalidPathException(); uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); - if (amount <= params.leftoverAmount) return (0, 0); + if (amount <= params.leftoverAmount) return false; unchecked { amount -= params.leftoverAmount; @@ -193,10 +198,8 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { amountOutMinimum: (amount * params.rateMinRAY) / RAY }); - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - tokenIn, tokenOut, abi.encodeCall(ICamelotV3Router.exactInput, (paramsUpdate)), params.leftoverAmount <= 1 - ); // U: [CAMV3-6] + _executeSwapSafeApprove(tokenIn, abi.encodeCall(ICamelotV3Router.exactInput, (paramsUpdate))); // U: [CAMV3-6] + return true; } /// @notice Swaps input token for given amount of output token through a single pool @@ -206,17 +209,16 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (!isPoolAllowed(params.tokenIn, params.tokenOut)) revert InvalidPathException(); address creditAccount = _creditAccount(); ICamelotV3Router.ExactOutputSingleParams memory paramsUpdate = params; paramsUpdate.recipient = creditAccount; - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - params.tokenIn, params.tokenOut, abi.encodeCall(ICamelotV3Router.exactOutputSingle, (paramsUpdate)), false - ); // U: [CAMV3-7] + _executeSwapSafeApprove(params.tokenIn, abi.encodeCall(ICamelotV3Router.exactOutputSingle, (paramsUpdate))); // U: [CAMV3-7] + return true; } /// @notice Swaps input token for given amount of output token through multiple pools @@ -227,20 +229,40 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { external override creditFacadeOnly // U: [CAMV3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); - (bool valid, address tokenOut, address tokenIn) = _validatePath(params.path); + (bool valid,, address tokenIn) = _validatePath(params.path); if (!valid) revert InvalidPathException(); ICamelotV3Router.ExactOutputParams memory paramsUpdate = params; paramsUpdate.recipient = creditAccount; - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - tokenIn, tokenOut, abi.encodeCall(ICamelotV3Router.exactOutput, (paramsUpdate)), false - ); // U: [CAMV3-8] + _executeSwapSafeApprove(tokenIn, abi.encodeCall(ICamelotV3Router.exactOutput, (paramsUpdate))); // U: [CAMV3-8] + return true; + } + + // ---- // + // DATA // + // ---- // + + function supportedPools() public view returns (CamelotV3Pool[] memory pools) { + bytes32[] memory poolHashes = _supportedPoolHashes.values(); + uint256 len = poolHashes.length; + + pools = new CamelotV3Pool[](len); + + for (uint256 i = 0; i < len; ++i) { + pools[i] = _hashToPool[poolHashes[i]]; + } + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + CamelotV3Pool[] memory pools = supportedPools(); + + serializedData = abi.encode(creditManager, targetContract, pools); } // ------------- // @@ -250,19 +272,31 @@ contract CamelotV3Adapter is AbstractAdapter, ICamelotV3Adapter { /// @notice Returns whether the (token0, token1, fee) pool is allowed to be traded through the adapter function isPoolAllowed(address token0, address token1) public view override returns (bool) { (token0, token1) = _sortTokens(token0, token1); - return _poolStatus[token0][token1]; + return _supportedPoolHashes.contains(keccak256(abi.encode(token0, token1))); } /// @notice Sets status for a batch of pools /// @param pools Array of `CamelotV3PoolStatus` objects function setPoolStatusBatch(CamelotV3PoolStatus[] calldata pools) external override configuratorOnly { uint256 len = pools.length; - unchecked { - for (uint256 i; i < len; ++i) { - (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); - _poolStatus[token0][token1] = pools[i].allowed; // U: [CAMV3-9] - emit SetPoolStatus(token0, token1, pools[i].allowed); // U: [CAMV3-9] + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); + + bytes32 poolHash = keccak256(abi.encode(token0, token1)); + if (pools[i].allowed) { + /// For each added pool, we verify that the pool tokens are valid collaterals, + /// as otherwise operations with unsupported tokens would be possible, leading + /// to possibility of control flow capture + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + + _supportedPoolHashes.add(poolHash); + _hashToPool[poolHash] = CamelotV3Pool({token0: token0, token1: token1}); + } else { + _supportedPoolHashes.remove(poolHash); + delete _hashToPool[poolHash]; } + emit SetPoolStatus(token0, token1, pools[i].allowed); // U: [CAMV3-9] } } diff --git a/contracts/adapters/compound/CompoundV2_CErc20Adapter.sol b/contracts/adapters/compound/CompoundV2_CErc20Adapter.sol deleted file mode 100644 index 3848c9d1..00000000 --- a/contracts/adapters/compound/CompoundV2_CErc20Adapter.sol +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; - -import {CompoundV2_CTokenAdapter} from "./CompoundV2_CTokenAdapter.sol"; -import {ICErc20} from "../../integrations/compound/ICErc20.sol"; -import {ICompoundV2_CTokenAdapter} from "../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; - -/// @title Compound V2 CErc20 adapter -contract CompoundV2_CErc20Adapter is CompoundV2_CTokenAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.COMPOUND_V2_CERC20; - uint16 public constant override _gearboxAdapterVersion = 3_00; - - /// @notice cToken's underlying token - address public immutable override underlying; - - /// @notice Collateral token mask of underlying token in the credit manager - uint256 public immutable override tokenMask; - - /// @notice Collateral token mask of cToken in the credit manager - uint256 public immutable override cTokenMask; - - /// @notice Constructor - /// @param _creditManager Credit manager address - /// @param _cToken CErc20 token address - constructor(address _creditManager, address _cToken) - CompoundV2_CTokenAdapter(_creditManager, _cToken) // U:[COMP2T-1] - { - underlying = ICErc20(targetContract).underlying(); // U:[COMP2T-1] - - cTokenMask = _getMaskOrRevert(targetContract); // U:[COMP2T-1] - tokenMask = _getMaskOrRevert(underlying); // U:[COMP2T-1] - } - - /// @notice cToken that this adapter is connected to - function cToken() external view override returns (address) { - return targetContract; // U:[COMP2T-1] - } - - /// @dev Internal implementation of `mint` - /// - underlying is approved before the call because cToken needs permission to transfer it - /// - cToken is enabled after the call - /// - underlying is not disabled after the call because operation doesn't spend the entire balance - function _mint(uint256 amount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - _approveToken(underlying, type(uint256).max); // U:[COMP2T-4] - error = abi.decode(_execute(_encodeMint(amount)), (uint256)); // U:[COMP2T-4] - _approveToken(underlying, 1); // U:[COMP2T-4] - (tokensToEnable, tokensToDisable) = (cTokenMask, 0); - } - - /// @dev Internal implementation of `mintDiff` - /// - underlying is approved before the call because cToken needs permission to transfer it - /// - cToken is enabled after the call - /// - underlying is disabled after the call if leftoverAmount <= 1 - function _mintDiff(uint256 leftoverAmount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - address creditAccount = _creditAccount(); // U:[COMP2T-5] - - uint256 amount = IERC20(underlying).balanceOf(creditAccount); // U:[COMP2T-5] - if (amount <= leftoverAmount) return (0, 0, 0); - unchecked { - amount -= leftoverAmount; // U:[COMP2T-5] - } - - _approveToken(underlying, type(uint256).max); // U:[COMP2T-5] - error = abi.decode(_execute(_encodeMint(amount)), (uint256)); // U:[COMP2T-5] - _approveToken(underlying, 1); // U:[COMP2T-5] - (tokensToEnable, tokensToDisable) = (cTokenMask, leftoverAmount <= 1 ? tokenMask : 0); - } - - /// @dev Internal implementation of `redeem` - /// - cToken is not approved before the call because cToken doesn't need permission to burn it - /// - underlying is enabled after the call - /// - cToken is not disabled after the call because operation doesn't spend the entire balance - function _redeem(uint256 amount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - error = abi.decode(_execute(_encodeRedeem(amount)), (uint256)); // U:[COMP2T-6] - (tokensToEnable, tokensToDisable) = (tokenMask, 0); - } - - /// @dev Internal implementation of `redeemDiff` - /// - cToken is not approved before the call because cToken doesn't need permission to burn it - /// - underlying is enabled after the call - /// - cToken is disabled after the call if leftoverAmount <= 1 - function _redeemDiff(uint256 leftoverAmount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - address creditAccount = _creditAccount(); // U:[COMP2T-7] - - uint256 amount = ICErc20(targetContract).balanceOf(creditAccount); // U:[COMP2T-7] - if (amount <= leftoverAmount) return (0, 0, 0); - unchecked { - amount -= leftoverAmount; // U:[COMP2T-7] - } - - error = abi.decode(_execute(_encodeRedeem(amount)), (uint256)); // U:[COMP2T-7] - (tokensToEnable, tokensToDisable) = (tokenMask, leftoverAmount <= 1 ? cTokenMask : 0); - } - - /// @dev Internal implementation of `redeemUnderlying` - /// - cToken is not approved before the call because cToken doesn't need permission to burn it - /// - underlying is enabled after the call - /// - cToken is not disabled after the call because operation doesn't spend the entire balance - function _redeemUnderlying(uint256 amount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - error = abi.decode(_execute(_encodeRedeemUnderlying(amount)), (uint256)); // U:[COMP2T-8] - (tokensToEnable, tokensToDisable) = (tokenMask, 0); - } -} diff --git a/contracts/adapters/compound/CompoundV2_CEtherAdapter.sol b/contracts/adapters/compound/CompoundV2_CEtherAdapter.sol deleted file mode 100644 index d2ef5d73..00000000 --- a/contracts/adapters/compound/CompoundV2_CEtherAdapter.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; - -import {CEtherGateway} from "../../helpers/compound/CompoundV2_CEtherGateway.sol"; -import {CompoundV2_CTokenAdapter} from "./CompoundV2_CTokenAdapter.sol"; -import {ICEther} from "../../integrations/compound/ICEther.sol"; -import {ICompoundV2_CTokenAdapter} from "../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; - -/// @title Compound V2 CEther adapter -contract CompoundV2_CEtherAdapter is CompoundV2_CTokenAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.COMPOUND_V2_CETHER; - uint16 public constant override _gearboxAdapterVersion = 3_00; - - /// @notice cETH token address - address public immutable override cToken; - - /// @notice WETH token address - address public immutable override underlying; - - /// @notice Collateral token mask of WETH in the credit manager - uint256 public immutable override tokenMask; - - /// @notice Collateral token mask of cETH in the credit manager - uint256 public immutable override cTokenMask; - - /// @notice Constructor - /// @param _creditManager Credit manager address - /// @param _cethGateway CEther gateway contract address - constructor(address _creditManager, address _cethGateway) - CompoundV2_CTokenAdapter(_creditManager, _cethGateway) // U:[COMP2E-1] - { - cToken = CEtherGateway(payable(targetContract)).ceth(); // U:[COMP2E-1] - underlying = CEtherGateway(payable(targetContract)).weth(); // U:[COMP2E-1] - - cTokenMask = _getMaskOrRevert(cToken); // U:[COMP2E-1] - tokenMask = _getMaskOrRevert(underlying); // U:[COMP2E-1] - } - - /// @dev Internal implementation of `mint` - /// - WETH is approved before the call because Gateway needs permission to transfer it - /// - cETH is enabled after the call - /// - WETH is not disabled after the call because operation doesn't spend the entire balance - function _mint(uint256 amount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - _approveToken(underlying, type(uint256).max); // U:[COMP2E-4] - error = abi.decode(_execute(_encodeMint(amount)), (uint256)); // U:[COMP2E-4] - _approveToken(underlying, 1); // U:[COMP2E-4] - (tokensToEnable, tokensToDisable) = (cTokenMask, 0); - } - - /// @dev Internal implementation of `mintDiff` - /// - WETH is approved before the call because Gateway needs permission to transfer it - /// - cETH is enabled after the call - /// - WETH is disabled after the call if leftoverAmount <= 1 - function _mintDiff(uint256 leftoverAmount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - address creditAccount = _creditAccount(); // U:[COMP2E-5] - - uint256 amount = IERC20(underlying).balanceOf(creditAccount); // U:[COMP2E-5] - if (amount <= leftoverAmount) return (0, 0, 0); - unchecked { - amount -= leftoverAmount; // U:[COMP2E-5] - } - - _approveToken(underlying, type(uint256).max); // U:[COMP2E-5] - error = abi.decode(_execute(_encodeMint(amount)), (uint256)); // U:[COMP2E-5] - _approveToken(underlying, 1); // U:[COMP2E-5] - (tokensToEnable, tokensToDisable) = (cTokenMask, leftoverAmount <= 1 ? tokenMask : 0); - } - - /// @dev Internal implementation of `redeem` - /// - cETH is approved before the call because Gateway needs permission to transfer it - /// - WETH is enabled after the call - /// - cETH is not disabled after the call because operation doesn't spend the entire balance - function _redeem(uint256 amount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - _approveToken(cToken, type(uint256).max); // U:[COMP2E-6] - error = abi.decode(_execute(_encodeRedeem(amount)), (uint256)); // U:[COMP2E-6] - _approveToken(cToken, 1); // U:[COMP2E-6] - (tokensToEnable, tokensToDisable) = (tokenMask, 0); - } - - /// @dev Internal implementation of `redeemDiff` - /// - cETH is approved before the call because Gateway needs permission to transfer it - /// - WETH is enabled after the call - /// - cETH is disabled after the call if leftoverAmount <= 1 - function _redeemDiff(uint256 leftoverAmount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - address creditAccount = _creditAccount(); // U:[COMP2E-7] - - uint256 amount = ICEther(cToken).balanceOf(creditAccount); // U:[COMP2E-7] - if (amount <= leftoverAmount) return (0, 0, 0); - unchecked { - amount -= leftoverAmount; // U:[COMP2E-7] - } - - _approveToken(cToken, type(uint256).max); // U:[COMP2E-7] - error = abi.decode(_execute(_encodeRedeem(amount)), (uint256)); // U:[COMP2E-7] - _approveToken(cToken, 1); // U:[COMP2E-7] - (tokensToEnable, tokensToDisable) = (tokenMask, leftoverAmount <= 1 ? cTokenMask : 0); - } - - /// @dev Internal implementation of `redeemUnderlying` - /// - cETH is approved before the call because Gateway needs permission to transfer it - /// - WETH is enabled after the call - /// - cETH is not disabled after the call because operation doesn't spend the entire balance - function _redeemUnderlying(uint256 amount) - internal - override - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error) - { - _approveToken(cToken, type(uint256).max); // U:[COMP2E-8] - error = abi.decode(_execute(_encodeRedeemUnderlying(amount)), (uint256)); // U:[COMP2E-8] - _approveToken(cToken, 1); // U:[COMP2E-8] - (tokensToEnable, tokensToDisable) = (tokenMask, 0); - } -} diff --git a/contracts/adapters/compound/CompoundV2_CTokenAdapter.sol b/contracts/adapters/compound/CompoundV2_CTokenAdapter.sol deleted file mode 100644 index 238485b7..00000000 --- a/contracts/adapters/compound/CompoundV2_CTokenAdapter.sol +++ /dev/null @@ -1,158 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AbstractAdapter} from "../AbstractAdapter.sol"; - -import {ICErc20Actions} from "../../integrations/compound/ICErc20.sol"; -import {ICompoundV2_CTokenAdapter} from "../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; - -/// @title Compound V2 cToken adapter -/// @notice Implements logic allowing CAs to interact with Compound's cTokens -/// @dev Abstract base contract for CErc20 and CEther adapters -abstract contract CompoundV2_CTokenAdapter is AbstractAdapter, ICompoundV2_CTokenAdapter { - /// @notice Constructor - /// @param _creditManager Credit manager address - /// @param _targetContract Target contract address, must implement `ICErc20Actions` - constructor(address _creditManager, address _targetContract) - AbstractAdapter(_creditManager, _targetContract) // U:[COMP2-1] - {} - - /// @dev Reverts if CToken operation produced non-zero error code - function _revertOnError(uint256 error) internal pure { - if (error != 0) revert CTokenError(error); // U:[COMP2-3] - } - - // ------- // - // MINTING // - // ------- // - - /// @notice Deposit given amount of underlying tokens into Compound in exchange for cTokens - /// @param amount Amount of underlying tokens to deposit - function mint(uint256 amount) - external - override - creditFacadeOnly // U:[COMP2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - uint256 error; - (tokensToEnable, tokensToDisable, error) = _mint(amount); // U:[COMP2-4] - _revertOnError(error); // U:[COMP2-3] - } - - /// @notice Deposit all underlying tokens into Compound in exchange for cTokens, except for specified amount - /// @param leftoverAmount Amount of underlying tokens to keep on the account - function mintDiff(uint256 leftoverAmount) - external - override - creditFacadeOnly // U:[COMP2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - uint256 error; - (tokensToEnable, tokensToDisable, error) = _mintDiff(leftoverAmount); // U:[COMP2-5] - _revertOnError(error); // U:[COMP2-3] - } - - /// @dev Internal implementation of `mint` - /// Since minting process might be different for CErc20 and CEther, - /// it's up to deriving adapters to implement this function - function _mint(uint256 amount) - internal - virtual - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error); - - /// @dev Internal implementation of `mintDiff` - /// Since minting process might be different for CErc20 and CEther, - /// it's up to deriving adapters to implement this function - function _mintDiff(uint256 leftoverAmount) - internal - virtual - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error); - - /// @dev Encodes calldata for `ICErc20Actions.mint` call - function _encodeMint(uint256 amount) internal pure returns (bytes memory callData) { - callData = abi.encodeCall(ICErc20Actions.mint, (amount)); // U:[COMP2-4,5] - } - - // --------- // - // REDEEMING // - // --------- // - - /// @notice Burn given amount of cTokens to withdraw underlying from Compound - /// @param amount Amount of cTokens to burn - function redeem(uint256 amount) - external - override - creditFacadeOnly // U:[COMP2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - uint256 error; - (tokensToEnable, tokensToDisable, error) = _redeem(amount); // U:[COMP2-6] - _revertOnError(error); // U:[COMP2-3] - } - - /// @notice Withdraw all underlying tokens from Compound, except the specified amount, and burn cTokens - /// @param leftoverAmount Amount of cToken to leave on the account - function redeemDiff(uint256 leftoverAmount) - external - override - creditFacadeOnly // U:[COMP2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - uint256 error; - (tokensToEnable, tokensToDisable, error) = _redeemDiff(leftoverAmount); // U:[COMP2-7] - _revertOnError(error); // U:[COMP2-3] - } - - /// @dev Internal implementation of `redeem` - /// Since redeeming process might be different for CErc20 and CEther, - /// it's up to deriving adapters to implement this function - function _redeem(uint256 amount) - internal - virtual - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error); - - /// @dev Internal implementation of `redeemDiff` - /// Since redeeming process might be different for CErc20 and CEther, - /// it's up to deriving adapters to implement this function - function _redeemDiff(uint256 leftoverAmount) - internal - virtual - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error); - - /// @dev Encodes calldata for `ICErc20Actions.redeem` call - function _encodeRedeem(uint256 amount) internal pure returns (bytes memory callData) { - callData = abi.encodeCall(ICErc20Actions.redeem, (amount)); // U:[COMP2-6,7] - } - - // -------------------- // - // REDEEMING UNDERLYING // - // -------------------- // - - /// @notice Burn cTokens to withdraw given amount of underlying from Compound - /// @param amount Amount of underlying to withdraw - function redeemUnderlying(uint256 amount) - external - override - creditFacadeOnly // U:[COMP2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - uint256 error; - (tokensToEnable, tokensToDisable, error) = _redeemUnderlying(amount); // U:[COMP2-8] - _revertOnError(error); // U:[COMP2-3] - } - - /// @dev Internal implementation of `redeemUnderlying` - /// Since redeeming process might be different for CErc20 and CEther, - /// it's up to deriving adapters to implement this function - function _redeemUnderlying(uint256 amount) - internal - virtual - returns (uint256 tokensToEnable, uint256 tokensToDisable, uint256 error); - - /// @dev Encodes calldata for `ICErc20Actions.redeemUnderlying` call - function _encodeRedeemUnderlying(uint256 amount) internal pure returns (bytes memory callData) { - callData = abi.encodeCall(ICErc20Actions.redeemUnderlying, (amount)); // U:[COMP2-8] - } -} diff --git a/contracts/adapters/convex/ConvexV1_BaseRewardPool.sol b/contracts/adapters/convex/ConvexV1_BaseRewardPool.sol index 4fd93517..d0cf3668 100644 --- a/contracts/adapters/convex/ConvexV1_BaseRewardPool.sol +++ b/contracts/adapters/convex/ConvexV1_BaseRewardPool.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {BitMask} from "@gearbox-protocol/core-v3/contracts/libraries/BitMask.sol"; import {IBooster} from "../../integrations/convex/IBooster.sol"; @@ -20,8 +19,8 @@ import {IConvexV1BaseRewardPoolAdapter} from "../../interfaces/convex/IConvexV1B contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPoolAdapter { using BitMask for uint256; - AdapterType public constant override _gearboxAdapterType = AdapterType.CONVEX_V1_BASE_REWARD_POOL; - uint16 public constant override _gearboxAdapterVersion = 3_01; + bytes32 public constant override contractType = "ADAPTER::CVX_V1_BASE_REWARD_POOL"; + uint256 public constant override version = 3_11; /// @notice Address of a Curve LP token deposited into the Convex pool address public immutable override curveLPtoken; @@ -44,18 +43,6 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo /// @notice Address of a reward token of the fourth extra reward pool, if any address public immutable override extraReward4; - /// @notice Collateral token mask of a Curve LP token in the credit manager - uint256 public immutable override curveLPTokenMask; - - /// @notice Collateral token mask of a Convex LP token in the credit manager - uint256 public immutable override stakingTokenMask; - - /// @notice Collateral token mask of a reward pool stake token - uint256 public immutable override stakedTokenMask; - - /// @notice Bitmask of all reward tokens of the pool (CRV, CVX, extra reward tokens, if any) in the credit manager - uint256 public immutable override rewardTokensMask; - /// @notice Constructor /// @param _creditManager Credit manager address /// @param _baseRewardPool BaseRewardPool address @@ -64,22 +51,19 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo AbstractAdapter(_creditManager, _baseRewardPool) // U:[CVX1R-1] { stakingToken = address(IBaseRewardPool(_baseRewardPool).stakingToken()); // U:[CVX1R-1] - stakingTokenMask = _getMaskOrRevert(stakingToken); // U:[CVX1R-1] + _getMaskOrRevert(stakingToken); // U:[CVX1R-1] stakedPhantomToken = _stakedPhantomToken; // U:[CVX1R-1] - stakedTokenMask = _getMaskOrRevert(stakedPhantomToken); // U:[CVX1R-1] + _getMaskOrRevert(stakedPhantomToken); // U:[CVX1R-1] address booster = IBaseRewardPool(_baseRewardPool).operator(); IBooster.PoolInfo memory poolInfo = IBooster(booster).poolInfo(IBaseRewardPool(_baseRewardPool).pid()); curveLPtoken = poolInfo.lptoken; // U:[CVX1R-1] - curveLPTokenMask = _getMaskOrRevert(curveLPtoken); // U:[CVX1R-1] - - uint256 _rewardTokensMask; + _getMaskOrRevert(curveLPtoken); // U:[CVX1R-1] address rewardToken = address(IBaseRewardPool(_baseRewardPool).rewardToken()); - _rewardTokensMask = _rewardTokensMask.enable(_getMaskOrRevert(rewardToken)); // U:[CVX1R-1] - - _rewardTokensMask = _rewardTokensMask.enable(_getSecondaryRewardMask(booster)); // U:[CVX1R-1] + _getMaskOrRevert(rewardToken); // U:[CVX1R-1] + _checkSecondaryRewardMask(booster); // U:[CVX1R-1] address _extraReward1; address _extraReward2; @@ -88,21 +72,16 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo uint256 extraRewardLength = IBaseRewardPool(_baseRewardPool).extraRewardsLength(); if (extraRewardLength >= 1) { - uint256 _extraRewardMask; - (_extraReward1, _extraRewardMask) = _getExtraReward(0); - _rewardTokensMask = _rewardTokensMask.enable(_extraRewardMask); + _extraReward1 = _getExtraReward(0); if (extraRewardLength >= 2) { - (_extraReward2, _extraRewardMask) = _getExtraReward(1); - _rewardTokensMask = _rewardTokensMask.enable(_extraRewardMask); + _extraReward2 = _getExtraReward(1); if (extraRewardLength >= 3) { - (_extraReward3, _extraRewardMask) = _getExtraReward(2); - _rewardTokensMask = _rewardTokensMask.enable(_extraRewardMask); + _extraReward3 = _getExtraReward(2); if (extraRewardLength >= 4) { - (_extraReward4, _extraRewardMask) = _getExtraReward(3); - _rewardTokensMask = _rewardTokensMask.enable(_extraRewardMask); + _extraReward4 = _getExtraReward(3); } } } @@ -110,40 +89,38 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo extraReward1 = _extraReward1; // U:[CVX1R-2] extraReward2 = _extraReward2; // U:[CVX1R-2] - extraReward3 = _extraReward3; - extraReward4 = _extraReward4; - rewardTokensMask = _rewardTokensMask; // U:[CVX1R-2] + extraReward3 = _extraReward3; // U:[CVX1R-2] + extraReward4 = _extraReward4; // U:[CVX1R-2] } - /// @dev Returns `i`-th extra reward token and its collateral mask in the credit mnager - function _getExtraReward(uint256 i) internal view returns (address extraReward, uint256 extraRewardMask) { + /// @dev Returns `i`-th extra reward token and checks that it is a valid collateral in the Credit Manager + function _getExtraReward(uint256 i) internal view returns (address extraReward) { extraReward = IRewards(IBaseRewardPool(targetContract).extraRewards(i)).rewardToken(); // `extraReward` might be a wrapper around the reward token, and there seems to be no reliable way to check it // programatically, so we assume that it's a wrapper if it's not recognized as collateral in the credit manager - try ICreditManagerV3(creditManager).getTokenMaskOrRevert(extraReward) returns (uint256 mask) { - extraRewardMask = mask; - } catch { + try ICreditManagerV3(creditManager).getTokenMaskOrRevert(extraReward) returns (uint256) {} + catch { try IExtraRewardWrapper(extraReward).token() returns (address baseToken) { extraReward = baseToken; } catch { extraReward = IExtraRewardWrapper(extraReward).baseToken(); } - extraRewardMask = _getMaskOrRevert(extraReward); + _getMaskOrRevert(extraReward); } } + /// @dev Checks that the secondary token is a valid collateral. /// @dev Aura on L2 networks can have a different contract instead of the secondary reward token /// in IBooster.minter(). If the minter is not recognized as collateral in CM, we assume that /// it is not the secondary reward and handle the situation - function _getSecondaryRewardMask(address booster) internal view returns (uint256 rewardMask) { + function _checkSecondaryRewardMask(address booster) internal view { address reward = IBooster(booster).minter(); - try ICreditManagerV3(creditManager).getTokenMaskOrRevert(reward) returns (uint256 mask) { - rewardMask = mask; - } catch { + try ICreditManagerV3(creditManager).getTokenMaskOrRevert(reward) returns (uint256) {} + catch { reward = IAuraL2Coordinator(reward).auraOFT(); - rewardMask = _getMaskOrRevert(reward); + _getMaskOrRevert(reward); } } @@ -157,9 +134,10 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _stake(msg.data, false); // U:[CVX1R-4] + _executeSwapSafeApprove(stakingToken, msg.data); // U:[CVX1R-4] + return false; } /// @notice Stakes the entire balance of Convex LP token in the reward pool, except the specified amount @@ -168,7 +146,7 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CVX1R-5] @@ -176,24 +154,17 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = - _stake(abi.encodeCall(IBaseRewardPool.stake, (balance - leftoverAmount)), leftoverAmount <= 1); // U:[CVX1R-5] + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IBaseRewardPool.stake, (balance - leftoverAmount))); // U:[CVX1R-5] } } + return false; } - /// @dev Internal implementation of `stake` and `stakeDiff` - /// - Staking token is approved because reward pool needs permission to transfer it - /// - Staked token is enabled after the call - /// - Staking token is only disabled when staking the entire balance - function _stake(bytes memory callData, bool disableStakingToken) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(stakingToken, type(uint256).max); // U:[CVX1R-4,5] - _execute(callData); // U:[CVX1R-4,5] - _approveToken(stakingToken, 1); // U:[CVX1R-4,5] - (tokensToEnable, tokensToDisable) = (stakedTokenMask, disableStakingToken ? stakingTokenMask : 0); + /// @notice Deposits into a phantom token + function depositPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IBaseRewardPool.stake, (amount))); + return false; } // ----- // @@ -205,10 +176,10 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { _execute(msg.data); // U:[CVX1R-6] - (tokensToEnable, tokensToDisable) = (rewardTokensMask, 0); // U:[CVX1R-6] + return false; } // -------- // @@ -216,15 +187,15 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo // -------- // /// @notice Withdraws Convex LP token from the reward pool - /// @param claim Whether to claim staking rewards - /// @dev `amount` parameter is ignored since calldata is passed directly to the target contract - function withdraw(uint256, bool claim) + /// @dev `amount` and `claim` parameters are ignored since calldata is passed directly to the target contract + function withdraw(uint256, bool) external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _withdraw(msg.data, claim, false); // U:[CVX1R-7] + _execute(msg.data); // U:[CVX1R-7] + return false; } /// @notice Withdraws the entire balance of Convex LP token from the reward pool, except the specified amount @@ -234,7 +205,7 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CVX1R-6] @@ -242,26 +213,23 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _withdraw( - abi.encodeCall(IBaseRewardPool.withdraw, (balance - leftoverAmount, claim)), - claim, - leftoverAmount <= 1 - ); // U:[CVX1R-6] + _execute(abi.encodeCall(IBaseRewardPool.withdraw, (balance - leftoverAmount, claim))); // U:[CVX1R-6] } } + + return false; } - /// @dev Internal implementation of `withdraw` and `withdrawDiff` - /// - Staking token is enabled after the call - /// - Staked token is only disabled when withdrawing the entire balance - /// - Rewards tokens are enabled if `claim` is true - function _withdraw(bytes memory callData, bool claim, bool disableStakedToken) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) + /// @notice Withdraws phantom token for its underlying + function withdrawPhantomToken(address token, uint256 amount) + external + override + creditFacadeOnly // U:[CVX1R-3] + returns (bool) { - _execute(callData); // U:[CVX1R-7,8] - (tokensToEnable, tokensToDisable) = - (stakingTokenMask.enable(claim ? rewardTokensMask : 0), disableStakedToken ? stakedTokenMask : 0); + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); // U:[CVX1R-11] + _execute(abi.encodeCall(IBaseRewardPool.withdraw, (amount, false))); // U:[CVX1R-11] + return false; } // ------ // @@ -269,15 +237,15 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo // ------ // /// @notice Withdraws Convex LP token from the reward pool and unwraps it into Curve LP token - /// @param claim Whether to claim staking rewards - /// @dev `amount` parameter is ignored since calldata is passed directly to the target contract - function withdrawAndUnwrap(uint256, bool claim) + /// @dev `amount` and `claim` parameters are ignored since calldata is passed directly to the target contract + function withdrawAndUnwrap(uint256, bool) external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _withdrawAndUnwrap(msg.data, claim, false); // U:[CVX1R-9] + _execute(msg.data); // U:[CVX1R-9] + return false; } /// @notice Withdraws the entire balance of Convex LP token from the reward pool, except the specified amount @@ -288,7 +256,7 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo external override creditFacadeOnly // U:[CVX1R-3] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CVX1R-10] @@ -296,25 +264,22 @@ contract ConvexV1BaseRewardPoolAdapter is AbstractAdapter, IConvexV1BaseRewardPo if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _withdrawAndUnwrap( - abi.encodeCall(IBaseRewardPool.withdrawAndUnwrap, (balance - leftoverAmount, claim)), - claim, - leftoverAmount <= 1 - ); // U:[CVX1R-10] + _execute(abi.encodeCall(IBaseRewardPool.withdrawAndUnwrap, (balance - leftoverAmount, claim))); // U:[CVX1R-10] } } + + return false; } - /// @dev Internal implementation of `withdrawAndUnwrap` and `withdrawDiffAndUnwrap` - /// - Curve LP token is enabled after the call - /// - Staked token is only disabled when withdrawing the entire balance - /// - Rewards tokens are enabled if `claim` is true - function _withdrawAndUnwrap(bytes memory callData, bool claim, bool disableStakedToken) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _execute(callData); // U:[CVX1R-9,10] - (tokensToEnable, tokensToDisable) = - (curveLPTokenMask.enable(claim ? rewardTokensMask : 0), disableStakedToken ? stakedTokenMask : 0); + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode( + creditManager, + targetContract, + curveLPtoken, + stakingToken, + stakedPhantomToken, + [extraReward1, extraReward2, extraReward3, extraReward4] + ); } } diff --git a/contracts/adapters/convex/ConvexV1_Booster.sol b/contracts/adapters/convex/ConvexV1_Booster.sol index ffa33b1c..1ebdae00 100644 --- a/contracts/adapters/convex/ConvexV1_Booster.sol +++ b/contracts/adapters/convex/ConvexV1_Booster.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {ICreditConfiguratorV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditConfiguratorV3.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {IBooster} from "../../integrations/convex/IBooster.sol"; import {IBaseRewardPool} from "../../integrations/convex/IBaseRewardPool.sol"; @@ -20,8 +20,19 @@ import {IConvexV1BaseRewardPoolAdapter} from "../../interfaces/convex/IConvexV1B /// @title Convex V1 Booster adapter interface /// @notice Implements logic allowing CAs to interact with Convex Booster contract ConvexV1BoosterAdapter is AbstractAdapter, IConvexV1BoosterAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.CONVEX_V1_BOOSTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + using EnumerableSet for EnumerableSet.UintSet; + + bytes32 public constant override contractType = "ADAPTER::CVX_V1_BOOSTER"; + uint256 public constant override version = 3_10; + + /// @dev Set of all pids that have corresponding phantom tokens + EnumerableSet.UintSet internal _supportedPids; + + /// @notice Maps pool ID to Curve token being deposited + mapping(uint256 => address) public override pidToCurveToken; + + /// @notice Maps pool ID to pool's Convex staking token + mapping(uint256 => address) public override pidToConvexToken; /// @notice Maps pool ID to phantom token representing staked position mapping(uint256 => address) public override pidToPhantomToken; @@ -33,21 +44,31 @@ contract ConvexV1BoosterAdapter is AbstractAdapter, IConvexV1BoosterAdapter { AbstractAdapter(_creditManager, _booster) // U:[CVX1B-1] {} + /// @dev Reverts if the passed pid is not recognized by the adapter + modifier supportedPidsOnly(uint256 pid) { + // Checking for a supported pid is required both during deposits and withdrawals, + // as adding pools to Convex is permissionless and not sanitizing the pid would + // allow users to potentially run arbitrary code mid-execution + if (!_supportedPids.contains(pid)) revert UnsupportedPidException(); + _; + } + // ------- // // DEPOSIT // // ------- // /// @notice Deposits Curve LP tokens into Booster /// @param _pid ID of the pool to deposit to - /// @param _stake Whether to stake Convex LP tokens in the rewards pool - /// @dev `_amount` parameter is ignored since calldata is passed directly to the target contract - function deposit(uint256 _pid, uint256, bool _stake) + /// @dev `_amount` and `_stake` parameters are ignored since calldata is passed directly to the target contract + function deposit(uint256 _pid, uint256, bool) external override creditFacadeOnly // U:[CVX1B-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + supportedPidsOnly(_pid) // U:[CVX1B-2A] + returns (bool) { - (tokensToEnable, tokensToDisable) = _deposit(_pid, _stake, msg.data, false); // U:[CVX1B-3] + _executeSwapSafeApprove(pidToCurveToken[_pid], msg.data); // U:[CVX1B-3] + return false; } /// @notice Deposits the entire balance of Curve LP tokens into Booster, except the specified amount @@ -58,44 +79,24 @@ contract ConvexV1BoosterAdapter is AbstractAdapter, IConvexV1BoosterAdapter { external override creditFacadeOnly // U:[CVX1B-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + supportedPidsOnly(_pid) // U:[CVX1B-2A] + returns (bool) { address creditAccount = _creditAccount(); // U:[CVX1B-4] - IBooster.PoolInfo memory pool = IBooster(targetContract).poolInfo(_pid); - - address tokenIn = pool.lptoken; // U:[CVX1B-4] - address tokenOut = _stake ? pidToPhantomToken[_pid] : pool.token; // U:[CVX1B-4] + address tokenIn = pidToCurveToken[_pid]; // U:[CVX1B-4] uint256 balance = IERC20(tokenIn).balanceOf(creditAccount); // U:[CVX1B-4] if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - tokenIn, - tokenOut, - abi.encodeCall(IBooster.deposit, (_pid, balance - leftoverAmount, _stake)), - leftoverAmount <= 1 + _executeSwapSafeApprove( + tokenIn, abi.encodeCall(IBooster.deposit, (_pid, balance - leftoverAmount, _stake)) ); // U:[CVX1B-4] } } - } - - /// @dev Internal implementation of `deposit` and `depositDiff` - /// - Curve LP token is approved before the call - /// - Convex LP token (or staked phantom token, if `_stake` is true) is enabled after the call - /// - Curve LP token is only disabled when depositing the entire balance - function _deposit(uint256 _pid, bool _stake, bytes memory callData, bool disableCurveLP) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - IBooster.PoolInfo memory pool = IBooster(targetContract).poolInfo(_pid); - address tokenIn = pool.lptoken; // U:[CVX1B-3,4] - address tokenOut = _stake ? pidToPhantomToken[_pid] : pool.token; // U:[CVX1B-3,4] - - // using `_executeSwap` because tokens are not known in advance and need to check if they are registered - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove(tokenIn, tokenOut, callData, disableCurveLP); // U:[CVX1B-3,4] + return false; } // -------- // @@ -109,9 +110,11 @@ contract ConvexV1BoosterAdapter is AbstractAdapter, IConvexV1BoosterAdapter { external override creditFacadeOnly // U:[CVX1B-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + supportedPidsOnly(_pid) // U:[CVX1B-2A] + returns (bool) { - (tokensToEnable, tokensToDisable) = _withdraw(_pid, msg.data, false); // U:[CVX1B-5] + _execute(msg.data); // U:[CVX1B-5] + return false; } /// @notice Withdraws all Curve LP tokens from Booster, except the specified amount @@ -121,51 +124,57 @@ contract ConvexV1BoosterAdapter is AbstractAdapter, IConvexV1BoosterAdapter { external override creditFacadeOnly // U:[CVX1B-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + supportedPidsOnly(_pid) // U:[CVX1B-2A] + returns (bool) { address creditAccount = _creditAccount(); // U:[CVX1B-6] - IBooster.PoolInfo memory pool = IBooster(targetContract).poolInfo(_pid); - - address tokenIn = pool.token; // U:[CVX1B-6] - address tokenOut = pool.lptoken; // U:[CVX1B-6] + address tokenIn = pidToConvexToken[_pid]; // U:[CVX1B-6] uint256 balance = IERC20(tokenIn).balanceOf(creditAccount); // U:[CVX1B-6] if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable,) = _executeSwapNoApprove( - tokenIn, - tokenOut, - abi.encodeCall(IBooster.withdraw, (_pid, balance - leftoverAmount)), - leftoverAmount <= 1 - ); // U:[CVX1B-6] + _execute(abi.encodeCall(IBooster.withdraw, (_pid, balance - leftoverAmount))); // U:[CVX1B-6] } } + + return false; } - /// @dev Internal implementation of `withdraw` and `withdrawDiff` - /// - Curve LP token is enabled after the call - /// - Convex LP token is only disabled when withdrawing the entire stake - function _withdraw(uint256 _pid, bytes memory callData, bool disableConvexLP) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - IBooster.PoolInfo memory pool = IBooster(targetContract).poolInfo(_pid); + // ---- // + // DATA // + // ---- // + + function getSupportedPids() public view returns (uint256[] memory) { + return _supportedPids.values(); + } - address tokenIn = pool.token; // U:[CVX1B-5,6] - address tokenOut = pool.lptoken; // U:[CVX1B-5,6] + struct Pool { + uint256 pid; + address curveToken; + address convexToken; + address phantomToken; + } - // using `_executeSwap` because tokens are not known in advance and need to check if they are registered - (tokensToEnable, tokensToDisable,) = _executeSwapNoApprove(tokenIn, tokenOut, callData, disableConvexLP); // U:[CVX1B-5,6] + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + uint256[] memory supportedPids = getSupportedPids(); + uint256 len = supportedPids.length; + Pool[] memory supportedPools = new Pool[](len); + for (uint256 i = 0; i < len; ++i) { + uint256 pid = supportedPids[i]; + supportedPools[i] = Pool(pid, pidToCurveToken[pid], pidToConvexToken[pid], pidToPhantomToken[pid]); + } + serializedData = abi.encode(creditManager, targetContract, supportedPools); } // ------------- // // CONFIGURATION // // ------------- // - /// @notice Updates the mapping of pool IDs to phantom staked token addresses - function updateStakedPhantomTokensMap() + /// @notice Updates the set of supported pids and related token mappings + function updateSupportedPids() external override configuratorOnly // U:[CVX1B-7] @@ -175,21 +184,25 @@ contract ConvexV1BoosterAdapter is AbstractAdapter, IConvexV1BoosterAdapter { address[] memory allowedAdapters = cc.allowedAdapters(); uint256 len = allowedAdapters.length; - unchecked { - for (uint256 i = 0; i < len; ++i) { - address adapter = allowedAdapters[i]; - address poolTargetContract = IAdapter(adapter).targetContract(); - AdapterType aType = IAdapter(adapter)._gearboxAdapterType(); - - if ( - aType == AdapterType.CONVEX_V1_BASE_REWARD_POOL - && IBaseRewardPool(poolTargetContract).operator() == targetContract - ) { - uint256 pid = IBaseRewardPool(poolTargetContract).pid(); - address phantomToken = IConvexV1BaseRewardPoolAdapter(adapter).stakedPhantomToken(); - pidToPhantomToken[pid] = phantomToken; - emit SetPidToPhantomToken(pid, phantomToken); - } + for (uint256 i = 0; i < len; ++i) { + address adapter = allowedAdapters[i]; + address poolTargetContract = IAdapter(adapter).targetContract(); + + if ( + IAdapter(adapter).contractType() == "ADAPTER::CVX_V1_BASE_REWARD_POOL" + && IBaseRewardPool(poolTargetContract).operator() == targetContract + ) { + uint256 pid = IBaseRewardPool(poolTargetContract).pid(); + address phantomToken = IConvexV1BaseRewardPoolAdapter(adapter).stakedPhantomToken(); + + /// No sanity checks on pool-related tokens (Curve token, Convex token, phantom token) being collateral + /// need to be performed, as they were already done while deploying the pool adapter itself + + pidToPhantomToken[pid] = phantomToken; + pidToCurveToken[pid] = IConvexV1BaseRewardPoolAdapter(adapter).curveLPtoken(); + pidToConvexToken[pid] = IConvexV1BaseRewardPoolAdapter(adapter).stakingToken(); + + if (_supportedPids.add(pid)) emit AddSupportedPid(pid); } } } diff --git a/contracts/adapters/curve/CurveV1_2.sol b/contracts/adapters/curve/CurveV1_2.sol index 2325b084..640a1f85 100644 --- a/contracts/adapters/curve/CurveV1_2.sol +++ b/contracts/adapters/curve/CurveV1_2.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ICurvePool2Assets, N_COINS} from "../../integrations/curve/ICurvePool_2.sol"; import {ICurveV1_2AssetsAdapter} from "../../interfaces/curve/ICurveV1_2AssetsAdapter.sol"; @@ -13,8 +10,8 @@ import {CurveV1AdapterBase} from "./CurveV1_Base.sol"; /// @title Curve V1 2 assets adapter /// @notice Implements logic allowing to interact with Curve pools with 2 assets contract CurveV1Adapter2Assets is CurveV1AdapterBase, ICurveV1_2AssetsAdapter { - function _gearboxAdapterType() external pure virtual override returns (AdapterType) { - return AdapterType.CURVE_V1_2ASSETS; + function contractType() external pure virtual override returns (bytes32) { + return "ADAPTER::CURVE_V1_2ASSETS"; } /// @notice Constructor @@ -22,8 +19,10 @@ contract CurveV1Adapter2Assets is CurveV1AdapterBase, ICurveV1_2AssetsAdapter { /// @param _curvePool Target Curve pool address /// @param _lp_token Pool LP token address /// @param _metapoolBase Base pool address (for metapools only) or zero address - constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase) - CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, N_COINS) + /// @param _use256 Whether the pool uses uint256 or int128 for coin indices. Normally StableSwap pools use int128, + /// but can be uint256 in forks, e.g. PancakeSwap stable pools. + constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase, bool _use256) + CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, N_COINS, _use256) {} /// @notice Add liquidity to the pool @@ -33,9 +32,10 @@ contract CurveV1Adapter2Assets is CurveV1AdapterBase, ICurveV1_2AssetsAdapter { external override creditFacadeOnly // U:[CRV2-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _add_liquidity(amounts[0] > 1, amounts[1] > 1, false, false); // U:[CRV2-2] + _add_liquidity(amounts[0] > 1, amounts[1] > 1, false, false); // U:[CRV2-2] + return true; } /// @dev Returns calldata for adding liquidity in coin `i` @@ -71,21 +71,31 @@ contract CurveV1Adapter2Assets is CurveV1AdapterBase, ICurveV1_2AssetsAdapter { external virtual creditFacadeOnly // U:[CRV2-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity(); // U:[CRV2-3] + _execute(msg.data); // U:[CRV2-3] + return true; } /// @notice Withdraw exact amounts of tokens from the pool - /// @param amounts Amounts of tokens to withdraw - /// @dev `max_burn_amount` parameter is ignored because calldata is directly passed to the target contract - function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) + /// @dev `amounts` and `max_burn_amount` parameters are ignored because calldata is directly passed to the target contract + function remove_liquidity_imbalance(uint256[N_COINS] calldata, uint256) external virtual override creditFacadeOnly // U:[CRV2-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_imbalance(amounts[0] > 1, amounts[1] > 1, false, false); // U:[CRV2-4] + _execute(msg.data); // U:[CRV2-4] + return true; + } + + /// @notice Serialized adapter parameters + function serialize() external view virtual returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, token, lp_token, metapoolBase); + + serializedData = bytes.concat( + serializedData, abi.encode(use256, [token0, token1], [underlying0, underlying1, underlying2, underlying3]) + ); } } diff --git a/contracts/adapters/curve/CurveV1_3.sol b/contracts/adapters/curve/CurveV1_3.sol index b96153a7..a0d4e8a1 100644 --- a/contracts/adapters/curve/CurveV1_3.sol +++ b/contracts/adapters/curve/CurveV1_3.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ICurvePool3Assets, N_COINS} from "../../integrations/curve/ICurvePool_3.sol"; import {ICurveV1_3AssetsAdapter} from "../../interfaces/curve/ICurveV1_3AssetsAdapter.sol"; @@ -13,17 +10,17 @@ import {CurveV1AdapterBase} from "./CurveV1_Base.sol"; /// @title Curve V1 3 assets adapter /// @notice Implements logic allowing to interact with Curve pools with 3 assets contract CurveV1Adapter3Assets is CurveV1AdapterBase, ICurveV1_3AssetsAdapter { - function _gearboxAdapterType() external pure virtual override returns (AdapterType) { - return AdapterType.CURVE_V1_3ASSETS; - } + bytes32 public constant override contractType = "ADAPTER::CURVE_V1_3ASSETS"; /// @notice Constructor /// @param _creditManager Credit manager address /// @param _curvePool Target Curve pool address /// @param _lp_token Pool LP token address /// @param _metapoolBase Base pool address (for metapools only) or zero address - constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase) - CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, N_COINS) + /// @param _use256 Whether the pool uses uint256 or int128 for coin indices. Normally StableSwap pools use int128, + /// but can be uint256 in forks, e.g. PancakeSwap stable pools. + constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase, bool _use256) + CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, N_COINS, _use256) {} /// @notice Add liquidity to the pool @@ -33,9 +30,10 @@ contract CurveV1Adapter3Assets is CurveV1AdapterBase, ICurveV1_3AssetsAdapter { external override creditFacadeOnly // U:[CRV3-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _add_liquidity(amounts[0] > 1, amounts[1] > 1, amounts[2] > 1, false); // U:[CRV3-2] + _add_liquidity(amounts[0] > 1, amounts[1] > 1, amounts[2] > 1, false); // U:[CRV3-2] + return true; } /// @dev Returns calldata for adding liquidity in coin `i` @@ -71,22 +69,36 @@ contract CurveV1Adapter3Assets is CurveV1AdapterBase, ICurveV1_3AssetsAdapter { external virtual creditFacadeOnly // U:[CRV3-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity(); // U:[CRV3-3] + _execute(msg.data); // U:[CRV3-3] + return true; } /// @notice Withdraw exact amounts of tokens from the pool - /// @param amounts Amounts of tokens to withdraw - /// @dev `max_burn_amount` parameter is ignored because calldata is directly passed to the target contract - function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) + /// @dev `amounts` and `max_burn_amount` parameters are ignored because calldata is directly passed to the target contract + function remove_liquidity_imbalance(uint256[N_COINS] calldata, uint256) external virtual override creditFacadeOnly // U:[CRV3-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = - _remove_liquidity_imbalance(amounts[0] > 1, amounts[1] > 1, amounts[2] > 1, false); // U:[CRV3-4] + _execute(msg.data); // U:[CRV3-4] + return true; + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode( + creditManager, + targetContract, + token, + lp_token, + metapoolBase, + use256, + [token0, token1, token2], + [underlying0, underlying1, underlying2, underlying3] + ); } } diff --git a/contracts/adapters/curve/CurveV1_4.sol b/contracts/adapters/curve/CurveV1_4.sol index 33691384..17862f64 100644 --- a/contracts/adapters/curve/CurveV1_4.sol +++ b/contracts/adapters/curve/CurveV1_4.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ICurvePool4Assets, N_COINS} from "../../integrations/curve/ICurvePool_4.sol"; import {ICurveV1_4AssetsAdapter} from "../../interfaces/curve/ICurveV1_4AssetsAdapter.sol"; @@ -13,17 +10,17 @@ import {CurveV1AdapterBase} from "./CurveV1_Base.sol"; /// @title Curve V1 4 assets adapter /// @notice Implements logic allowing to interact with Curve pools with 4 assets contract CurveV1Adapter4Assets is CurveV1AdapterBase, ICurveV1_4AssetsAdapter { - function _gearboxAdapterType() external pure virtual override returns (AdapterType) { - return AdapterType.CURVE_V1_4ASSETS; - } + bytes32 public constant override contractType = "ADAPTER::CURVE_V1_4ASSETS"; /// @notice Constructor /// @param _creditManager Credit manager address /// @param _curvePool Target Curve pool address /// @param _lp_token Pool LP token address /// @param _metapoolBase Base pool address (for metapools only) or zero address - constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase) - CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, N_COINS) + /// @param _use256 Whether the pool uses uint256 or int128 for coin indices. Normally StableSwap pools use int128, + /// but can be uint256 in forks, e.g. PancakeSwap stable pools. + constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase, bool _use256) + CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, N_COINS, _use256) {} /// @notice Add liquidity to the pool @@ -33,10 +30,10 @@ contract CurveV1Adapter4Assets is CurveV1AdapterBase, ICurveV1_4AssetsAdapter { external override creditFacadeOnly // U:[CRV4-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = - _add_liquidity(amounts[0] > 1, amounts[1] > 1, amounts[2] > 1, amounts[3] > 1); // U:[CRV4-2] + _add_liquidity(amounts[0] > 1, amounts[1] > 1, amounts[2] > 1, amounts[3] > 1); // U:[CRV4-2] + return true; } /// @dev Returns calldata for adding liquidity in coin `i` @@ -72,22 +69,36 @@ contract CurveV1Adapter4Assets is CurveV1AdapterBase, ICurveV1_4AssetsAdapter { external virtual creditFacadeOnly // U:[CRV4-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity(); // U:[CRV4-3] + _execute(msg.data); // U:[CRV4-3] + return true; } /// @notice Withdraw exact amounts of tokens from the pool - /// @param amounts Amounts of tokens to withdraw - /// @dev `max_burn_amount` parameter is ignored because calldata is directly passed to the target contract - function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) + /// @dev `amounts` and `max_burn_amount` parameters are ignored because calldata is directly passed to the target contract + function remove_liquidity_imbalance(uint256[N_COINS] calldata, uint256) external virtual override creditFacadeOnly // U:[CRV4-1] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = - _remove_liquidity_imbalance(amounts[0] > 1, amounts[1] > 1, amounts[2] > 1, amounts[3] > 1); // U:[CRV4-4] + _execute(msg.data); // U:[CRV4-4] + return true; + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode( + creditManager, + targetContract, + token, + lp_token, + metapoolBase, + use256, + [token0, token1, token2, token3], + [underlying0, underlying1, underlying2, underlying3] + ); } } diff --git a/contracts/adapters/curve/CurveV1_Base.sol b/contracts/adapters/curve/CurveV1_Base.sol index 7262a01b..4664994f 100644 --- a/contracts/adapters/curve/CurveV1_Base.sol +++ b/contracts/adapters/curve/CurveV1_Base.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {BitMask} from "@gearbox-protocol/core-v3/contracts/libraries/BitMask.sol"; import {IncorrectParameterException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; @@ -19,7 +19,7 @@ import {AbstractAdapter} from "../AbstractAdapter.sol"; abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { using BitMask for uint256; - uint16 public constant override _gearboxAdapterVersion = 3_00; + uint256 public constant override version = 3_11; /// @notice Pool LP token address (added for backward compatibility) address public immutable override token; @@ -27,9 +27,6 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { /// @notice Pool LP token address address public immutable override lp_token; - /// @notice Collateral token mask of pool LP token in the credit manager - uint256 public immutable override lpTokenMask; - /// @notice Base pool address (for metapools only) address public immutable override metapoolBase; @@ -44,47 +41,42 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { address public immutable override token2; address public immutable override token3; - uint256 public immutable override token0Mask; - uint256 public immutable override token1Mask; - uint256 public immutable override token2Mask; - uint256 public immutable override token3Mask; - address public immutable override underlying0; address public immutable override underlying1; address public immutable override underlying2; address public immutable override underlying3; - uint256 public immutable override underlying0Mask; - uint256 public immutable override underlying1Mask; - uint256 public immutable override underlying2Mask; - uint256 public immutable override underlying3Mask; - /// @notice Constructor /// @param _creditManager Credit manager address /// @param _curvePool Target Curve pool address /// @param _lp_token Pool LP token address /// @param _metapoolBase Metapool's base pool address (must have 2 or 3 coins) or zero address /// @param _nCoins Number of coins in the pool - constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase, uint256 _nCoins) + /// @param _use256 Whether the pool uses uint256 or int128 for coin indices + constructor( + address _creditManager, + address _curvePool, + address _lp_token, + address _metapoolBase, + uint256 _nCoins, + bool _use256 + ) AbstractAdapter(_creditManager, _curvePool) // U:[CRVB-1] nonZeroAddress(_lp_token) // U:[CRVB-1] { - lpTokenMask = _getMaskOrRevert(_lp_token); // U:[CRVB-1] + _getMaskOrRevert(_lp_token); // U:[CRVB-1] token = _lp_token; // U:[CRVB-1] lp_token = _lp_token; // U:[CRVB-1] metapoolBase = _metapoolBase; // U:[CRVB-1] nCoins = _nCoins; // U:[CRVB-1] - use256 = _use256(); + use256 = _use256; address[4] memory tokens; - uint256[4] memory tokenMasks; - unchecked { - for (uint256 i; i < nCoins; ++i) { - tokens[i] = _getCoin(_curvePool, i); // U:[CRVB-1] - if (tokens[i] == address(0)) revert IncorrectParameterException(); // U:[CRVB-1] - tokenMasks[i] = _getMaskOrRevert(tokens[i]); // U:[CRVB-1] - } + for (uint256 i; i < nCoins; ++i) { + tokens[i] = _getCoin(_curvePool, i); // U:[CRVB-1] + if (tokens[i] == address(0)) revert IncorrectParameterException(); // U:[CRVB-1] + _getMaskOrRevert(tokens[i]); // U:[CRVB-1] } token0 = tokens[0]; @@ -92,14 +84,8 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { token2 = tokens[2]; token3 = tokens[3]; - token0Mask = tokenMasks[0]; - token1Mask = tokenMasks[1]; - token2Mask = tokenMasks[2]; - token3Mask = tokenMasks[3]; - // underlying tokens (only relevant for meta and lending pools) address[4] memory underlyings; - uint256[4] memory underlyingMasks; unchecked { for (uint256 i; i < 4; ++i) { if (_metapoolBase != address(0)) { @@ -115,7 +101,7 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { else break; } - if (underlyings[i] != address(0)) underlyingMasks[i] = _getMaskOrRevert(underlyings[i]); // U:[CRVB-1] + if (underlyings[i] != address(0)) _getMaskOrRevert(underlyings[i]); // U:[CRVB-1] } } @@ -123,11 +109,6 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { underlying1 = underlyings[1]; underlying2 = underlyings[2]; underlying3 = underlyings[3]; - - underlying0Mask = underlyingMasks[0]; - underlying1Mask = underlyingMasks[1]; - underlying2Mask = underlyingMasks[2]; - underlying3Mask = underlyingMasks[3]; } // -------- // @@ -143,9 +124,10 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - return _exchange(i, j, dx, min_dy); // U:[CRVB-3] + _exchange(i, j, dx, min_dy); // U:[CRVB-3] + return true; } /// @dev Same as the previous one but accepts coin indexes as `int128` @@ -153,17 +135,15 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - return _exchange(_toU256(i), _toU256(j), dx, min_dy); // U:[CRVB-3] + _exchange(_toU256(i), _toU256(j), dx, min_dy); // U:[CRVB-3] + return true; } /// @dev Implementation of both versions of `exchange` - function _exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _exchange_impl(i, j, _getExchangeCallData(i, j, dx, min_dy), false); // U:[CRVB-3] + function _exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) internal { + _executeSwapSafeApprove(_get_token(i), _getExchangeCallData(i, j, dx, min_dy)); // U:[CRVB-3] } /// @notice Exchanges the entire balance of one pool asset to another, except the specified amount @@ -175,35 +155,20 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CRVB-4] address tokenIn = _get_token(i); // U:[CRVB-4] uint256 dx = IERC20(tokenIn).balanceOf(creditAccount); // U:[CRVB-4] - if (dx <= leftoverAmount) return (0, 0); + if (dx <= leftoverAmount) return false; unchecked { dx -= leftoverAmount; // U:[CRVB-4] } uint256 min_dy = (dx * rateMinRAY) / RAY; // U:[CRVB-4] - (tokensToEnable, tokensToDisable) = - _exchange_impl(i, j, _getExchangeCallData(i, j, dx, min_dy), leftoverAmount <= 1); // U:[CRVB-4] - } - - /// @dev Internal implementation of `exchange` and `exchange_diff` - /// - passes calldata to the target contract - /// - sets max approval for the input token before the call and resets it to 1 after - /// - enables output asset after the call - /// - disables input asset only when exchanging the entire balance - function _exchange_impl(uint256 i, uint256 j, bytes memory callData, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(_get_token(i), type(uint256).max); // U:[CRVB-3,4] - _execute(callData); // U:[CRVB-3,4] - _approveToken(_get_token(i), 1); // U:[CRVB-3,4] - (tokensToEnable, tokensToDisable) = (_get_token_mask(j), disableTokenIn ? _get_token_mask(i) : 0); // U:[CRVB-3,4] + _executeSwapSafeApprove(tokenIn, _getExchangeCallData(i, j, dx, min_dy)); // U:[CRVB-4] + return true; } /// @dev Returns calldata for `exchange` and `exchange_diff` calls @@ -226,9 +191,10 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - return _exchange_underlying(i, j, dx, min_dy); // U:[CRVB-5] + _exchange_underlying(i, j, dx, min_dy); // U:[CRVB-5] + return true; } /// @dev Same as the previous one but accepts coin indexes as `int128` @@ -236,18 +202,15 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - return _exchange_underlying(_toU256(i), _toU256(j), dx, min_dy); // U:[CRVB-5] + _exchange_underlying(_toU256(i), _toU256(j), dx, min_dy); // U:[CRVB-5] + return true; } /// @dev Implementation of both versions of `exchange_underlying` - function _exchange_underlying(uint256 i, uint256 j, uint256 dx, uint256 min_dy) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = - _exchange_underlying_impl(i, j, _getExchangeUnderlyingCallData(i, j, dx, min_dy), false); // U:[CRVB-5] + function _exchange_underlying(uint256 i, uint256 j, uint256 dx, uint256 min_dy) internal { + _executeSwapSafeApprove(_get_underlying(i), _getExchangeUnderlyingCallData(i, j, dx, min_dy)); // U:[CRVB-5] } /// @notice Exchanges the entire balance of one pool's underlying asset to another, except the specified amount @@ -258,35 +221,20 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CRVB-6] address tokenIn = _get_underlying(i); // U:[CRVB-6] uint256 dx = IERC20(tokenIn).balanceOf(creditAccount); // U:[CRVB-6] - if (dx <= leftoverAmount) return (0, 0); + if (dx <= leftoverAmount) return false; unchecked { dx -= leftoverAmount; // U:[CRVB-6] } uint256 min_dy = (dx * rateMinRAY) / RAY; // U:[CRVB-6] - (tokensToEnable, tokensToDisable) = - _exchange_underlying_impl(i, j, _getExchangeUnderlyingCallData(i, j, dx, min_dy), leftoverAmount <= 1); // U:[CRVB-6] - } - - /// @dev Internal implementation of `exchange_underlying` and `exchange_diff_underlying` - /// - passes calldata to the target contract - /// - sets max approval for the input token before the call and resets it to 1 after - /// - enables output asset after the call - /// - disables input asset only when exchanging the entire balance - function _exchange_underlying_impl(uint256 i, uint256 j, bytes memory callData, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(_get_underlying(i), type(uint256).max); // U:[CRVB-5,6] - _execute(callData); // U:[CRVB-5,6] - _approveToken(_get_underlying(i), 1); // U:[CRVB-5,6] - (tokensToEnable, tokensToDisable) = (_get_underlying_mask(j), disableTokenIn ? _get_underlying_mask(i) : 0); // U:[CRVB-5,6] + _executeSwapSafeApprove(tokenIn, _getExchangeUnderlyingCallData(i, j, dx, min_dy)); // U:[CRVB-6] + return true; } /// @dev Returns calldata for `exchange_underlying` and `exchange_diff_underlying` calls @@ -308,14 +256,10 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { /// - passes calldata to the target contract /// - sets max approvals for the specified tokens before the call and resets them to 1 after /// - enables LP token - function _add_liquidity(bool t0Approve, bool t1Approve, bool t2Approve, bool t3Approve) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function _add_liquidity(bool t0Approve, bool t1Approve, bool t2Approve, bool t3Approve) internal { _approveTokens(t0Approve, t1Approve, t2Approve, t3Approve, type(uint256).max); // U:[CRV2-2, CRV3-2, CRV4-2] _execute(msg.data); // U:[CRV2-2, CRV3-2, CRV4-2] _approveTokens(t0Approve, t1Approve, t2Approve, t3Approve, 1); // U:[CRV2-2, CRV3-2, CRV4-2] - (tokensToEnable, tokensToDisable) = (lpTokenMask, 0); // U:[CRV2-2, CRV3-2, CRV4-2] } /// @notice Adds given amount of asset as liquidity to the pool @@ -326,10 +270,10 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = - _add_liquidity_one_coin_impl(i, _getAddLiquidityOneCoinCallData(i, amount, minAmount), false); // U:[CRVB-7] + _executeSwapSafeApprove(_get_token(i), _getAddLiquidityOneCoinCallData(i, amount, minAmount)); // U:[CRVB-7] + return true; } /// @notice Adds the entire balance of asset as liquidity to the pool, except the specified amount @@ -340,35 +284,20 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { external override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CRVB-8] address tokenIn = _get_token(i); // U:[CRVB-8] uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); // U:[CRVB-8] - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; // U:[CRVB-8] } uint256 minAmount = (amount * rateMinRAY) / RAY; // U:[CRVB-8] - (tokensToEnable, tokensToDisable) = - _add_liquidity_one_coin_impl(i, _getAddLiquidityOneCoinCallData(i, amount, minAmount), leftoverAmount <= 1); // U:[CRVB-8] - } - - /// @dev Internal implementation of `add_liquidity_one_coin' and `add_diff_liquidity_one_coin` - /// - passes calldata to the target contract - /// - sets max approval for the input token before the call and resets it to 1 after - /// - enables LP token - /// - disables input token only when adding the entire balance - function _add_liquidity_one_coin_impl(uint256 i, bytes memory callData, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(_get_token(i), type(uint256).max); // U:[CRVB-7,8] - _execute(callData); // U:[CRVB-7,8] - _approveToken(_get_token(i), 1); // U:[CRVB-7,8] - (tokensToEnable, tokensToDisable) = (lpTokenMask, disableTokenIn ? _get_token_mask(i) : 0); // U:[CRVB-7,8] + _executeSwapSafeApprove(tokenIn, _getAddLiquidityOneCoinCallData(i, amount, minAmount)); // U:[CRVB-8] + return true; } /// @notice Returns the amount of LP token received for adding a single asset to the pool @@ -405,30 +334,6 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { // REMOVE LIQUIDITY // // ---------------- // - /// @dev Internal implementation of `remove_liquidity` - /// - passes calldata to the target contract - /// - enables all pool tokens - function _remove_liquidity() internal returns (uint256 tokensToEnable, uint256 tokensToDisable) { - _execute(msg.data); // U:[CRV2-3, CRV3-3, CRV4-3] - (tokensToEnable, tokensToDisable) = (token0Mask | token1Mask | token2Mask | token3Mask, 0); // U:[CRV2-3, CRV3-3, CRV4-3] - } - - /// @dev Internal implementation of `remove_liquidity_imbalance` - /// - passes calldata to the target contract - /// - enables specified pool tokens - function _remove_liquidity_imbalance(bool t0Enable, bool t1Enable, bool t2Enable, bool t3Enable) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _execute(msg.data); // U:[CRV2-4, CRV3-4, CRV4-4] - - if (t0Enable) tokensToEnable = tokensToEnable.enable(token0Mask); // U:[CRV2-4, CRV3-4, CRV4-4] - if (t1Enable) tokensToEnable = tokensToEnable.enable(token1Mask); // U:[CRV2-4, CRV3-4, CRV4-4] - if (t2Enable) tokensToEnable = tokensToEnable.enable(token2Mask); // U:[CRV3-4, CRV4-4] - if (t3Enable) tokensToEnable = tokensToEnable.enable(token3Mask); // U:[CRV4-4] - tokensToDisable = 0; // U:[CRV2-4, CRV3-4, CRV4-4] - } - /// @notice Removes liquidity from the pool in a specified asset /// @param amount Amount of liquidity to remove /// @param i Index of the asset to withdraw @@ -438,9 +343,10 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { virtual override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin(amount, i, minAmount); // U:[CRVB-9] + _remove_liquidity_one_coin(amount, i, minAmount); // U:[CRVB-9] + return true; } /// @dev Same as the previous one but accepts coin indexes as `int128` @@ -449,18 +355,15 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { virtual override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin(amount, _toU256(i), minAmount); // U:[CRVB-9] + _remove_liquidity_one_coin(amount, _toU256(i), minAmount); // U:[CRVB-9] + return true; } /// @dev Implementation of both versions of `remove_liquidity_one_coin` - function _remove_liquidity_one_coin(uint256 amount, uint256 i, uint256 minAmount) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = - _remove_liquidity_one_coin_impl(i, _getRemoveLiquidityOneCoinCallData(i, amount, minAmount), false); // U:[CRVB-9] + function _remove_liquidity_one_coin(uint256 amount, uint256 i, uint256 minAmount) internal { + _execute(_getRemoveLiquidityOneCoinCallData(i, amount, minAmount)); } /// @notice Removes all liquidity from the pool, except the specified amount, in a specified asset @@ -472,7 +375,7 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { virtual override creditFacadeOnly // U:[CRVB-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { return _remove_diff_liquidity_one_coin(i, leftoverAmount, rateMinRAY); // U:[CRVB-10] } @@ -480,32 +383,19 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { /// @dev Implementation of `remove_diff_liquidity_one_coin` function _remove_diff_liquidity_one_coin(uint256 i, uint256 leftoverAmount, uint256 rateMinRAY) internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[CRVB-10] uint256 amount = IERC20(lp_token).balanceOf(creditAccount); // U:[CRVB-10] - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; // U:[CRVB-10] } uint256 minAmount = (amount * rateMinRAY) / RAY; // U:[CRVB-10] - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin_impl( - i, _getRemoveLiquidityOneCoinCallData(i, amount, minAmount), leftoverAmount <= 1 - ); // U:[CRVB-10] - } - - /// @dev Internal implementation of `remove_liquidity_one_coin` and `remove_diff_liquidity_one_coin` - /// - passes calldata to the targe contract - /// - enables received asset - /// - disables LP token only when removing all liquidity - function _remove_liquidity_one_coin_impl(uint256 i, bytes memory callData, bool disableLP) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _execute(callData); - (tokensToEnable, tokensToDisable) = (_get_token_mask(i), disableLP ? lpTokenMask : 0); // U:[CRVB-9,10] + _execute(_getRemoveLiquidityOneCoinCallData(i, amount, minAmount)); // U:[CRVB-10] + return true; } /// @dev Returns calldata for `remove_liquidity_one_coin` and `remove_diff_liquidity_one_coin` calls @@ -523,15 +413,6 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { // HELPERS // // ------- // - /// @dev Returns true if pool is a cryptoswap pool, which is determined by whether it implements `mid_fee` - function _use256() internal view returns (bool result) { - try ICurvePool(targetContract).mid_fee() returns (uint256) { - result = true; - } catch { - result = false; - } - } - /// @dev Returns `i`-th coin of the `pool`, tries both signatures function _getCoin(address pool, uint256 i) internal view returns (address coin) { try ICurvePool(pool).coins(i) returns (address addr) { @@ -572,22 +453,6 @@ abstract contract CurveV1AdapterBase is AbstractAdapter, ICurveV1Adapter { if (i == 3) return underlying3; } - /// @dev Returns token `i`'s mask - function _get_token_mask(uint256 i) internal view returns (uint256 mask) { - if (i == 0) return token0Mask; - if (i == 1) return token1Mask; - if (i == 2) return token2Mask; - if (i == 3) return token3Mask; - } - - /// @dev Returns underlying `i`'s mask - function _get_underlying_mask(uint256 i) internal view returns (uint256 mask) { - if (i == 0) return underlying0Mask; - if (i == 1) return underlying1Mask; - if (i == 2) return underlying2Mask; - if (i == 3) return underlying3Mask; - } - /// @dev Sets target contract's approval for specified tokens to `amount` function _approveTokens(bool t0Approve, bool t1Approve, bool t2Approve, bool t3Approve, uint256 amount) internal { if (t0Approve) _approveToken(token0, amount); diff --git a/contracts/adapters/curve/CurveV1_DepositZap.sol b/contracts/adapters/curve/CurveV1_DepositZap.sol index 4f03c350..11748612 100644 --- a/contracts/adapters/curve/CurveV1_DepositZap.sol +++ b/contracts/adapters/curve/CurveV1_DepositZap.sol @@ -1,20 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {CurveV1AdapterBase} from "./CurveV1_Base.sol"; /// @title Curve V1 DepozitZap adapter /// @notice Implements logic for interacting with a Curve zap wrapper (to `remove_liquidity_one_coin` from older pools) contract CurveV1AdapterDeposit is CurveV1AdapterBase { - AdapterType public constant override _gearboxAdapterType = AdapterType.CURVE_V1_WRAPPER; + bytes32 public constant override contractType = "ADAPTER::CURVE_V1_WRAPPER"; /// @notice Sets allowance for the pool LP token to max before the operation and to 1 after modifier withLPTokenApproval() { @@ -29,7 +27,7 @@ contract CurveV1AdapterDeposit is CurveV1AdapterBase { /// @param _lp_token Pool LP token address /// @param _nCoins Number of coins in the pool constructor(address _creditManager, address _curveDeposit, address _lp_token, uint256 _nCoins) - CurveV1AdapterBase(_creditManager, _curveDeposit, _lp_token, address(0), _nCoins) + CurveV1AdapterBase(_creditManager, _curveDeposit, _lp_token, address(0), _nCoins, false) {} /// @inheritdoc CurveV1AdapterBase @@ -40,9 +38,10 @@ contract CurveV1AdapterDeposit is CurveV1AdapterBase { override creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin(amount, i, minAmount); + _remove_liquidity_one_coin(amount, i, minAmount); + return true; } /// @inheritdoc CurveV1AdapterBase @@ -53,9 +52,10 @@ contract CurveV1AdapterDeposit is CurveV1AdapterBase { override creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin(amount, _toU256(i), minAmount); + _remove_liquidity_one_coin(amount, _toU256(i), minAmount); + return true; } /// @inheritdoc CurveV1AdapterBase @@ -66,9 +66,9 @@ contract CurveV1AdapterDeposit is CurveV1AdapterBase { override creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_diff_liquidity_one_coin(i, leftoverAmount, rateMinRAY); + return _remove_diff_liquidity_one_coin(i, leftoverAmount, rateMinRAY); } /// @dev Does nothing since this adapter should not be used to add liquidity @@ -86,4 +86,19 @@ contract CurveV1AdapterDeposit is CurveV1AdapterBase { override returns (bytes memory, bytes memory) {} + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode( + creditManager, + targetContract, + token, + lp_token, + metapoolBase, + nCoins, + use256, + [token0, token1, token2, token3], + [underlying0, underlying1, underlying2, underlying3] + ); + } } diff --git a/contracts/adapters/curve/CurveV1_StableNG.sol b/contracts/adapters/curve/CurveV1_StableNG.sol index 1f17a880..8c54a4bc 100644 --- a/contracts/adapters/curve/CurveV1_StableNG.sol +++ b/contracts/adapters/curve/CurveV1_StableNG.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ICurvePoolStableNG} from "../../integrations/curve/ICurvePool_StableNG.sol"; import {ICurveV1_StableNGAdapter} from "../../interfaces/curve/ICurveV1_StableNGAdapter.sol"; @@ -13,31 +10,32 @@ import {CurveV1AdapterBase} from "./CurveV1_Base.sol"; /// @title Curve Stable NG adapter /// @notice Implements logic allowing to interact with Curve StableNG pools contract CurveV1AdapterStableNG is CurveV1AdapterBase, ICurveV1_StableNGAdapter { - function _gearboxAdapterType() external pure virtual override returns (AdapterType) { - return AdapterType.CURVE_STABLE_NG; - } + bytes32 public constant override contractType = "ADAPTER::CURVE_STABLE_NG"; /// @notice Constructor /// @param _creditManager Credit manager address /// @param _curvePool Target Curve pool address /// @param _lp_token Pool LP token address /// @param _metapoolBase Base pool address (for metapools only) or zero address - constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase) - CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, ICurvePoolStableNG(_curvePool).N_COINS()) + /// @param _use256 Whether the pool uses uint256 or int128 for coin indices + constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase, bool _use256) + CurveV1AdapterBase( + _creditManager, + _curvePool, + _lp_token, + _metapoolBase, + ICurvePoolStableNG(_curvePool).N_COINS(), + _use256 + ) {} /// @notice Add liquidity to the pool /// @param amounts Amounts of tokens to add /// @dev `min_mint_amount` parameter is ignored because calldata is passed directly to the target contract - function add_liquidity(uint256[] calldata amounts, uint256) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function add_liquidity(uint256[] calldata amounts, uint256) external override creditFacadeOnly returns (bool) { uint256 len = amounts.length; - (tokensToEnable, tokensToDisable) = - _add_liquidity(amounts[0] > 1, amounts[1] > 1, len > 2 && amounts[2] > 1, len > 3 && amounts[3] > 1); + _add_liquidity(amounts[0] > 1, amounts[1] > 1, len > 2 && amounts[2] > 1, len > 3 && amounts[3] > 1); + return true; } /// @dev Returns calldata for adding liquidity in coin `i` @@ -69,28 +67,36 @@ contract CurveV1AdapterStableNG is CurveV1AdapterBase, ICurveV1_StableNGAdapter /// @notice Remove liquidity from the pool /// @dev '_amount' and 'min_amounts' parameters are ignored because calldata is directly passed to the target contract - function remove_liquidity(uint256, uint256[] calldata) - external - virtual - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _remove_liquidity(); + function remove_liquidity(uint256, uint256[] calldata) external virtual creditFacadeOnly returns (bool) { + _execute(msg.data); + return true; } /// @notice Withdraw exact amounts of tokens from the pool - /// @param amounts Amounts of tokens to withdraw - /// @dev `max_burn_amount` parameter is ignored because calldata is directly passed to the target contract - function remove_liquidity_imbalance(uint256[] calldata amounts, uint256) + /// @dev `amounts` and `max_burn_amount` parameters are ignored because calldata is directly passed to the target contract + function remove_liquidity_imbalance(uint256[] calldata, uint256) external virtual override creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - uint256 len = amounts.length; - (tokensToEnable, tokensToDisable) = _remove_liquidity_imbalance( - amounts[0] > 1, amounts[1] > 1, len > 2 && amounts[2] > 1, len > 3 && amounts[3] > 1 + _execute(msg.data); + return true; + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode( + creditManager, + targetContract, + token, + lp_token, + metapoolBase, + nCoins, + use256, + [token0, token1, token2, token3], + [underlying0, underlying1, underlying2, underlying3] ); } } diff --git a/contracts/adapters/curve/CurveV1_stETH.sol b/contracts/adapters/curve/CurveV1_stETH.sol index 08de7a31..10b82653 100644 --- a/contracts/adapters/curve/CurveV1_stETH.sol +++ b/contracts/adapters/curve/CurveV1_stETH.sol @@ -1,13 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {N_COINS} from "../../integrations/curve/ICurvePool_2.sol"; import {ICurveV1Adapter} from "../../interfaces/curve/ICurveV1Adapter.sol"; @@ -17,7 +15,7 @@ import {CurveV1Adapter2Assets} from "./CurveV1_2.sol"; /// @title Curve V1 stETH adapter /// @notice Same as `CurveV1Adapter2Assets` but uses stETH gateway and needs to approve LP token contract CurveV1AdapterStETH is CurveV1Adapter2Assets { - AdapterType public constant override _gearboxAdapterType = AdapterType.CURVE_V1_STECRV_POOL; + bytes32 public constant override contractType = "ADAPTER::CURVE_V1_STECRV_POOL"; /// @notice Sets allowance for the pool LP token to max before the operation and to 1 after modifier withLPTokenApproval() { @@ -31,7 +29,7 @@ contract CurveV1AdapterStETH is CurveV1Adapter2Assets { /// @param _curveStETHPoolGateway steCRV pool gateway address /// @param _lp_token steCRV LP token address constructor(address _creditManager, address _curveStETHPoolGateway, address _lp_token) - CurveV1Adapter2Assets(_creditManager, _curveStETHPoolGateway, _lp_token, address(0)) + CurveV1Adapter2Assets(_creditManager, _curveStETHPoolGateway, _lp_token, address(0), false) {} /// @inheritdoc CurveV1Adapter2Assets @@ -41,21 +39,23 @@ contract CurveV1AdapterStETH is CurveV1Adapter2Assets { override creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity(); + _execute(msg.data); + return true; } /// @inheritdoc CurveV1Adapter2Assets /// @dev Unlike other adapters, approves the LP token to the target - function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) + function remove_liquidity_imbalance(uint256[N_COINS] calldata, uint256) external override creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_imbalance(amounts[0] > 1, amounts[1] > 1, false, false); + _execute(msg.data); + return true; } /// @inheritdoc CurveV1AdapterBase @@ -65,9 +65,10 @@ contract CurveV1AdapterStETH is CurveV1Adapter2Assets { override(CurveV1AdapterBase, ICurveV1Adapter) creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin(amount, i, minAmount); + _remove_liquidity_one_coin(amount, i, minAmount); + return true; } /// @inheritdoc CurveV1AdapterBase @@ -77,9 +78,10 @@ contract CurveV1AdapterStETH is CurveV1Adapter2Assets { override(CurveV1AdapterBase, ICurveV1Adapter) creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_liquidity_one_coin(amount, _toU256(i), minAmount); + _remove_liquidity_one_coin(amount, _toU256(i), minAmount); + return true; } /// @inheritdoc CurveV1AdapterBase @@ -89,8 +91,14 @@ contract CurveV1AdapterStETH is CurveV1Adapter2Assets { override(CurveV1AdapterBase, ICurveV1Adapter) creditFacadeOnly withLPTokenApproval - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _remove_diff_liquidity_one_coin(i, leftoverAmount, rateMinRAY); + return _remove_diff_liquidity_one_coin(i, leftoverAmount, rateMinRAY); + } + + /// @notice Serialized adapter parameters + function serialize() external view override returns (bytes memory serializedData) { + serializedData = + abi.encode(creditManager, targetContract, token, lp_token, metapoolBase, nCoins, use256, [token0, token1]); } } diff --git a/contracts/adapters/equalizer/EqualizerRouterAdapter.sol b/contracts/adapters/equalizer/EqualizerRouterAdapter.sol index 95e14995..82b83399 100644 --- a/contracts/adapters/equalizer/EqualizerRouterAdapter.sol +++ b/contracts/adapters/equalizer/EqualizerRouterAdapter.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IEqualizerRouter, Route} from "../../integrations/equalizer/IEqualizerRouter.sol"; import { @@ -23,11 +22,8 @@ import { contract EqualizerRouterAdapter is AbstractAdapter, IEqualizerRouterAdapter { using EnumerableSet for EnumerableSet.Bytes32Set; - AdapterType public constant override _gearboxAdapterType = AdapterType.EQUALIZER_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; - - /// @dev Mapping from hash(token0, token1, stable) to whether the pool can be traded through the adapter - mapping(address => mapping(address => mapping(bool => bool))) internal _poolStatus; + bytes32 public constant override contractType = "ADAPTER::EQUALIZER_ROUTER"; + uint256 public constant override version = 3_10; /// @dev Mapping from hash(token0, token1, stable) to respective tuple mapping(bytes32 => EqualizerPool) internal _hashToPool; @@ -43,7 +39,7 @@ contract EqualizerRouterAdapter is AbstractAdapter, IEqualizerRouterAdapter { /// @notice Swap given amount of input token to output token /// @param amountIn Amount of input token to spend /// @param amountOutMin Minumum amount of output token to receive - /// @param routes Array of Route structs representing a swap path, must have at most 3 elements + /// @param routes Array of Route structs representing a swap path /// @param deadline Maximum timestamp until which the transaction is valid /// @dev Parameter `to` is ignored since swap recipient can only be the credit account function swapExactTokensForTokens( @@ -52,101 +48,104 @@ contract EqualizerRouterAdapter is AbstractAdapter, IEqualizerRouterAdapter { Route[] calldata routes, address, uint256 deadline - ) external override creditFacadeOnly returns (uint256 tokensToEnable, uint256 tokensToDisable) { + ) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); - (bool valid, address tokenIn, address tokenOut) = _validatePath(routes); + (bool valid, address tokenIn) = _validatePath(routes); if (!valid) revert InvalidPathException(); - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IEqualizerRouter.swapExactTokensForTokens, (amountIn, amountOutMin, routes, creditAccount, deadline) - ), - false + ) ); + + return true; } /// @notice Swap the entire balance of input token to output token, except the specified amount /// @param leftoverAmount Amount of tokenIn to keep on the account /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 - /// @param routes Array of Route structs representing a swap path, must have at most 3 elements + /// @param routes Array of Route structs representing a swap path /// @param deadline Maximum timestamp until which the transaction is valid function swapDiffTokensForTokens( uint256 leftoverAmount, uint256 rateMinRAY, Route[] calldata routes, uint256 deadline - ) external override creditFacadeOnly returns (uint256 tokensToEnable, uint256 tokensToDisable) { + ) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); - address tokenIn; - address tokenOut; - - { - bool valid; - (valid, tokenIn, tokenOut) = _validatePath(routes); - if (!valid) revert InvalidPathException(); - } + (bool valid, address tokenIn) = _validatePath(routes); + if (!valid) revert InvalidPathException(); uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; } - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IEqualizerRouter.swapExactTokensForTokens, (amount, (amount * rateMinRAY) / RAY, routes, creditAccount, deadline) - ), - leftoverAmount <= 1 + ) ); - } - // ------------- // - // CONFIGURATION // - // ------------- // - - /// @notice Returns whether the (token0, token1) pair is allowed to be traded through the adapter - function isPoolAllowed(address token0, address token1, bool stable) public view override returns (bool) { - (token0, token1) = _sortTokens(token0, token1); - return _poolStatus[token0][token1][stable]; + return true; } + // ---- // + // DATA // + // ---- // + function supportedPools() public view returns (EqualizerPool[] memory pools) { bytes32[] memory poolHashes = _supportedPoolHashes.values(); uint256 len = poolHashes.length; + pools = new EqualizerPool[](len); + for (uint256 i = 0; i < len; ++i) { pools[i] = _hashToPool[poolHashes[i]]; } } + function serialize() external view returns (bytes memory serializedData) { + EqualizerPool[] memory pools = supportedPools(); + serializedData = abi.encode(creditManager, targetContract, pools); + } + + // ------------- // + // CONFIGURATION // + // ------------- // + + /// @notice Returns whether the (token0, token1) pair is allowed to be traded through the adapter + function isPoolAllowed(address token0, address token1, bool stable) public view override returns (bool) { + (token0, token1) = _sortTokens(token0, token1); + return _supportedPoolHashes.contains(keccak256(abi.encode(token0, token1, stable))); + } + /// @notice Sets status for a batch of pools /// @param pools Array of `EqualizerPoolStatus` objects function setPoolStatusBatch(EqualizerPoolStatus[] calldata pools) external override configuratorOnly { uint256 len = pools.length; - unchecked { - for (uint256 i; i < len; ++i) { - (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); - _poolStatus[token0][token1][pools[i].stable] = pools[i].allowed; - - bytes32 poolHash = keccak256(abi.encode(token0, token1, pools[i].stable)); - if (pools[i].allowed) { - _supportedPoolHashes.add(poolHash); - _hashToPool[poolHash] = EqualizerPool({token0: token0, token1: token1, stable: pools[i].stable}); - } else { - _supportedPoolHashes.remove(poolHash); - delete _hashToPool[poolHash]; - } - - emit SetPoolStatus(token0, token1, pools[i].stable, pools[i].allowed); + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); + bytes32 poolHash = keccak256(abi.encode(token0, token1, pools[i].stable)); + if (pools[i].allowed) { + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + + _supportedPoolHashes.add(poolHash); + _hashToPool[poolHash] = EqualizerPool({token0: token0, token1: token1, stable: pools[i].stable}); + } else { + _supportedPoolHashes.remove(poolHash); + delete _hashToPool[poolHash]; } + emit SetPoolStatus(token0, token1, pools[i].stable, pools[i].allowed); } } @@ -154,26 +153,19 @@ contract EqualizerRouterAdapter is AbstractAdapter, IEqualizerRouterAdapter { // HELPERS // // ------- // - /// @dev Performs sanity check on a swap path, if path is valid also returns input and output tokens - /// - Path length must be no more than 4 (i.e., at most 3 hops) + /// @dev Performs sanity check on a swap path, if path is valid also returns input token + /// - Path length must be no more than 3 (i.e., at most 3 hops) /// - Each swap must be through an allowed pool - function _validatePath(Route[] memory routes) - internal - view - returns (bool valid, address tokenIn, address tokenOut) - { + function _validatePath(Route[] memory routes) internal view returns (bool valid, address tokenIn) { uint256 len = routes.length; - if (len < 1 || len > 3) return (false, tokenIn, tokenOut); + if (len < 1 || len > 3) return (false, tokenIn); tokenIn = routes[0].from; - tokenOut = routes[len - 1].to; valid = isPoolAllowed(routes[0].from, routes[0].to, routes[0].stable); - if (valid && len > 1) { - valid = isPoolAllowed(routes[1].from, routes[1].to, routes[1].stable) && (routes[0].to == routes[1].from); - if (valid && len > 2) { - valid = - isPoolAllowed(routes[2].from, routes[2].to, routes[2].stable) && (routes[1].to == routes[2].from); - } + + for (uint256 i = 1; i < len && valid; i++) { + valid = + isPoolAllowed(routes[i].from, routes[i].to, routes[i].stable) && (routes[i - 1].to == routes[i].from); } } diff --git a/contracts/adapters/erc4626/ERC4626Adapter.sol b/contracts/adapters/erc4626/ERC4626Adapter.sol index c0e3db43..b1dcaeba 100644 --- a/contracts/adapters/erc4626/ERC4626Adapter.sol +++ b/contracts/adapters/erc4626/ERC4626Adapter.sol @@ -1,43 +1,46 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IERC4626Adapter} from "../../interfaces/erc4626/IERC4626Adapter.sol"; /// @title ERC4626 Vault adapter /// @notice Implements logic allowing CAs to interact with any standard-compliant ERC4626 vault contract ERC4626Adapter is AbstractAdapter, IERC4626Adapter { - uint16 public constant override _gearboxAdapterVersion = 3_00; - /// @notice Address of the underlying asset of the vault address public immutable override asset; - /// @notice Mask of the underlying asset of the vault - uint256 public immutable override assetMask; + /// @notice Address of the vault + address public immutable override vault; - /// @notice Mask of the ERC4626 vault shares - uint256 public immutable override sharesMask; + function version() external pure virtual override returns (uint256) { + return 3_12; + } - function _gearboxAdapterType() external pure virtual override returns (AdapterType) { - return AdapterType.ERC4626_VAULT; + function contractType() external pure virtual override returns (bytes32) { + return "ADAPTER::ERC4626_VAULT"; } /// @notice Constructor /// @param _creditManager Credit manager address /// @param _vault ERC4626 vault address - constructor(address _creditManager, address _vault) - AbstractAdapter(_creditManager, _vault) // U:[TV-1] + /// @param _gateway An optional gateway address. If provided, the adapter will use it as target instead of the vault address. + constructor(address _creditManager, address _vault, address _gateway) + AbstractAdapter(_creditManager, _gateway == address(0) ? _vault : _gateway) // U:[TV-1] { + vault = _vault; asset = IERC4626(_vault).asset(); // U:[TV-1] - assetMask = _getMaskOrRevert(asset); // U:[TV-1] - sharesMask = _getMaskOrRevert(_vault); // U:[TV-1] + + // We verify that the vault asset and shares are valid collaterals + // in the system before deployment + _getMaskOrRevert(asset); // U:[TV-1] + _getMaskOrRevert(_vault); // U:[TV-1] } /// @notice Deposits a specified amount of underlying asset from the credit account @@ -47,10 +50,10 @@ contract ERC4626Adapter is AbstractAdapter, IERC4626Adapter { external override creditFacadeOnly // U:[TV-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[TV-3] - (tokensToEnable, tokensToDisable) = _deposit(creditAccount, assets, false); // U:[TV-3] + return _deposit(creditAccount, assets); // U:[TV-3] } /// @notice Deposits the entire balance of underlying asset from the credit account, except the specified amount @@ -59,25 +62,22 @@ contract ERC4626Adapter is AbstractAdapter, IERC4626Adapter { external override creditFacadeOnly // U:[TV-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[TV-4] uint256 balance = IERC20(asset).balanceOf(creditAccount); // U:[TV-4] - if (balance <= leftoverAmount) return (0, 0); + if (balance <= leftoverAmount) return false; unchecked { balance -= leftoverAmount; // U:[TV-4] } - (tokensToEnable, tokensToDisable) = _deposit(creditAccount, balance, leftoverAmount <= 1); // U:[TV-4] + return _deposit(creditAccount, balance); // U:[TV-4] } /// @dev Implementation for the deposit function - function _deposit(address creditAccount, uint256 assets, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = - _executeDeposit(disableTokenIn, abi.encodeCall(IERC4626.deposit, (assets, creditAccount))); // U:[TV-3,4] + function _deposit(address creditAccount, uint256 assets) internal virtual returns (bool) { + _executeSwapSafeApprove(asset, abi.encodeCall(IERC4626.deposit, (assets, creditAccount))); // U:[TV-3,4] + return false; } /// @notice Deposits an amount of asset required to mint exactly 'shares' of vault shares @@ -87,11 +87,16 @@ contract ERC4626Adapter is AbstractAdapter, IERC4626Adapter { external override creditFacadeOnly // U:[TV-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[TV-5] - (tokensToEnable, tokensToDisable) = - _executeDeposit(false, abi.encodeCall(IERC4626.mint, (shares, creditAccount))); // U:[TV-5] + return _mint(creditAccount, shares); + } + + /// @dev Implementation for the mint function + function _mint(address creditAccount, uint256 shares) internal virtual returns (bool) { + _executeSwapSafeApprove(asset, abi.encodeCall(IERC4626.mint, (shares, creditAccount))); // U:[TV-5] + return false; } /// @notice Burns an amount of shares required to get exactly `assets` of asset @@ -99,14 +104,18 @@ contract ERC4626Adapter is AbstractAdapter, IERC4626Adapter { /// @dev `receiver` and `owner` are ignored, since they are always set to the credit account address function withdraw(uint256 assets, address, address) external - virtual override creditFacadeOnly // U:[TV-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[TV-6] - (tokensToEnable, tokensToDisable) = - _executeWithdrawal(false, abi.encodeCall(IERC4626.withdraw, (assets, creditAccount, creditAccount))); // U:[TV-6] + return _withdraw(creditAccount, assets); + } + + /// @dev Implementation for the withdraw function + function _withdraw(address creditAccount, uint256 assets) internal virtual returns (bool) { + _execute(abi.encodeCall(IERC4626.withdraw, (assets, creditAccount, creditAccount))); // U:[TV-6] + return false; } /// @notice Burns a specified amount of shares from the credit account @@ -114,65 +123,39 @@ contract ERC4626Adapter is AbstractAdapter, IERC4626Adapter { /// @dev `receiver` and `owner` are ignored, since they are always set to the credit account address function redeem(uint256 shares, address, address) external - virtual override creditFacadeOnly // U:[TV-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[TV-7] - (tokensToEnable, tokensToDisable) = _redeem(creditAccount, shares, false); // U:[TV-7] + return _redeem(creditAccount, shares); // U:[TV-7] } /// @notice Burns the entire balance of shares from the credit account, except the specified amount /// @param leftoverAmount Amount of vault token to keep on the account function redeemDiff(uint256 leftoverAmount) external - virtual override creditFacadeOnly // U:[TV-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[TV-8] - uint256 balance = IERC20(targetContract).balanceOf(creditAccount); // U:[TV-8] - if (balance <= leftoverAmount) return (0, 0); + uint256 balance = IERC20(vault).balanceOf(creditAccount); // U:[TV-8] + if (balance <= leftoverAmount) return false; unchecked { balance -= leftoverAmount; // U:[TV-8] } - (tokensToEnable, tokensToDisable) = _redeem(creditAccount, balance, leftoverAmount <= 1); // U:[TV-8] + return _redeem(creditAccount, balance); // U:[TV-8] } /// @dev Implementation for the redeem function - function _redeem(address creditAccount, uint256 shares, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = - _executeWithdrawal(disableTokenIn, abi.encodeCall(IERC4626.redeem, (shares, creditAccount, creditAccount))); // U:[TV-7,8] - } - - /// @dev Implementation for deposit (asset => shares) actions execution - /// @dev All deposit-type actions follow the same structure, with only - /// calldata and disabling the input token being different - function _executeDeposit(bool disableAsset, bytes memory callData) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(asset, type(uint256).max); // U:[TV-3,4,5] - _execute(callData); // U:[TV-3,4,5] - _approveToken(asset, 1); // U:[TV-3,4,5] - tokensToEnable = sharesMask; - tokensToDisable = disableAsset ? assetMask : 0; + function _redeem(address creditAccount, uint256 shares) internal virtual returns (bool) { + _execute(abi.encodeCall(IERC4626.redeem, (shares, creditAccount, creditAccount))); // U:[TV-7,8] + return false; } - /// @dev Implementation for withdrawal (shares => asset) actions execution - /// @dev All withdrawal-type actions follow the same structure, with only - /// calldata and disabling the input token being different - function _executeWithdrawal(bool disableShares, bytes memory callData) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _execute(callData); // U:[TV-6,7,8] - tokensToEnable = assetMask; - tokensToDisable = disableShares ? sharesMask : 0; + /// @notice Serialized adapter parameters + function serialize() external view virtual returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, vault, asset); } } diff --git a/contracts/adapters/erc4626/ERC4626ReferralAdapter.sol b/contracts/adapters/erc4626/ERC4626ReferralAdapter.sol new file mode 100644 index 00000000..ae21d83d --- /dev/null +++ b/contracts/adapters/erc4626/ERC4626ReferralAdapter.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {ERC4626Adapter} from "../erc4626/ERC4626Adapter.sol"; +import {IERC4626Referral} from "../../integrations/erc4626/IERC4626Referral.sol"; + +/// @title ERC4626 Vault Referral adapter +/// @notice Same as `ERC4626Adapter`, but uses a signature for deposits that allows deployer to specify the referral code +contract ERC4626ReferralAdapter is ERC4626Adapter { + uint16 public immutable referral; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _vault ERC4626 vault address + /// @param _referral Referral code + constructor(address _creditManager, address _vault, uint16 _referral) + ERC4626Adapter(_creditManager, _vault, address(0)) + { + referral = _referral; + } + + function version() external pure virtual override returns (uint256) { + return 3_10; + } + + function contractType() external pure virtual override returns (bytes32) { + return "ADAPTER::ERC4626_VAULT_REFERRAL"; + } + + function serialize() external view virtual override returns (bytes memory) { + return abi.encode(creditManager, targetContract, asset, referral); + } + + function _deposit(address creditAccount, uint256 assets) internal virtual override returns (bool) { + _executeSwapSafeApprove(asset, abi.encodeCall(IERC4626Referral.deposit, (assets, creditAccount, referral))); + return false; + } + + function _mint(address creditAccount, uint256 shares) internal virtual override returns (bool) { + _executeSwapSafeApprove(asset, abi.encodeCall(IERC4626Referral.mint, (shares, creditAccount, referral))); + return false; + } +} diff --git a/contracts/adapters/fluid/FluidDexAdapter.sol b/contracts/adapters/fluid/FluidDexAdapter.sol new file mode 100644 index 00000000..7fe8b120 --- /dev/null +++ b/contracts/adapters/fluid/FluidDexAdapter.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {IFluidDex, ConstantViews} from "../../integrations/fluid/IFluidDex.sol"; +import {IFluidDexAdapter} from "../../interfaces/fluid/IFluidDexAdapter.sol"; + +/// @title FluidDex Adapter +/// @notice Implements logic for interacting with the FluidDex exchange +contract FluidDexAdapter is AbstractAdapter, IFluidDexAdapter { + bytes32 public constant override contractType = "ADAPTER::FLUID_DEX"; + uint256 public constant override version = 3_10; + + /// @notice Token0 in the FluidDex pair + address public immutable override token0; + + /// @notice Token1 in the FluidDex pair + address public immutable override token1; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _targetContract FluidDex contract address + constructor(address _creditManager, address _targetContract) AbstractAdapter(_creditManager, _targetContract) { + ConstantViews memory constantViews = IFluidDex(targetContract).constantsView(); + + token0 = constantViews.token0; + token1 = constantViews.token1; + + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + } + + /// @notice Swaps given amount of one token to another + /// @param swap0to1 Direction of swap (true for token0 to token1, false for token1 to token0) + /// @param amountIn Amount of input token to swap + /// @param amountOutMin Minimum amount of output token to receive + /// @dev The `to` parameter is ignored as it is always the Credit Account + function swapIn(bool swap0to1, uint256 amountIn, uint256 amountOutMin, address) + external + override + creditFacadeOnly + returns (bool) + { + address creditAccount = _creditAccount(); + _swapIn(swap0to1, creditAccount, amountIn, amountOutMin); + return true; + } + + /// @notice Swaps the entire balance of one token to another, except the specified amount + /// @param swap0to1 Direction of swap (true for token0 to token1, false for token1 to token0) + /// @param leftoverAmount Amount of input token to keep on the account + /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 + function swapInDiff(bool swap0to1, uint256 leftoverAmount, uint256 rateMinRAY) + external + override + creditFacadeOnly + returns (bool) + { + address creditAccount = _creditAccount(); + address tokenIn = swap0to1 ? token0 : token1; + + uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); + if (amount <= leftoverAmount) return false; + + unchecked { + amount -= leftoverAmount; + } + + _swapIn(swap0to1, creditAccount, amount, (amount * rateMinRAY) / RAY); + return true; + } + + /// @dev Internal implementation for `swapIn` and `swapInDiff` + function _swapIn(bool swap0to1, address creditAccount, uint256 amountIn, uint256 amountOutMin) internal { + address tokenIn = swap0to1 ? token0 : token1; + _executeSwapSafeApprove( + tokenIn, abi.encodeCall(IFluidDex.swapIn, (swap0to1, amountIn, amountOutMin, creditAccount)) + ); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, token0, token1); + } +} diff --git a/contracts/adapters/infinifi/InfinifiGatewayAdapter.sol b/contracts/adapters/infinifi/InfinifiGatewayAdapter.sol new file mode 100644 index 00000000..2df654e1 --- /dev/null +++ b/contracts/adapters/infinifi/InfinifiGatewayAdapter.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; +import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {IInfinifiGateway, IInfinifiLockingController} from "../../integrations/infinifi/IInfinifiGateway.sol"; +import {IInfinifiGatewayAdapter, LockedTokenStatus} from "../../interfaces/infinifi/IInfinifiGatewayAdapter.sol"; + +/// @title Infinifi Gateway adapter +/// @notice Implements logic for interacting with the Infinifi Gateway +contract InfinifiGatewayAdapter is AbstractAdapter, IInfinifiGatewayAdapter { + using EnumerableSet for EnumerableSet.AddressSet; + + bytes32 public constant override contractType = "ADAPTER::INFINIFI_GATEWAY"; + uint256 public constant override version = 3_10; + + /// @notice The USDC address + address public immutable usdc; + + /// @notice The iUSD address + address public immutable iusd; + + /// @notice The siUSD address + address public immutable siusd; + + /// @notice The set of allowed locked tokens + EnumerableSet.AddressSet private _allowedLockedTokens; + + /// @notice The mapping of unwinding epochs to locked tokens + mapping(uint32 => address) public unwindingEpochToLockedToken; + + /// @notice The mapping of locked tokens to unwinding epochs + mapping(address => uint32) public lockedTokenToUnwindingEpoch; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _infinifiGateway Infinifi Gateway address + constructor(address _creditManager, address _infinifiGateway) AbstractAdapter(_creditManager, _infinifiGateway) { + usdc = IInfinifiGateway(_infinifiGateway).getAddress("USDC"); + iusd = IInfinifiGateway(_infinifiGateway).getAddress("receiptToken"); + siusd = IInfinifiGateway(_infinifiGateway).getAddress("stakedToken"); + + _getMaskOrRevert(usdc); + _getMaskOrRevert(iusd); + _getMaskOrRevert(siusd); + } + + /// MINT + + /// @notice Mints iUSD from the underlying asset + /// @param amount The amount of underlying asset to mint + /// @dev `to` is ignored, since the recipient is always the credit account + function mint(address, uint256 amount) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + _mint(creditAccount, amount); + return false; + } + + /// @notice Mints iUSD from the underlying asset using the entire balance, except for the specified amount + /// @param leftoverAmount The amount of underlying asset to leave in the credit account + /// @dev `to` is ignored, since the recipient is always the credit account + function mintDiff(uint256 leftoverAmount) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + uint256 balance = IERC20(usdc).balanceOf(creditAccount); + if (balance <= leftoverAmount) return false; + _mint(creditAccount, balance - leftoverAmount); + return false; + } + + /// @dev Internal implementation for `mint` and `mintDiff` + function _mint(address creditAccount, uint256 amount) internal { + _executeSwapSafeApprove(usdc, abi.encodeCall(IInfinifiGateway.mint, (creditAccount, amount))); + } + + /// STAKE + + /// @notice Stakes iUSD into siUSD + /// @param amount The amount of iUSD to stake + /// @dev `to` is ignored, since the recipient is always the credit account + function stake(address, uint256 amount) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + _stake(creditAccount, amount); + return false; + } + + /// @notice Stakes iUSD into siUSD using the entire balance, except for the specified amount + /// @param leftoverAmount The amount of iUSD to leave in the credit account + function stakeDiff(uint256 leftoverAmount) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + uint256 balance = IERC20(iusd).balanceOf(creditAccount); + if (balance <= leftoverAmount) return false; + _stake(creditAccount, balance - leftoverAmount); + return false; + } + + /// @dev Internal implementation for `stake` and `stakeDiff` + function _stake(address creditAccount, uint256 amount) internal { + _executeSwapSafeApprove(iusd, abi.encodeCall(IInfinifiGateway.stake, (creditAccount, amount))); + } + + /// UNSTAKE + + /// @notice Unstakes siUSD into iUSD + /// @param amount The amount of siUSD to unstake + /// @dev `to` is ignored, since the recipient is always the credit account + function unstake(address, uint256 amount) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + _unstake(creditAccount, amount); + return false; + } + + /// @notice Unstakes siUSD into iUSD using the entire balance, except for the specified amount + /// @param leftoverAmount The amount of siUSD to leave in the credit account + function unstakeDiff(uint256 leftoverAmount) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + uint256 balance = IERC20(siusd).balanceOf(creditAccount); + if (balance <= leftoverAmount) return false; + _unstake(creditAccount, balance - leftoverAmount); + return false; + } + + /// @dev Internal implementation for `unstake` and `unstakeDiff` + function _unstake(address creditAccount, uint256 amount) internal { + _executeSwapSafeApprove(siusd, abi.encodeCall(IInfinifiGateway.unstake, (creditAccount, amount))); + } + + /// CREATE POSITION + + /// @notice Creates a locked token position from iUSD + /// @param amount The amount of iUSD to lock + /// @param unwindingEpochs The unwinding duration of the locked position + /// @dev `to` is ignored, since the recipient is always the credit account + function createPosition(uint256 amount, uint32 unwindingEpochs) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + _createPosition(creditAccount, amount, unwindingEpochs); + return false; + } + + /// @notice Creates a locked token position from iUSD using the entire balance, except for the specified amount + /// @param leftoverAmount The amount of iUSD to leave in the credit account + /// @param unwindingEpochs The unwinding duration of the locked position + function createPositionDiff(uint256 leftoverAmount, uint32 unwindingEpochs) + external + creditFacadeOnly + returns (bool) + { + address creditAccount = _creditAccount(); + uint256 balance = IERC20(iusd).balanceOf(creditAccount); + if (balance <= leftoverAmount) return false; + _createPosition(creditAccount, balance - leftoverAmount, unwindingEpochs); + return false; + } + + /// @dev Internal implementation for `createPosition` and `createPositionDiff` + function _createPosition(address creditAccount, uint256 amount, uint32 unwindingEpochs) internal { + if (!_allowedLockedTokens.contains(unwindingEpochToLockedToken[unwindingEpochs])) { + revert LockedTokenNotAllowedException(); + } + + _executeSwapSafeApprove( + iusd, abi.encodeCall(IInfinifiGateway.createPosition, (amount, unwindingEpochs, creditAccount)) + ); + } + + /// REDEEM + + /// @notice Redeems iUSD for the underlying asset + /// @param amount The amount of iUSD to redeem + /// @param minAssetsOut The minimum amount of underlying asset to receive + /// @dev `to` is ignored, since the recipient is always the credit account + function redeem(address, uint256 amount, uint256 minAssetsOut) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + _redeem(creditAccount, amount, minAssetsOut); + return false; + } + + /// @notice Redeems iUSD for the underlying asset using the entire balance, except for the specified amount + /// @param leftoverAmount The amount of iUSD to leave in the credit account + /// @param minRateRAY The minimum rate of underlying asset to receive + function redeemDiff(uint256 leftoverAmount, uint256 minRateRAY) external creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + uint256 balance = IERC20(iusd).balanceOf(creditAccount); + if (balance <= leftoverAmount) return false; + uint256 amount = balance - leftoverAmount; + _redeem(creditAccount, amount, amount * minRateRAY / RAY); + return false; + } + + /// @dev Internal implementation for `redeem` and `redeemDiff` + function _redeem(address creditAccount, uint256 amount, uint256 minAssetsOut) internal { + _executeSwapSafeApprove(iusd, abi.encodeCall(IInfinifiGateway.redeem, (creditAccount, amount, minAssetsOut))); + } + + /// @notice Claims iUSD redemptions that are enqueued + /// @dev Although this adapter only supports immediate redemptions and enqueued redemptions are not considered collateral, + /// the function is left in to allow claiming delayed redemptions created accidentally + function claimRedemption() external creditFacadeOnly returns (bool) { + _execute(abi.encodeCall(IInfinifiGateway.claimRedemption, ())); + return false; + } + + /// DATA + + /// @notice Returns the set of allowed locked tokens + function getAllowedLockedTokens() public view returns (address[] memory tokens) { + return _allowedLockedTokens.values(); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory) { + return abi.encode(creditManager, targetContract, usdc, iusd, siusd, getAllowedLockedTokens()); + } + + /// CONFIGURATION + + function setLockedTokenBatchStatus(LockedTokenStatus[] calldata lockedTokens) external configuratorOnly { + uint256 len = lockedTokens.length; + address lockingController = IInfinifiGateway(targetContract).getAddress("lockingController"); + for (uint256 i; i < len; ++i) { + if ( + IInfinifiLockingController(lockingController).shareToken(lockedTokens[i].unwindingEpochs) + != lockedTokens[i].lockedToken + ) { + revert LockedTokenUnwindingEpochsMismatchException(); + } + + if (lockedTokens[i].allowed) { + _allowedLockedTokens.add(lockedTokens[i].lockedToken); + _getMaskOrRevert(lockedTokens[i].lockedToken); + unwindingEpochToLockedToken[lockedTokens[i].unwindingEpochs] = lockedTokens[i].lockedToken; + lockedTokenToUnwindingEpoch[lockedTokens[i].lockedToken] = lockedTokens[i].unwindingEpochs; + } else { + _allowedLockedTokens.remove(lockedTokens[i].lockedToken); + delete unwindingEpochToLockedToken[lockedTokens[i].unwindingEpochs]; + delete lockedTokenToUnwindingEpoch[lockedTokens[i].lockedToken]; + } + + emit SetLockedTokenStatus( + lockedTokens[i].lockedToken, lockedTokens[i].unwindingEpochs, lockedTokens[i].allowed + ); + } + } +} diff --git a/contracts/adapters/infinifi/InfinifiUnwindingGatewayAdapter.sol b/contracts/adapters/infinifi/InfinifiUnwindingGatewayAdapter.sol new file mode 100644 index 00000000..3249ed60 --- /dev/null +++ b/contracts/adapters/infinifi/InfinifiUnwindingGatewayAdapter.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; +import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {IInfinifiUnwindingGateway} from "../../interfaces/infinifi/IInfinifiUnwindingGateway.sol"; +import { + IInfinifiUnwindingGatewayAdapter, + LockedTokenStatus +} from "../../interfaces/infinifi/IInfinifiUnwindingGatewayAdapter.sol"; +import {IInfinifiGateway, IInfinifiLockingController} from "../../integrations/infinifi/IInfinifiGateway.sol"; + +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +/// @title Infinifi Gateway adapter +/// @notice Implements logic for interacting with the Infinifi Gateway +contract InfinifiUnwindingGatewayAdapter is AbstractAdapter, IInfinifiUnwindingGatewayAdapter { + using EnumerableSet for EnumerableSet.AddressSet; + + bytes32 public constant override contractType = "ADAPTER::INFINIFI_UNWINDING"; + uint256 public constant override version = 3_10; + + /// @notice The set of allowed locked tokens + EnumerableSet.AddressSet private _allowedLockedTokens; + + /// @notice The mapping of unwinding epochs to locked tokens + mapping(uint32 => address) public unwindingEpochToLockedToken; + + /// @notice The mapping of locked tokens to unwinding epochs + mapping(address => uint32) public lockedTokenToUnwindingEpoch; + + address public immutable infinifiUnwindingPhantomToken; + + constructor(address _creditManager, address _infinifiUnwindingGateway, address _infinifiUnwindingPhantomToken) + AbstractAdapter(_creditManager, _infinifiUnwindingGateway) + { + infinifiUnwindingPhantomToken = _infinifiUnwindingPhantomToken; + } + + /// @notice Starts unwinding a locked token position + /// @param shares The amount of shares to unwinding + /// @param unwindingEpochs The number of epochs to unwinding + function startUnwinding(uint256 shares, uint32 unwindingEpochs) external override creditFacadeOnly returns (bool) { + address lockedToken = unwindingEpochToLockedToken[unwindingEpochs]; + + if (!_allowedLockedTokens.contains(lockedToken)) { + revert LockedTokenNotAllowedException(); + } + + _executeSwapSafeApprove( + lockedToken, abi.encodeCall(IInfinifiUnwindingGateway.startUnwinding, (shares, unwindingEpochs)) + ); + + return true; + } + + /// @notice Withdraws the assets that finished unwinding + /// @param amount The amount of assets to withdraw + function withdraw(uint256 amount) external override creditFacadeOnly returns (bool) { + _execute(abi.encodeCall(IInfinifiUnwindingGateway.withdraw, (amount))); + return false; + } + + /// @notice Withdraws phantom token for its underlying + function withdrawPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != infinifiUnwindingPhantomToken) revert IncorrectStakedPhantomTokenException(); + _execute(abi.encodeCall(IInfinifiUnwindingGateway.withdraw, (amount))); + return false; + } + + /// @dev It's not possible to deposit from underlying (the vault's asset) into the withdrawal phantom token, + /// hence the function is not implemented. + function depositPhantomToken(address, uint256) external view override creditFacadeOnly returns (bool) { + revert NotImplementedException(); + } + + function getAllowedLockedTokens() public view returns (address[] memory tokens) { + return _allowedLockedTokens.values(); + } + + function serialize() external view returns (bytes memory) { + return abi.encode(creditManager, targetContract, getAllowedLockedTokens()); + } + + function setLockedTokenBatchStatus(LockedTokenStatus[] calldata lockedTokens) external configuratorOnly { + uint256 len = lockedTokens.length; + address lockingController = IInfinifiUnwindingGateway(targetContract).lockingController(); + for (uint256 i; i < len; ++i) { + if ( + IInfinifiLockingController(lockingController).shareToken(lockedTokens[i].unwindingEpochs) + != lockedTokens[i].lockedToken + ) { + revert LockedTokenUnwindingEpochsMismatchException(); + } + + if (lockedTokens[i].allowed) { + _allowedLockedTokens.add(lockedTokens[i].lockedToken); + _getMaskOrRevert(lockedTokens[i].lockedToken); + unwindingEpochToLockedToken[lockedTokens[i].unwindingEpochs] = lockedTokens[i].lockedToken; + lockedTokenToUnwindingEpoch[lockedTokens[i].lockedToken] = lockedTokens[i].unwindingEpochs; + } else { + _allowedLockedTokens.remove(lockedTokens[i].lockedToken); + delete unwindingEpochToLockedToken[lockedTokens[i].unwindingEpochs]; + delete lockedTokenToUnwindingEpoch[lockedTokens[i].lockedToken]; + } + + emit SetLockedTokenStatus( + lockedTokens[i].lockedToken, lockedTokens[i].unwindingEpochs, lockedTokens[i].allowed + ); + } + } +} diff --git a/contracts/adapters/infrared/InfraredVaultAdapter.sol b/contracts/adapters/infrared/InfraredVaultAdapter.sol new file mode 100644 index 00000000..6d36d516 --- /dev/null +++ b/contracts/adapters/infrared/InfraredVaultAdapter.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {IInfraredVault, UserReward} from "../../integrations/infrared/IInfraredVault.sol"; +import {IInfraredVaultAdapter} from "../../interfaces/infrared/IInfraredVaultAdapter.sol"; + +/// @title InfraredVault adapter +/// @notice Implements logic for interacting with Infrared Vault contracts +contract InfraredVaultAdapter is AbstractAdapter, IInfraredVaultAdapter { + bytes32 public constant override contractType = "ADAPTER::INFRARED_VAULT"; + uint256 public constant override version = 3_11; + + /// @notice Address of the staking token + address public immutable override stakingToken; + + /// @notice Address of a phantom token representing account's stake in the vault + address public immutable override stakedPhantomToken; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _infraredVault InfraredVault contract address + /// @param _stakedPhantomToken Staked phantom token address + constructor(address _creditManager, address _infraredVault, address _stakedPhantomToken) + AbstractAdapter(_creditManager, _infraredVault) + { + stakingToken = IInfraredVault(_infraredVault).stakingToken(); + _getMaskOrRevert(stakingToken); + + stakedPhantomToken = _stakedPhantomToken; + _getMaskOrRevert(stakedPhantomToken); + + address[] memory tokens = IInfraredVault(_infraredVault).getAllRewardTokens(); + for (uint256 i = 0; i < tokens.length; ++i) { + _getMaskOrRevert(tokens[i]); + } + } + + // ----- // + // STAKE // + // ----- // + + /// @notice Stakes tokens in the InfraredVault + /// @param amount Amount of tokens to stake + function stake(uint256 amount) external override creditFacadeOnly returns (bool) { + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IInfraredVault.stake, (amount))); + return false; + } + + /// @notice Stakes the entire balance of staking token, except the specified amount + /// @param leftoverAmount Amount of staking token to keep on the account + function stakeDiff(uint256 leftoverAmount) external override creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + + uint256 balance = IERC20(stakingToken).balanceOf(creditAccount); + + if (balance > leftoverAmount) { + unchecked { + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IInfraredVault.stake, (balance - leftoverAmount))); + } + } + return false; + } + + /// @notice Deposits into a phantom token + function depositPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IInfraredVault.stake, (amount))); + return false; + } + + // ----- // + // CLAIM // + // ----- // + + /// @notice Claims all rewards on the current position + function getReward() external override creditFacadeOnly returns (bool) { + _execute(abi.encodeCall(IInfraredVault.getReward, ())); + return false; + } + + // -------- // + // WITHDRAW // + // -------- // + + /// @notice Withdraws staked tokens from the InfraredVault + /// @param amount Amount of tokens to withdraw + function withdraw(uint256 amount) external override creditFacadeOnly returns (bool) { + _execute(abi.encodeCall(IInfraredVault.withdraw, (amount))); + return false; + } + + /// @notice Withdraws the entire balance of staked tokens, except the specified amount + /// @param leftoverAmount Amount of staked tokens to keep in the contract + function withdrawDiff(uint256 leftoverAmount) external override creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + + uint256 balance = IERC20(stakedPhantomToken).balanceOf(creditAccount); + + if (balance > leftoverAmount) { + unchecked { + _execute(abi.encodeCall(IInfraredVault.withdraw, (balance - leftoverAmount))); + } + } + + return false; + } + + /// @notice Exits the staking position by withdrawing all staked tokens and claiming rewards + function exit() external override creditFacadeOnly returns (bool) { + _execute(abi.encodeCall(IInfraredVault.exit, ())); + return false; + } + + /// @notice Withdraws phantom token for its underlying + /// @dev `token` parameter is ignored as adapter only handles one token + function withdrawPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); + _execute(abi.encodeCall(IInfraredVault.withdraw, (amount))); + return false; + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, stakingToken, stakedPhantomToken); + } +} diff --git a/contracts/adapters/kodiak/KodiakIslandGatewayAdapter.sol b/contracts/adapters/kodiak/KodiakIslandGatewayAdapter.sol new file mode 100644 index 00000000..ab3a2c29 --- /dev/null +++ b/contracts/adapters/kodiak/KodiakIslandGatewayAdapter.sol @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import { + IKodiakIslandGatewayAdapter, + KodiakIslandStatus, + IslandStatus +} from "../../interfaces/kodiak/IKodiakIslandGatewayAdapter.sol"; +import {IKodiakIslandGateway, Ratios} from "../../interfaces/kodiak/IKodiakIslandGateway.sol"; +import {IKodiakIsland} from "../../integrations/kodiak/IKodiakIsland.sol"; + +/// @title KodiakIslandGateway adapter +/// @notice Implements logic for interacting with KodiakIslandGateway contracts +contract KodiakIslandGatewayAdapter is AbstractAdapter, IKodiakIslandGatewayAdapter { + using EnumerableSet for EnumerableSet.AddressSet; + + bytes32 public constant override contractType = "ADAPTER::KODIAK_ISLAND_GATEWAY"; + uint256 public constant override version = 3_10; + + EnumerableSet.AddressSet private _allowedIslands; + + mapping(address => IslandStatus) private _islandStatus; + + constructor(address _creditManager, address _kodiakGateway) AbstractAdapter(_creditManager, _kodiakGateway) {} + + // -----// + // SWAP // + // -----// + + /// @notice Swaps tokens through the KodiakIslandGateway. + function swap(address island, address tokenIn, uint256 amountIn, uint256 amountOutMin) + external + override + creditFacadeOnly + returns (bool) + { + if (!_isSwapAllowed(island)) revert IslandNotAllowedException(island); + + _swap(island, tokenIn, amountIn, amountOutMin); + + return true; + } + + /// @notice Swaps tokens through the KodiakIslandGateway, using the entire balance of the input token, + /// except the specified amount. + function swapDiff(address island, address tokenIn, uint256 leftoverAmount, uint256 minRateRAY) + external + override + creditFacadeOnly + returns (bool) + { + if (!_isSwapAllowed(island)) revert IslandNotAllowedException(island); + + address creditAccount = _creditAccount(); + + uint256 amountIn = _getAmountOverLeftover(tokenIn, leftoverAmount, creditAccount); + + if (amountIn == 0) return false; + + _swap(island, tokenIn, amountIn, amountIn * minRateRAY / RAY); + + return true; + } + + /// @dev Internal function to swap tokens through the KodiakIslandGateway. + function _swap(address island, address tokenIn, uint256 amountIn, uint256 amountOutMin) internal { + _executeSwapSafeApprove( + tokenIn, abi.encodeCall(IKodiakIslandGateway.swap, (island, tokenIn, amountIn, amountOutMin)) + ); + } + + // ------------- // + // ADD LIQUIDITY // + // ------------- // + + /// @notice Adds liquidity to an island with an imbalanced ratio. + /// @dev `receiver` is ignored, since it is always set to the credit account. + function addLiquidityImbalanced(address island, uint256 amount0, uint256 amount1, uint256 minLPAmount, address) + external + override + creditFacadeOnly + returns (bool) + { + if (!_isDepositAllowed(island)) revert IslandNotAllowedException(island); + + (address token0, address token1) = _getIslandTokens(island); + + address creditAccount = _creditAccount(); + + _addLiquidityImbalanced(island, token0, token1, amount0, amount1, minLPAmount, creditAccount); + + return true; + } + + /// @notice Adds liquidity to an island with an imbalanced ratio, with externally provided deposit and price ratios. + /// @dev `receiver` is ignored, since it is always set to the credit account. + function addLiquidityImbalancedAssisted( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address, + Ratios memory ratios + ) external override creditFacadeOnly returns (bool) { + if (!_isDepositAllowed(island)) revert IslandNotAllowedException(island); + + (address token0, address token1) = _getIslandTokens(island); + + address creditAccount = _creditAccount(); + + _addLiquidityImbalancedAssisted(island, token0, token1, amount0, amount1, minLPAmount, creditAccount, ratios); + + return true; + } + + /// @notice Adds liquidity to an island with an imbalanced ratio, using the entire balance of the tokens, + /// except the specified amount. + function addLiquidityImbalancedDiff( + address island, + uint256 leftoverAmount0, + uint256 leftoverAmount1, + uint256[2] memory minRatesRAY + ) external override creditFacadeOnly returns (bool) { + if (!_isDepositAllowed(island)) revert IslandNotAllowedException(island); + + (address token0, address token1) = _getIslandTokens(island); + + address creditAccount = _creditAccount(); + + uint256 amount0 = _getAmountOverLeftover(token0, leftoverAmount0, creditAccount); + uint256 amount1 = _getAmountOverLeftover(token1, leftoverAmount1, creditAccount); + + if (amount0 == 0 && amount1 == 0) return false; + + uint256 minLPAmount = (amount0 * minRatesRAY[0] + amount1 * minRatesRAY[1]) / RAY; + + _addLiquidityImbalanced(island, token0, token1, amount0, amount1, minLPAmount, creditAccount); + + return true; + } + + /// @notice Adds liquidity to an island with an imbalanced ratio, using the entire balance of the tokens, + /// except the specified amount, with externally provided deposit and price ratios. + function addLiquidityImbalancedDiffAssisted( + address island, + uint256 leftoverAmount0, + uint256 leftoverAmount1, + uint256[2] memory minRatesRAY, + Ratios memory ratios + ) external override creditFacadeOnly returns (bool) { + if (!_isDepositAllowed(island)) revert IslandNotAllowedException(island); + + (address token0, address token1) = _getIslandTokens(island); + + address creditAccount = _creditAccount(); + + uint256 amount0 = _getAmountOverLeftover(token0, leftoverAmount0, creditAccount); + uint256 amount1 = _getAmountOverLeftover(token1, leftoverAmount1, creditAccount); + + if (amount0 == 0 && amount1 == 0) return false; + + uint256 minLPAmount = (amount0 * minRatesRAY[0] + amount1 * minRatesRAY[1]) / RAY; + + _addLiquidityImbalancedAssisted(island, token0, token1, amount0, amount1, minLPAmount, creditAccount, ratios); + + return true; + } + + /// @dev Internal implementation of `addLiquidityImbalanced`. + function _addLiquidityImbalanced( + address island, + address token0, + address token1, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address creditAccount + ) internal { + _approveToken(token0, type(uint256).max); + _approveToken(token1, type(uint256).max); + _execute( + abi.encodeCall( + IKodiakIslandGateway.addLiquidityImbalanced, (island, amount0, amount1, minLPAmount, creditAccount) + ) + ); + _approveToken(token0, 1); + _approveToken(token1, 1); + } + + /// @dev Internal implementation of `addLiquidityImbalancedAssisted`. + function _addLiquidityImbalancedAssisted( + address island, + address token0, + address token1, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address creditAccount, + Ratios memory ratios + ) internal { + _approveToken(token0, type(uint256).max); + _approveToken(token1, type(uint256).max); + _execute( + abi.encodeCall( + IKodiakIslandGateway.addLiquidityImbalancedAssisted, + (island, amount0, amount1, minLPAmount, creditAccount, ratios) + ) + ); + _approveToken(token0, 1); + _approveToken(token1, 1); + } + + // ---------------- // + // REMOVE LIQUIDITY // + // ---------------- // + + /// @notice Removes liquidity from an island in a single token. + /// @dev `receiver` is ignored, since it is always set to the credit account. + function removeLiquiditySingle(address island, uint256 lpAmount, address tokenOut, uint256 minAmountOut, address) + external + override + creditFacadeOnly + returns (bool) + { + if (!_isWithdrawalAllowed(island)) revert IslandNotAllowedException(island); + + address creditAccount = _creditAccount(); + + _removeLiquiditySingle(island, lpAmount, tokenOut, minAmountOut, creditAccount); + + return true; + } + + /// @notice Removes liquidity from an island in a single token, using the entire island balance, + /// except the specified amount. + function removeLiquiditySingleDiff(address island, uint256 leftoverAmount, address tokenOut, uint256 minRateRAY) + external + override + creditFacadeOnly + returns (bool) + { + if (!_isWithdrawalAllowed(island)) revert IslandNotAllowedException(island); + + address creditAccount = _creditAccount(); + + uint256 lpAmount = _getAmountOverLeftover(island, leftoverAmount, creditAccount); + + if (lpAmount == 0) return false; + + _removeLiquiditySingle(island, lpAmount, tokenOut, lpAmount * minRateRAY / RAY, creditAccount); + + return true; + } + + /// @dev Internal implementation of `removeLiquiditySingle`. + function _removeLiquiditySingle( + address island, + uint256 lpAmount, + address tokenOut, + uint256 minAmountOut, + address creditAccount + ) internal { + _executeSwapSafeApprove( + island, + abi.encodeCall( + IKodiakIslandGateway.removeLiquiditySingle, (island, lpAmount, tokenOut, minAmountOut, creditAccount) + ) + ); + } + + // ------- // + // HELPERS // + // ------- // + + /// @dev Internal function to get the amount of tokens over the leftover amount. + function _getAmountOverLeftover(address token, uint256 leftoverAmount, address creditAccount) + internal + view + returns (uint256 amount) + { + amount = IERC20(token).balanceOf(creditAccount); + if (amount > leftoverAmount) { + amount -= leftoverAmount; + } else { + amount = 0; + } + } + + /// @dev Internal function to get the island tokens. + function _getIslandTokens(address island) internal view returns (address token0, address token1) { + token0 = IKodiakIsland(island).token0(); + token1 = IKodiakIsland(island).token1(); + } + + /// @dev Internal function to check if deposit is allowed for an island. + function _isDepositAllowed(address island) internal view returns (bool) { + return _islandStatus[island] == IslandStatus.ALLOWED; + } + + /// @dev Internal function to check if withdrawal is allowed for an island. + function _isWithdrawalAllowed(address island) internal view returns (bool) { + return _islandStatus[island] != IslandStatus.NOT_ALLOWED; + } + + function _isSwapAllowed(address island) internal view returns (bool) { + return _islandStatus[island] == IslandStatus.ALLOWED || _islandStatus[island] == IslandStatus.SWAP_AND_EXIT_ONLY; + } + + // ---- // + // DATA // + // ---- // + + /// @notice Returns the status of a batch of Kodiak islands. + function allowedIslands() public view returns (KodiakIslandStatus[] memory) { + address[] memory islands = _allowedIslands.values(); + + uint256 len = islands.length; + KodiakIslandStatus[] memory islandsStatus = new KodiakIslandStatus[](len); + for (uint256 i; i < len; ++i) { + islandsStatus[i].island = islands[i]; + islandsStatus[i].status = _islandStatus[islands[i]]; + } + return islandsStatus; + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, allowedIslands()); + } + + // ------------- // + // CONFIGURATION // + // ------------- // + + /// @notice Sets allowed status for a batch of Kodiak islands + function setIslandStatusBatch(KodiakIslandStatus[] calldata islands) external override configuratorOnly { + uint256 len = islands.length; + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _getIslandTokens(islands[i].island); + if (islands[i].status != IslandStatus.NOT_ALLOWED) { + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + _getMaskOrRevert(islands[i].island); + _allowedIslands.add(islands[i].island); + _islandStatus[islands[i].island] = islands[i].status; + } else { + _allowedIslands.remove(islands[i].island); + _islandStatus[islands[i].island] = IslandStatus.NOT_ALLOWED; + } + emit SetIslandStatus(islands[i].island, islands[i].status); + } + } +} diff --git a/contracts/adapters/lido/LidoV1.sol b/contracts/adapters/lido/LidoV1.sol index 0cdb4af5..20777277 100644 --- a/contracts/adapters/lido/LidoV1.sol +++ b/contracts/adapters/lido/LidoV1.sol @@ -1,18 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { - AP_TREASURY, - IAddressProviderV3, - NO_VERSION_CONTROL -} from "@gearbox-protocol/core-v3/contracts/interfaces/IAddressProviderV3.sol"; +import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; +import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IstETH} from "../../integrations/lido/IstETH.sol"; import {ILidoV1Adapter} from "../../interfaces/lido/ILidoV1Adapter.sol"; @@ -21,8 +17,8 @@ import {LidoV1Gateway} from "../../helpers/lido/LidoV1_WETHGateway.sol"; /// @title Lido V1 adapter /// @notice Implements logic for interacting with the Lido contract through the gateway contract LidoV1Adapter is AbstractAdapter, ILidoV1Adapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.LIDO_V1; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::LIDO_V1"; + uint256 public constant override version = 3_10; /// @notice stETH token address public immutable override stETH; @@ -30,12 +26,6 @@ contract LidoV1Adapter is AbstractAdapter, ILidoV1Adapter { /// @notice WETH token address public immutable override weth; - /// @notice Collateral token mask of WETH in the credit manager - uint256 public immutable override wethTokenMask; - - /// @notice Collateral token mask of stETH in the credit manager - uint256 public immutable override stETHTokenMask; - /// @notice Address of Gearbox treasury address public immutable override treasury; @@ -46,12 +36,13 @@ contract LidoV1Adapter is AbstractAdapter, ILidoV1Adapter { AbstractAdapter(_creditManager, _lidoGateway) // U:[LDO1-1] { stETH = LidoV1Gateway(payable(_lidoGateway)).stETH(); // U:[LDO1-1] - stETHTokenMask = _getMaskOrRevert(stETH); // U:[LDO1-1] - weth = LidoV1Gateway(payable(_lidoGateway)).weth(); // U:[LDO1-1] - wethTokenMask = _getMaskOrRevert(weth); // U:[LDO1-1] - treasury = IAddressProviderV3(addressProvider).getAddressOrRevert(AP_TREASURY, NO_VERSION_CONTROL); // U:[LDO1-1] + // We check that WETH and stETH are both valid collaterals + _getMaskOrRevert(stETH); // U:[LDO1-1] + _getMaskOrRevert(weth); // U:[LDO1-1] + + treasury = IPoolV3(ICreditManagerV3(creditManager).pool()).treasury(); // U:[LDO1-1] } /// @notice Stakes given amount of WETH in Lido via Gateway @@ -61,9 +52,10 @@ contract LidoV1Adapter is AbstractAdapter, ILidoV1Adapter { external override creditFacadeOnly // U:[LDO1-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _submit(amount, false); // U:[LDO1-3] + _submit(amount); // U:[LDO1-3] + return false; } /// @notice Stakes the entire balance of WETH in Lido via Gateway, except the specified amount @@ -72,29 +64,26 @@ contract LidoV1Adapter is AbstractAdapter, ILidoV1Adapter { external override creditFacadeOnly // U:[LDO1-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[LDO1-4] uint256 balance = IERC20(weth).balanceOf(creditAccount); // U:[LDO1-4] if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _submit(balance - leftoverAmount, leftoverAmount <= 1); // U:[LDO1-4] + _submit(balance - leftoverAmount); } } + return false; } /// @dev Internal implementation of `submit`. - /// - WETH is approved before the call because Gateway needs permission to transfer it - /// - stETH is enabled after the call - /// - WETH is only disabled when staking the entire balance - function _submit(uint256 amount, bool disableWETH) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(weth, type(uint256).max); // U:[LDO1-3,4] - _execute(abi.encodeCall(LidoV1Gateway.submit, (amount, treasury))); // U:[LDO1-3,4] - _approveToken(weth, 1); // U:[LDO1-3,4] - (tokensToEnable, tokensToDisable) = (stETHTokenMask, disableWETH ? wethTokenMask : 0); + function _submit(uint256 amount) internal { + _executeSwapSafeApprove(weth, abi.encodeCall(LidoV1Gateway.submit, (amount, treasury))); // U:[LDO1-3,4] + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, stETH, weth, treasury); } } diff --git a/contracts/adapters/lido/WstETHV1.sol b/contracts/adapters/lido/WstETHV1.sol index 2b9a3212..4b7970d6 100644 --- a/contracts/adapters/lido/WstETHV1.sol +++ b/contracts/adapters/lido/WstETHV1.sol @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IwstETH} from "../../integrations/lido/IwstETH.sol"; import {IwstETHV1Adapter} from "../../interfaces/lido/IwstETHV1Adapter.sol"; @@ -14,18 +13,12 @@ import {IwstETHV1Adapter} from "../../interfaces/lido/IwstETHV1Adapter.sol"; /// @title wstETH adapter /// @notice Implements logic for wrapping / unwrapping stETH contract WstETHV1Adapter is AbstractAdapter, IwstETHV1Adapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.LIDO_WSTETH_V1; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::LIDO_WSTETH_V1"; + uint256 public constant override version = 3_10; /// @notice Address of the stETH token address public immutable override stETH; - /// @notice Collateral token mask of stETH in the credit manager - uint256 public immutable override stETHTokenMask; - - /// @notice Collateral token mask of wstETH in the credit manager - uint256 public immutable override wstETHTokenMask; - /// @notice Constructor /// @param _creditManager Credit manager address /// @param _wstETH wstETH token address @@ -33,8 +26,8 @@ contract WstETHV1Adapter is AbstractAdapter, IwstETHV1Adapter { AbstractAdapter(_creditManager, _wstETH) // U:[LDO1W-1] { stETH = IwstETH(_wstETH).stETH(); // U:[LDO1W-1] - wstETHTokenMask = _getMaskOrRevert(_wstETH); // U:[LDO1W-1] - stETHTokenMask = _getMaskOrRevert(stETH); // U:[LDO1W-1] + _getMaskOrRevert(_wstETH); // U:[LDO1W-1] + _getMaskOrRevert(stETH); // U:[LDO1W-1] } // ---- // @@ -47,9 +40,10 @@ contract WstETHV1Adapter is AbstractAdapter, IwstETHV1Adapter { external override creditFacadeOnly // U:[LDO1W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _wrap(amount, false); // U:[LDO1W-3] + _wrap(amount); // U:[LDO1W-3] + return false; } /// @notice Wraps the entire balance of stETH into wstETH, except the specified amount @@ -58,30 +52,22 @@ contract WstETHV1Adapter is AbstractAdapter, IwstETHV1Adapter { external override creditFacadeOnly // U:[LDO1W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[LDO1W-4] uint256 balance = IERC20(stETH).balanceOf(creditAccount); // U:[LDO1W-4] if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _wrap(balance - leftoverAmount, leftoverAmount <= 1); // U:[LDO1W-4] + _wrap(balance - leftoverAmount); // U:[LDO1W-4] } } + return false; } /// @dev Internal implementation of `wrap` and `wrapDiff` - /// - stETH is approved before the call - /// - wstETH is enabled after the call - /// - stETH is only disabled if wrapping the entire balance - function _wrap(uint256 amount, bool disableStETH) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(stETH, type(uint256).max); // U:[LDO1W-3,4] - _execute(abi.encodeCall(IwstETH.wrap, (amount))); // U:[LDO1W-3,4] - _approveToken(stETH, 1); // U:[LDO1W-3,4] - (tokensToEnable, tokensToDisable) = (wstETHTokenMask, disableStETH ? stETHTokenMask : 0); + function _wrap(uint256 amount) internal { + _executeSwapSafeApprove(stETH, abi.encodeCall(IwstETH.wrap, (amount))); // U:[LDO1W-3,4] } // ------ // @@ -94,9 +80,10 @@ contract WstETHV1Adapter is AbstractAdapter, IwstETHV1Adapter { external override creditFacadeOnly // U:[LDO1W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _unwrap(amount, false); // U:[LDO1W-5] + _unwrap(amount); // U:[LDO1W-5] + return false; } /// @notice Unwraps the entire balance of wstETH to stETH, except the specified amount @@ -105,27 +92,26 @@ contract WstETHV1Adapter is AbstractAdapter, IwstETHV1Adapter { external override creditFacadeOnly // U:[LDO1W-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[LDO1W-6] uint256 balance = IERC20(targetContract).balanceOf(creditAccount); // U:[LDO1W-6] if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _unwrap(balance - leftoverAmount, leftoverAmount <= 1); // U:[LDO1W-6] + _unwrap(balance - leftoverAmount); // U:[LDO1W-6] } } + return false; } /// @dev Internal implementation of `unwrap` and `unwrapDiff` - /// - wstETH is not approved before the call - /// - stETH is enabled after the call - /// - wstETH is only disabled if unwrapping the entire balance - function _unwrap(uint256 amount, bool disableWstETH) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function _unwrap(uint256 amount) internal { _execute(abi.encodeCall(IwstETH.unwrap, (amount))); // U:[LDO1W-5,6] - (tokensToEnable, tokensToDisable) = (stETHTokenMask, disableWstETH ? wstETHTokenMask : 0); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, stETH); } } diff --git a/contracts/adapters/mellow/Mellow4626VaultAdapter.sol b/contracts/adapters/mellow/Mellow4626VaultAdapter.sol index 004e9886..8373431c 100644 --- a/contracts/adapters/mellow/Mellow4626VaultAdapter.sol +++ b/contracts/adapters/mellow/Mellow4626VaultAdapter.sol @@ -1,35 +1,42 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; import {ERC4626Adapter} from "../erc4626/ERC4626Adapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; +import {IMellow4626VaultAdapter} from "../../interfaces/mellow/IMellow4626VaultAdapter.sol"; +import {MellowWithdrawalPhantomToken} from "../../helpers/mellow/MellowWithdrawalPhantomToken.sol"; /// @title Mellow ERC4626 Vault adapter -/// @notice Implements logic allowing CAs to interact with a ERC4626 vaults, but with `withdraw` / `redeem` restricted, to avoid -/// CA's being exposed to Mellow's asynchronous withdrawals -contract Mellow4626VaultAdapter is ERC4626Adapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.MELLOW_ERC4626_VAULT; +/// @notice Implements logic allowing CAs to interact with Mellow ERC4626 MultiVaults +contract Mellow4626VaultAdapter is ERC4626Adapter, IMellow4626VaultAdapter { + uint256 public constant override(ERC4626Adapter, IVersion) version = 3_12; + bytes32 public constant override(ERC4626Adapter, IVersion) contractType = "ADAPTER::MELLOW_ERC4626_VAULT"; /// @notice Constructor /// @param _creditManager Credit manager address - /// @param _vault ERC4626 vault address - constructor(address _creditManager, address _vault) ERC4626Adapter(_creditManager, _vault) {} - - /// @dev For Mellow ERC4626 vaults all withdrawals revert to avoid CA's interacting with Mellow's delayed withdrawals - function withdraw(uint256, address, address) external view override creditFacadeOnly returns (uint256, uint256) { - revert NotImplementedException(); + /// @param _vault Mellow vault address + /// @param _stakedPhantomToken Staked phantom token address + constructor(address _creditManager, address _vault, address _stakedPhantomToken) + ERC4626Adapter(_creditManager, _vault, address(0)) + { + _getMaskOrRevert(_stakedPhantomToken); + address vault_ = MellowWithdrawalPhantomToken(_stakedPhantomToken).multiVault(); + if (vault_ != _vault) revert InvalidMultiVaultException(); } - /// @dev For Mellow ERC4626 vaults all withdrawals revert to avoid CA's interacting with Mellow's delayed withdrawals - function redeem(uint256, address, address) external view override creditFacadeOnly returns (uint256, uint256) { - revert NotImplementedException(); + /// @notice Requests a withdrawal from the Mellow vault for given amount of assets + /// @dev This function is overridden to return `true`, since the withdrawal phantom token should be priced with safe prices + function _withdraw(address creditAccount, uint256 assets) internal override returns (bool) { + super._withdraw(creditAccount, assets); + return true; } - /// @dev For Mellow ERC4626 vaults all withdrawals revert to avoid CA's interacting with Mellow's delayed withdrawals - function redeemDiff(uint256) external view override creditFacadeOnly returns (uint256, uint256) { - revert NotImplementedException(); + /// @notice Requests a withdrawal from the Mellow vault for given amount of shares + /// @dev This function is overridden to return `true`, since the withdrawal phantom token should be priced with safe prices + function _redeem(address creditAccount, uint256 shares) internal override returns (bool) { + super._redeem(creditAccount, shares); + return true; } } diff --git a/contracts/adapters/mellow/MellowClaimerAdapter.sol b/contracts/adapters/mellow/MellowClaimerAdapter.sol new file mode 100644 index 00000000..12d8c865 --- /dev/null +++ b/contracts/adapters/mellow/MellowClaimerAdapter.sol @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; +import {IMellowClaimer} from "../../integrations/mellow/IMellowClaimer.sol"; +import { + IMellowMultiVault, + IEigenLayerWithdrawalQueue, + Subvault, + MellowProtocol +} from "../../integrations/mellow/IMellowMultiVault.sol"; +import {IMellowClaimerAdapter, MellowMultiVaultStatus} from "../../interfaces/mellow/IMellowClaimerAdapter.sol"; +import {MellowWithdrawalPhantomToken} from "../../helpers/mellow/MellowWithdrawalPhantomToken.sol"; + +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +/// @title Mellow Claimer adapter +/// @notice Implements logic allowing CAs to interact with a Mellow Claimer, which allows them to claim mature withdrawals. +contract MellowClaimerAdapter is AbstractAdapter, IMellowClaimerAdapter { + using EnumerableSet for EnumerableSet.AddressSet; + + bytes32 public constant override contractType = "ADAPTER::MELLOW_CLAIMER"; + uint256 public constant override version = 3_10; + + /// @notice Maps a staked phantom token to the multiVault it represents + mapping(address stakedPhantomToken => address multiVault) public phantomTokenToMultiVault; + + /// @notice Set of allowed multiVaults + EnumerableSet.AddressSet private _allowedMultiVaults; + + /// @notice A buffer provided during claims to handle a situation where + /// the actual claimed amount is less than claimed amount reported by the vault, + /// which can happen due to rounding errors or stETH rebasing math. + uint256 public constant MAX_ASSETS_BUFFER = 100; + + constructor(address _creditManager, address _claimer) AbstractAdapter(_creditManager, _claimer) {} + + /// @notice Accepts transferred pending assets in the MultiVault for the credit account + /// @dev During a MultiVault rebalance, a withdrawal request may end up with some withdrawal indices + /// in a transferred state. In order to correctly reflect the in `pendingAssetsOf()`, these + /// transfers need to be accepted, so this call must always be coupled with a withdrawal request. + function multiAccept(address multiVault, uint256[] calldata subvaultIndices, uint256[][] calldata indices) + external + creditFacadeOnly + returns (bool) + { + if (!_allowedMultiVaults.contains(multiVault)) revert MultiVaultNotAllowedException(); + _execute( + abi.encodeCall(IMellowClaimer.multiAcceptAndClaim, (multiVault, subvaultIndices, indices, address(0), 0)) + ); + return false; + } + + /// @notice Accepts all transferred pending assets, and claims all claimable withdrawals. + function multiAcceptAndClaim( + address multiVault, + uint256[] calldata subvaultIndices, + uint256[][] calldata indices, + address, + uint256 maxAssets + ) external creditFacadeOnly returns (bool) { + if (!_allowedMultiVaults.contains(multiVault)) revert MultiVaultNotAllowedException(); + + address creditAccount = _creditAccount(); + _claim(multiVault, subvaultIndices, indices, creditAccount, maxAssets); + return false; + } + + /// @notice Claims mature withdrawals, represented by the corresponding phantom token + function withdrawPhantomToken(address stakedPhantomToken, uint256 amount) + external + creditFacadeOnly + returns (bool) + { + address multiVault = phantomTokenToMultiVault[stakedPhantomToken]; + + if (!_allowedMultiVaults.contains(multiVault)) revert MultiVaultNotAllowedException(); + + address creditAccount = _creditAccount(); + + (uint256[] memory subvaultIndices, uint256[][] memory indices) = + getUserSubvaultIndices(multiVault, creditAccount); + + _claim(multiVault, subvaultIndices, indices, creditAccount, amount); + + return false; + } + + /// @dev It's not possible to deposit from underlying (the vault's asset) into the withdrawal phantom token, + /// hence the function is not implemented. + function depositPhantomToken(address, uint256) external view override creditFacadeOnly returns (bool) { + revert NotImplementedException(); + } + + /// @dev Internal implementation for claims. + /// @dev Withdrawals from Mellow MultiVaults may return slightly less than maxAssets, due to rounding errors or + /// stETH rebasing math. A buffer of 100 units should be sufficient for most cases. + function _claim( + address multiVault, + uint256[] memory subvaultIndices, + uint256[][] memory indices, + address creditAccount, + uint256 maxAssets + ) internal { + address asset = IERC4626(multiVault).asset(); + + uint256 assetBalanceBefore = IERC20(asset).balanceOf(creditAccount); + _execute( + abi.encodeCall( + IMellowClaimer.multiAcceptAndClaim, (multiVault, subvaultIndices, indices, creditAccount, maxAssets) + ) + ); + + if (maxAssets < MAX_ASSETS_BUFFER) return; + maxAssets -= MAX_ASSETS_BUFFER; + + uint256 assetBalanceAfter = IERC20(asset).balanceOf(creditAccount); + if (assetBalanceAfter - assetBalanceBefore < maxAssets) { + revert InsufficientClaimedException(); + } + } + + /// @dev Helper function to get the subvault indices and relevant withdrawal indices that belong to a multiVault. + /// @dev If a withdrawal is requested during a rebalance, some withdrawals may arrive in a transferred state, since the vault + /// covers the user's withdrawal with its own pending withdrawals. + function getMultiVaultSubvaultIndices(address multiVault) + public + view + returns (uint256[] memory subvaultIndices, uint256[][] memory withdrawalIndices) + { + return getUserSubvaultIndices(multiVault, multiVault); + } + + /// @dev Helper function to get the subvault indices and relevant withdrawal indices that belong to a user. + function getUserSubvaultIndices(address multiVault, address user) + public + view + returns (uint256[] memory subvaultIndices, uint256[][] memory withdrawalIndices) + { + uint256 subvaultCount = IMellowMultiVault(multiVault).subvaultsCount(); + subvaultIndices = new uint256[](subvaultCount); + withdrawalIndices = new uint256[][](subvaultCount); + + for (uint256 i = 0; i < subvaultCount; i++) { + Subvault memory subvault = IMellowMultiVault(multiVault).subvaultAt(i); + subvaultIndices[i] = i; + if (subvault.protocol == MellowProtocol.EIGEN_LAYER) { + (, withdrawalIndices[i],) = IEigenLayerWithdrawalQueue(subvault.withdrawalQueue).getAccountData({ + account: user, + withdrawalsLimit: type(uint256).max, + withdrawalsOffset: 0, + transferredWithdrawalsLimit: 0, + transferredWithdrawalsOffset: 0 + }); + } + } + } + + /// @notice Returns the list of allowed multiVaults + function allowedMultiVaults() public view returns (address[] memory) { + return _allowedMultiVaults.values(); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, allowedMultiVaults()); + } + + /// @notice Sets the allowed status for a batch of multiVaults. + function setMultiVaultStatusBatch(MellowMultiVaultStatus[] calldata multiVaults) external configuratorOnly { + uint256 len = multiVaults.length; + for (uint256 i; i < len; ++i) { + if (multiVaults[i].allowed) { + address asset = IMellowMultiVault(multiVaults[i].multiVault).asset(); + + _getMaskOrRevert(multiVaults[i].stakedPhantomToken); + _getMaskOrRevert(asset); + + (address claimer, address underlying) = + MellowWithdrawalPhantomToken(multiVaults[i].stakedPhantomToken).getPhantomTokenInfo(); + + if (claimer != targetContract || underlying != asset) revert InvalidStakedPhantomTokenException(); + + address vault = MellowWithdrawalPhantomToken(multiVaults[i].stakedPhantomToken).multiVault(); + + if (vault != multiVaults[i].multiVault) revert InvalidMultiVaultException(); + _allowedMultiVaults.add(multiVaults[i].multiVault); + phantomTokenToMultiVault[multiVaults[i].stakedPhantomToken] = multiVaults[i].multiVault; + } else { + _allowedMultiVaults.remove(multiVaults[i].multiVault); + } + emit SetMultiVaultStatus(multiVaults[i].multiVault, multiVaults[i].allowed); + } + } +} diff --git a/contracts/adapters/mellow/MellowDVVAdapter.sol b/contracts/adapters/mellow/MellowDVVAdapter.sol new file mode 100644 index 00000000..87b8e39e --- /dev/null +++ b/contracts/adapters/mellow/MellowDVVAdapter.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {IStateSerializer} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IStateSerializer.sol"; +import {ERC4626Adapter} from "../erc4626/ERC4626Adapter.sol"; +import {IERC4626Adapter} from "../../interfaces/erc4626/IERC4626Adapter.sol"; +import {IMellowSimpleLRTVault} from "../../integrations/mellow/IMellowSimpleLRTVault.sol"; +import {IMellow4626VaultAdapter} from "../../interfaces/mellow/IMellow4626VaultAdapter.sol"; + +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +/// @title Mellow DVV vault adapter +/// @notice Implements logic allowing CAs to interact with Mellow DVV vault +contract MellowDVVAdapter is ERC4626Adapter { + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ADAPTER::MELLOW_DVV"; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _vault ERC4626 vault address + constructor(address _creditManager, address _vault) ERC4626Adapter(_creditManager, _vault, address(0)) {} + + function _deposit(address, uint256) internal pure override returns (bool) { + revert NotImplementedException(); + } + + function _mint(address, uint256) internal pure override returns (bool) { + revert NotImplementedException(); + } +} diff --git a/contracts/adapters/mellow/MellowVaultAdapter.sol b/contracts/adapters/mellow/MellowVaultAdapter.sol index 923937ea..9928b4eb 100644 --- a/contracts/adapters/mellow/MellowVaultAdapter.sol +++ b/contracts/adapters/mellow/MellowVaultAdapter.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IMellowVaultAdapter, MellowUnderlyingStatus} from "../../interfaces/mellow/IMellowVaultAdapter.sol"; import {IMellowVault} from "../../integrations/mellow/IMellowVault.sol"; @@ -15,20 +15,19 @@ import {IMellowVault} from "../../integrations/mellow/IMellowVault.sol"; /// @title Mellow vault adapter /// @notice Implements logic for interacting with the Mellow vault contract (deposits only) contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.MELLOW_LRT_VAULT; - uint16 public constant override _gearboxAdapterVersion = 3_00; + using EnumerableSet for EnumerableSet.AddressSet; - /// @notice Mapping from underlying address to its status - mapping(address => bool) public isUnderlyingAllowed; + bytes32 public constant override contractType = "ADAPTER::MELLOW_LRT_VAULT"; + uint256 public constant override version = 3_10; - /// @notice Collateral token mask of the vault token - uint256 public immutable vaultTokenMask; + /// @dev Set of allowed underlying addresses + EnumerableSet.AddressSet internal _allowedUnderlyings; /// @notice Constructor /// @param _creditManager Credit manager address /// @param _mellowVault Mellow vault address constructor(address _creditManager, address _mellowVault) AbstractAdapter(_creditManager, _mellowVault) { - vaultTokenMask = _getMaskOrRevert(_mellowVault); // U:[MEL-1] + _getMaskOrRevert(_mellowVault); // U:[MEL-1] } /// @notice Deposits specified amounts of tokens into the vault in exchange for LP tokens. @@ -39,7 +38,7 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { function deposit(address, uint256[] memory amounts, uint256 minLpAmount, uint256 deadline) external creditFacadeOnly // U:[MEL-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); @@ -50,7 +49,7 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { if (amounts.length != len) revert IncorrectArrayLengthException(); // U:[MEL-3] for (uint256 i = 0; i < len;) { - if (!isUnderlyingAllowed[underlyings[i]]) { + if (!_allowedUnderlyings.contains(underlyings[i])) { revert UnderlyingNotAllowedException(underlyings[i]); // U:[MEL-3] } @@ -63,7 +62,7 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { _execute(abi.encodeCall(IMellowVault.deposit, (creditAccount, amounts, minLpAmount, deadline))); // U:[MEL-3] _approveAssets(underlyings, amounts, 1); - (tokensToEnable, tokensToDisable) = (vaultTokenMask, 0); + return true; } /// @notice Deposits a specififed amount of one underlying into the vault in exchange for LP tokens. @@ -74,13 +73,13 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { function depositOneAsset(address asset, uint256 amount, uint256 minLpAmount, uint256 deadline) external creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - if (!isUnderlyingAllowed[asset]) revert UnderlyingNotAllowedException(asset); // U:[MEL-4] + if (!_allowedUnderlyings.contains(asset)) revert UnderlyingNotAllowedException(asset); // U:[MEL-4] address creditAccount = _creditAccount(); - (tokensToEnable, tokensToDisable) = _depositOneAsset(creditAccount, asset, amount, minLpAmount, deadline, false); // U:[MEL-4] + return _depositOneAsset(creditAccount, asset, amount, minLpAmount, deadline); // U:[MEL-4] } /// @notice Deposits the entire balance of one underlying, except the specified amount, into the vault in exchange for LP tokens. @@ -91,22 +90,21 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { function depositOneAssetDiff(address asset, uint256 leftoverAmount, uint256 rateMinRAY, uint256 deadline) external creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - if (!isUnderlyingAllowed[asset]) revert UnderlyingNotAllowedException(asset); // U:[MEL-5] + if (!_allowedUnderlyings.contains(asset)) revert UnderlyingNotAllowedException(asset); // U:[MEL-5] address creditAccount = _creditAccount(); uint256 amount = IERC20(asset).balanceOf(creditAccount); - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount = amount - leftoverAmount; } - (tokensToEnable, tokensToDisable) = - _depositOneAsset(creditAccount, asset, amount, amount * rateMinRAY / RAY, deadline, leftoverAmount <= 1); // U:[MEL-5] + return _depositOneAsset(creditAccount, asset, amount, amount * rateMinRAY / RAY, deadline); // U:[MEL-5] } /// @dev Internal implementation for `depositOneAsset` and `depositOneAssetDiff` @@ -115,9 +113,8 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { address asset, uint256 amount, uint256 minLpAmount, - uint256 deadline, - bool disableTokenIn - ) internal returns (uint256 tokensToEnable, uint256 tokensToDisable) { + uint256 deadline + ) internal returns (bool) { address[] memory underlyings = IMellowVault(targetContract).underlyingTokens(); uint256 len = underlyings.length; @@ -139,7 +136,7 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { _approveToken(asset, type(uint256).max); _execute(abi.encodeCall(IMellowVault.deposit, (creditAccount, amounts, minLpAmount, deadline))); // U:[MEL-4,5] _approveToken(asset, 1); - (tokensToEnable, tokensToDisable) = (vaultTokenMask, disableTokenIn ? _getMaskOrRevert(asset) : 0); + return true; } /// @dev Internal function that changes approval for a batch of assets @@ -153,6 +150,20 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { } } + // ---- // + // DATA // + // ---- // + + /// @notice Returns the list of allowed underlyings + function allowedUnderlyings() public view returns (address[] memory) { + return _allowedUnderlyings.values(); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, allowedUnderlyings()); + } + // ------------- // // CONFIGURATION // // ------------- // @@ -164,11 +175,14 @@ contract MellowVaultAdapter is AbstractAdapter, IMellowVaultAdapter { configuratorOnly // U:[MEL-6] { uint256 len = underlyings.length; - unchecked { - for (uint256 i; i < len; ++i) { - isUnderlyingAllowed[underlyings[i].underlying] = underlyings[i].allowed; // U:[MEL-6] - emit SetUnderlyingStatus(underlyings[i].underlying, underlyings[i].allowed); // U:[MEL-6] + for (uint256 i; i < len; ++i) { + if (underlyings[i].allowed) { + _getMaskOrRevert(underlyings[i].underlying); + _allowedUnderlyings.add(underlyings[i].underlying); + } else { + _allowedUnderlyings.remove(underlyings[i].underlying); } + emit SetUnderlyingStatus(underlyings[i].underlying, underlyings[i].allowed); // U:[MEL-6] } } } diff --git a/contracts/adapters/mellow/MellowWrapperAdapter.sol b/contracts/adapters/mellow/MellowWrapperAdapter.sol new file mode 100644 index 00000000..e3c92842 --- /dev/null +++ b/contracts/adapters/mellow/MellowWrapperAdapter.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {IMellowWrapperAdapter, MellowVaultStatus} from "../../interfaces/mellow/IMellowWrapperAdapter.sol"; +import {IMellowWrapper} from "../../integrations/mellow/IMellowWrapper.sol"; + +/// @title Mellow Wrapper adapter +/// @notice Implements logic allowing CAs to interact with Mellow Wrapper +contract MellowWrapperAdapter is AbstractAdapter, IMellowWrapperAdapter { + using EnumerableSet for EnumerableSet.AddressSet; + + uint256 public constant version = 3_10; + bytes32 public constant contractType = "ADAPTER::MELLOW_WRAPPER"; + + address public immutable referral; + + address public immutable weth; + + EnumerableSet.AddressSet private _allowedVaults; + + constructor(address _creditManager, address _mellowWrapper, address _referral) + AbstractAdapter(_creditManager, _mellowWrapper) + { + referral = _referral; + weth = IMellowWrapper(_mellowWrapper).WETH(); + + _getMaskOrRevert(weth); + } + + /// @notice Deposits an amount of WETH into a vault + /// @param amount The amount of WETH to deposit + /// @param vault The vault to deposit into + /// @notice `depositToken`, `receiver`, and `referral` are ignored, as these parameters are fixed + function deposit(address, uint256 amount, address vault, address, address) + external + creditFacadeOnly + returns (bool) + { + if (!_allowedVaults.contains(vault)) revert VaultNotAllowedException(vault); + + address creditAccount = _creditAccount(); + + _deposit(creditAccount, vault, amount); + + return false; + } + + /// @notice Deposits the entire balance of WETH into a vault, except the specified amount + /// @param leftoverAmount Amount of WETH to leave on the Credit Account + /// @param vault The vault to deposit into + function depositDiff(uint256 leftoverAmount, address vault) external creditFacadeOnly returns (bool) { + if (!_allowedVaults.contains(vault)) revert VaultNotAllowedException(vault); + + address creditAccount = _creditAccount(); + + uint256 amount = IERC20(weth).balanceOf(creditAccount); + + if (amount <= leftoverAmount) return false; + + unchecked { + amount = amount - leftoverAmount; + } + + _deposit(creditAccount, vault, amount); + + return false; + } + + /// @dev Internal implementation for `deposit` and `depositDiff` + function _deposit(address creditAccount, address vault, uint256 amount) internal { + _executeSwapSafeApprove( + weth, abi.encodeCall(IMellowWrapper.deposit, (weth, amount, vault, creditAccount, referral)) + ); + } + + // ---- // + // DATA // + // ---- // + + /// @notice Returns the list of allowed vaults + function allowedVaults() public view returns (address[] memory) { + return _allowedVaults.values(); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, allowedVaults()); + } + + // ------------- // + // CONFIGURATION // + // ------------- // + + /// @notice Changes the allowed status of several vaults + function setVaultStatusBatch(MellowVaultStatus[] calldata vaults) external configuratorOnly { + uint256 len = vaults.length; + for (uint256 i; i < len; ++i) { + if (vaults[i].allowed) { + _getMaskOrRevert(vaults[i].vault); + _allowedVaults.add(vaults[i].vault); + } else { + _allowedVaults.remove(vaults[i].vault); + } + emit SetVaultStatus(vaults[i].vault, vaults[i].allowed); + } + } +} diff --git a/contracts/adapters/pendle/PendleRouterAdapter.sol b/contracts/adapters/pendle/PendleRouterAdapter.sol index 1a731b73..15e92b66 100644 --- a/contracts/adapters/pendle/PendleRouterAdapter.sol +++ b/contracts/adapters/pendle/PendleRouterAdapter.sol @@ -1,14 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import { IPendleRouterAdapter, @@ -35,8 +34,8 @@ import { contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { using EnumerableSet for EnumerableSet.Bytes32Set; - AdapterType public constant override _gearboxAdapterType = AdapterType.PENDLE_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::PENDLE_ROUTER"; + uint256 public constant override version = 3_10; /// @notice Mapping from (market, inputToken, pendleToken) to whether swaps are allowed, and which directions mapping(address => mapping(address => mapping(address => PendleStatus))) public isPairAllowed; @@ -63,14 +62,6 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { /// @param minPtOut Minimal amount of PT token out /// @param guessPtOut Search boundaries to save gas on PT amount calculation /// @param input Parameters of the input tokens - /// * `tokenIn` - token to swap into PT - /// * `netTokenIn` - amount of tokens to swap - /// * `tokenMintSy` - token used to mint SY. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be equal to `tokenIn` - /// * `pendleSwap` - address of the swap aggregator. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be `address(0)`. - /// * `swapData` - off-chain data for external routing. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be an empty struct /// @notice `receiver` and `limit` are ignored, since the recipient is always the Credit Account, /// and Gearbox does not use Pendle's limit orders function swapExactTokenForPt( @@ -83,7 +74,7 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { ) external creditFacadeOnly // U:[PEND-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool useSafePrices) { (, address pt,) = IPendleMarket(market).readTokens(); @@ -101,14 +92,14 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { input_m.tokenMintSy = input.tokenIn; } - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( input_m.tokenIn, - pt, abi.encodeCall( IPendleRouter.swapExactTokenForPt, (creditAccount, market, minPtOut, guessPtOut, input_m, limit) - ), - false + ) ); // U:[PEND-3] + + useSafePrices = true; } /// @notice Swaps the entire balance of input token into PT, except the specified amount @@ -116,8 +107,6 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { /// @param minRateRAY Minimal exchange rate of input to PT, in 1e27 format /// @param guessPtOut Search boundaries to save gas on PT amount calculation /// @param diffInput Input token parameters - /// * `tokenIn` - token to swap into PT - /// * `leftoverTokenIn` - amount of input token to leave on the account function swapDiffTokenForPt( address market, uint256 minRateRAY, @@ -126,7 +115,7 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { ) external creditFacadeOnly // U:[PEND-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool useSafePrices) { (, address pt,) = IPendleMarket(market).readTokens(); @@ -135,7 +124,7 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { address creditAccount = _creditAccount(); uint256 amount = IERC20(diffInput.tokenIn).balanceOf(creditAccount); - if (amount <= diffInput.leftoverTokenIn) return (0, 0); + if (amount <= diffInput.leftoverTokenIn) return false; unchecked { amount -= diffInput.leftoverTokenIn; @@ -148,29 +137,21 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { LimitOrderData memory limit; - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( diffInput.tokenIn, - pt, abi.encodeCall( IPendleRouter.swapExactTokenForPt, (creditAccount, market, amount * minRateRAY / RAY, guessPtOut, input, limit) - ), - diffInput.leftoverTokenIn <= 1 + ) ); // U:[PEND-4] + + useSafePrices = true; } /// @notice Swaps a specified amount of PT for token /// @param market Address of the market to swap in /// @param exactPtIn Amount of PT to swap - /// @param output Output token params: - /// * `tokenOut` - token to swap PT into - /// * `minTokenOut` - the minimal amount of token to receive - /// * `tokenRedeemSy` - token received after redeeming SY. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be equal to `tokenOut` - /// * `pendleSwap` - address of the swap aggregator. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be `address(0)`. - /// * `swapData` - off-chain data for external routing. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be an empty struct + /// @param output Output token params /// @notice `receiver` and `limit` are ignored, since the recipient is always the Credit Account, /// and Gearbox does not use Pendle's limit orders function swapExactPtForToken( @@ -182,7 +163,7 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { ) external creditFacadeOnly // U:[PEND-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool useSafePrices) { (, address pt,) = IPendleMarket(market).readTokens(); @@ -200,24 +181,21 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { output_m.minTokenOut = output.minTokenOut; } - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - pt, - output_m.tokenOut, - abi.encodeCall(IPendleRouter.swapExactPtForToken, (creditAccount, market, exactPtIn, output_m, limit)), - false + _executeSwapSafeApprove( + pt, abi.encodeCall(IPendleRouter.swapExactPtForToken, (creditAccount, market, exactPtIn, output_m, limit)) ); // U:[PEND-5] + + useSafePrices = true; } /// @notice Swaps the entire balance of PT into input token, except the specified amount /// @param market Address of the market to swap in /// @param leftoverPt Amount of PT to leave on the Credit Account - /// @param diffOutput Output token parameters: - /// * `tokenOut` - token to swap PT into - /// * `minRateRAY` - minimal exchange rate of PT into the output token + /// @param diffOutput Output token parameters function swapDiffPtForToken(address market, uint256 leftoverPt, TokenDiffOutput calldata diffOutput) external creditFacadeOnly // U:[PEND-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool useSafePrices) { (, address pt,) = IPendleMarket(market).readTokens(); @@ -228,7 +206,7 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { address creditAccount = _creditAccount(); uint256 amount = IERC20(pt).balanceOf(creditAccount); - if (amount <= leftoverPt) return (0, 0); + if (amount <= leftoverPt) return false; unchecked { amount -= leftoverPt; @@ -241,33 +219,24 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { LimitOrderData memory limit; - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - pt, - diffOutput.tokenOut, - abi.encodeCall(IPendleRouter.swapExactPtForToken, (creditAccount, market, amount, output, limit)), - leftoverPt <= 1 + _executeSwapSafeApprove( + pt, abi.encodeCall(IPendleRouter.swapExactPtForToken, (creditAccount, market, amount, output, limit)) ); // U:[PEND-6] + + useSafePrices = true; } /// @notice Redeems a specified amount of PT tokens into underlying after expiry /// @param yt YT token associated to PT /// @param netPyIn Amount of PT token to redeem - /// @param output Output token params: - /// * `tokenOut` - token to swap PT into - /// * `minTokenOut` - the minimal amount of token to receive - /// * `tokenRedeemSy` - token received after redeeming SY. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be equal to `tokenOut` - /// * `pendleSwap` - address of the swap aggregator. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be `address(0)`. - /// * `swapData` - off-chain data for external routing. Since the adapter does not use PendleRouter's external routing features, - /// this is always enforced to be an empty struct + /// @param output Output token params /// @notice `receiver` is ignored, since the recipient is always the Credit Account /// @notice Before expiry PT redemption also spends a corresponding amount of YT. To avoid the CA interacting /// with potentially non-collateral YT tokens, this function is only executable after expiry function redeemPyToToken(address, address yt, uint256 netPyIn, TokenOutput calldata output) external creditFacadeOnly // U:[PEND-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool useSafePrices) { address pt = IYToken(yt).PT(); @@ -288,26 +257,23 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { output_m.minTokenOut = output.minTokenOut; } - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - pt, - output_m.tokenOut, - abi.encodeCall(IPendleRouter.redeemPyToToken, (creditAccount, yt, netPyIn, output_m)), - false + _executeSwapSafeApprove( + pt, abi.encodeCall(IPendleRouter.redeemPyToToken, (creditAccount, yt, netPyIn, output_m)) ); // U:[PEND-7] + + useSafePrices = true; } /// @notice Redeems the entire balance of PT token into underlying after expiry, except the specified amount /// @param yt YT token associated to PT /// @param leftoverPt Amount of PT to keep on the account - /// @param diffOutput Output token parameters: - /// * `tokenOut` - token to swap PT into - /// * `minRateRAY` - minimal exchange rate of PT into the output token + /// @param diffOutput Output token parameters /// @notice Before expiry PT redemption also spends a corresponding amount of YT. To avoid the CA interacting /// with potentially non-collateral YT tokens, this function is only executable after expiry function redeemDiffPyToToken(address yt, uint256 leftoverPt, TokenDiffOutput calldata diffOutput) external creditFacadeOnly // U:[PEND-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool useSafePrices) { address pt = IYToken(yt).PT(); @@ -321,7 +287,7 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { address creditAccount = _creditAccount(); uint256 amount = IERC20(pt).balanceOf(creditAccount); - if (amount <= leftoverPt) return (0, 0); + if (amount <= leftoverPt) return false; unchecked { amount -= leftoverPt; @@ -332,20 +298,17 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { output.minTokenOut = amount * diffOutput.minRateRAY / RAY; output.tokenRedeemSy = diffOutput.tokenOut; - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - pt, - diffOutput.tokenOut, - abi.encodeCall(IPendleRouter.redeemPyToToken, (creditAccount, yt, amount, output)), - leftoverPt <= 1 - ); // U:[PEND-8] + _executeSwapSafeApprove(pt, abi.encodeCall(IPendleRouter.redeemPyToToken, (creditAccount, yt, amount, output))); // U:[PEND-8] + + useSafePrices = true; } - // ------------- // - // CONFIGURATION // - // ------------- // + // ---- // + // DATA // + // ---- // - /// @notice Return the list of all markets that were ever allowed in this adapter - function getAllowedPairs() external view override returns (PendlePairStatus[] memory pairs) { + /// @notice Return the list of all pairs currently allowed in the adapter + function getAllowedPairs() public view returns (PendlePairStatus[] memory pairs) { bytes32[] memory allowedHashes = _allowedPairHashes.values(); uint256 len = allowedHashes.length; @@ -360,6 +323,15 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { } } + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, getAllowedPairs()); + } + + // ------------- // + // CONFIGURATION // + // ------------- // + /// @notice Sets the allowed status of several (market, inputToken, pendleToken) tuples function setPairStatusBatch(PendlePairStatus[] calldata pairs) external @@ -367,23 +339,23 @@ contract PendleRouterAdapter is AbstractAdapter, IPendleRouterAdapter { configuratorOnly // U:[PEND-9] { uint256 len = pairs.length; - unchecked { - for (uint256 i; i < len; ++i) { - isPairAllowed[pairs[i].market][pairs[i].inputToken][pairs[i].pendleToken] = pairs[i].status; // U:[PEND-9] - (, address pt,) = IPendleMarket(pairs[i].market).readTokens(); - ptToMarket[pt] = pairs[i].market; - bytes32 pairHash = keccak256(abi.encode(pairs[i].market, pairs[i].inputToken, pairs[i].pendleToken)); - if (pairs[i].status != PendleStatus.NOT_ALLOWED) { - _allowedPairHashes.add(pairHash); // U:[PEND-9] - isRedemptionAllowed[pairs[i].inputToken][pairs[i].pendleToken] = true; // U:[PEND-9] - } else { - _allowedPairHashes.remove(pairHash); // U:[PEND-9] - isRedemptionAllowed[pairs[i].inputToken][pairs[i].pendleToken] = false; // U:[PEND-9] - } - _hashToPendlePair[pairHash] = pairs[i]; // U:[PEND-9] - - emit SetPairStatus(pairs[i].market, pairs[i].inputToken, pairs[i].pendleToken, pairs[i].status); // U:[PEND-9] + for (uint256 i; i < len; ++i) { + isPairAllowed[pairs[i].market][pairs[i].inputToken][pairs[i].pendleToken] = pairs[i].status; // U:[PEND-9] + (, address pt,) = IPendleMarket(pairs[i].market).readTokens(); + ptToMarket[pt] = pairs[i].market; + bytes32 pairHash = keccak256(abi.encode(pairs[i].market, pairs[i].inputToken, pairs[i].pendleToken)); + if (pairs[i].status != PendleStatus.NOT_ALLOWED) { + _allowedPairHashes.add(pairHash); // U:[PEND-9] + isRedemptionAllowed[pairs[i].inputToken][pairs[i].pendleToken] = true; // U:[PEND-9] + _getMaskOrRevert(pairs[i].inputToken); + _getMaskOrRevert(pairs[i].pendleToken); + } else { + _allowedPairHashes.remove(pairHash); // U:[PEND-9] + isRedemptionAllowed[pairs[i].inputToken][pairs[i].pendleToken] = false; // U:[PEND-9] } + _hashToPendlePair[pairHash] = pairs[i]; // U:[PEND-9] + + emit SetPairStatus(pairs[i].market, pairs[i].inputToken, pairs[i].pendleToken, pairs[i].status); // U:[PEND-9] } } } diff --git a/contracts/adapters/sky/DaiUsdsAdapter.sol b/contracts/adapters/sky/DaiUsdsAdapter.sol index 91a44cc7..2876da35 100644 --- a/contracts/adapters/sky/DaiUsdsAdapter.sol +++ b/contracts/adapters/sky/DaiUsdsAdapter.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; + import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IDaiUsds} from "../../integrations/sky/IDaiUsds.sol"; import {IDaiUsdsAdapter} from "../../interfaces/sky/IDaiUsdsAdapter.sol"; @@ -14,8 +15,8 @@ import {IDaiUsdsAdapter} from "../../interfaces/sky/IDaiUsdsAdapter.sol"; /// @title DaiUsds Adapter /// @notice Implements logic for interacting with the DAI / USDS wrapping contract contract DaiUsdsAdapter is AbstractAdapter, IDaiUsdsAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.DAI_USDS_EXCHANGE; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::DAI_USDS_EXCHANGE"; + uint256 public constant override version = 3_10; /// @notice DAI token address public immutable override dai; @@ -23,12 +24,6 @@ contract DaiUsdsAdapter is AbstractAdapter, IDaiUsdsAdapter { /// @notice USDS token address public immutable override usds; - /// @notice Collateral token mask of DAI in the credit manager - uint256 public immutable override daiMask; - - /// @notice Collateral token mask of USDS in the credit manager - uint256 public immutable override usdsMask; - /// @notice Constructor /// @param _creditManager Credit manager address /// @param _targetContract DAI / USDS exchange contract @@ -36,93 +31,69 @@ contract DaiUsdsAdapter is AbstractAdapter, IDaiUsdsAdapter { dai = IDaiUsds(_targetContract).dai(); usds = IDaiUsds(_targetContract).usds(); - daiMask = _getMaskOrRevert(dai); - usdsMask = _getMaskOrRevert(usds); + // We check that DAI and USDS are both valid collaterals + _getMaskOrRevert(dai); + _getMaskOrRevert(usds); } /// @notice Swaps given amount of DAI to USDS /// @param wad Amount of DAI to swap /// @dev `usr` (recipient) is ignored as it is always the Credit Account - function daiToUsds(address, uint256 wad) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function daiToUsds(address, uint256 wad) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); - (tokensToEnable, tokensToDisable) = _daiToUsds(creditAccount, wad, false); + _daiToUsds(creditAccount, wad); + return false; } /// @notice Swaps the entire balance of DAI to USDS, except the specified amount /// @param leftoverAmount Amount of DAI to keep on the account - function daiToUsdsDiff(uint256 leftoverAmount) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function daiToUsdsDiff(uint256 leftoverAmount) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); uint256 balance = IERC20(dai).balanceOf(creditAccount); if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = - _daiToUsds(creditAccount, balance - leftoverAmount, leftoverAmount <= 1); + _daiToUsds(creditAccount, balance - leftoverAmount); } } + return false; } /// @dev Internal implementation for `daiToUsds` and `daiToUsdsDiff` - function _daiToUsds(address creditAccount, uint256 amount, bool disableDai) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(dai, type(uint256).max); - _execute(abi.encodeCall(IDaiUsds.daiToUsds, (creditAccount, amount))); - _approveToken(dai, 1); - (tokensToEnable, tokensToDisable) = (usdsMask, disableDai ? daiMask : 0); + function _daiToUsds(address creditAccount, uint256 amount) internal { + _executeSwapSafeApprove(dai, abi.encodeCall(IDaiUsds.daiToUsds, (creditAccount, amount))); } /// @notice Swaps given amount of USDS to DAI /// @param wad Amount of USDS to swap /// @dev `usr` (recipient) is ignored as it is always the Credit Account - function usdsToDai(address, uint256 wad) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function usdsToDai(address, uint256 wad) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); - (tokensToEnable, tokensToDisable) = _usdsToDai(creditAccount, wad, false); + _usdsToDai(creditAccount, wad); + return false; } /// @notice Swaps the entire balance of USDS to DAI, except the specified amount /// @param leftoverAmount Amount of USDS to keep on the account - function usdsToDaiDiff(uint256 leftoverAmount) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function usdsToDaiDiff(uint256 leftoverAmount) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); uint256 balance = IERC20(usds).balanceOf(creditAccount); if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = - _usdsToDai(creditAccount, balance - leftoverAmount, leftoverAmount <= 1); + _usdsToDai(creditAccount, balance - leftoverAmount); } } + return false; } /// @dev Internal implementation for `usdsToDai` and `usdsToDaiDiff` - function _usdsToDai(address creditAccount, uint256 amount, bool disableUsds) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(usds, type(uint256).max); - _execute(abi.encodeCall(IDaiUsds.usdsToDai, (creditAccount, amount))); - _approveToken(usds, 1); - (tokensToEnable, tokensToDisable) = (daiMask, disableUsds ? usdsMask : 0); + function _usdsToDai(address creditAccount, uint256 amount) internal { + _executeSwapSafeApprove(usds, abi.encodeCall(IDaiUsds.usdsToDai, (creditAccount, amount))); + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, dai, usds); } } diff --git a/contracts/adapters/sky/StakingRewardsAdapter.sol b/contracts/adapters/sky/StakingRewardsAdapter.sol index a7566fdf..7a2a12e2 100644 --- a/contracts/adapters/sky/StakingRewardsAdapter.sol +++ b/contracts/adapters/sky/StakingRewardsAdapter.sol @@ -1,21 +1,25 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {BitMask} from "@gearbox-protocol/core-v3/contracts/libraries/BitMask.sol"; import {IStakingRewards} from "../../integrations/sky/IStakingRewards.sol"; +import {IStakingRewardsReferral} from "../../integrations/sky/IStakingRewards.sol"; import {IStakingRewardsAdapter} from "../../interfaces/sky/IStakingRewardsAdapter.sol"; /// @title Staking Rewards adapter -/// @notice Implements logic for interacting with StakingRewards contract +/// @notice Implements logic for interacting with a generic StakingRewards contract contract StakingRewardsAdapter is AbstractAdapter, IStakingRewardsAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.STAKING_REWARDS; - uint16 public constant override _gearboxAdapterVersion = 3_00; + using BitMask for uint256; + + bytes32 public constant override contractType = "ADAPTER::STAKING_REWARDS"; + uint256 public constant override version = 3_12; /// @notice Address of the staking token address public immutable override stakingToken; @@ -26,29 +30,27 @@ contract StakingRewardsAdapter is AbstractAdapter, IStakingRewardsAdapter { /// @notice Address of a phantom token representing account's stake in the reward pool address public immutable override stakedPhantomToken; - /// @notice Collateral token mask of staking token in the credit manager - uint256 public immutable override stakingTokenMask; - - /// @notice Collateral token mask of rewards token in the credit manager - uint256 public immutable override rewardsTokenMask; - - /// @notice Collateral token mask of staked phantom token in the credit manager - uint256 public immutable override stakedPhantomTokenMask; + /// @notice Referral code for the protocol + uint16 public immutable override referral; /// @notice Constructor /// @param _creditManager Credit manager address /// @param _stakingRewards StakingRewards contract address /// @param _stakedPhantomToken Staked phantom token address - constructor(address _creditManager, address _stakingRewards, address _stakedPhantomToken) + /// @param _referral Referral code + constructor(address _creditManager, address _stakingRewards, address _stakedPhantomToken, uint16 _referral) AbstractAdapter(_creditManager, _stakingRewards) { stakingToken = IStakingRewards(_stakingRewards).stakingToken(); + _getMaskOrRevert(stakingToken); + rewardsToken = IStakingRewards(_stakingRewards).rewardsToken(); + _getMaskOrRevert(rewardsToken); + stakedPhantomToken = _stakedPhantomToken; + _getMaskOrRevert(stakedPhantomToken); - stakingTokenMask = _getMaskOrRevert(stakingToken); - rewardsTokenMask = _getMaskOrRevert(rewardsToken); - stakedPhantomTokenMask = _getMaskOrRevert(stakedPhantomToken); + referral = _referral; } // ----- // @@ -57,43 +59,40 @@ contract StakingRewardsAdapter is AbstractAdapter, IStakingRewardsAdapter { /// @notice Stakes tokens in the StakingRewards contract /// @param amount Amount of tokens to stake - function stake(uint256 amount) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _stake(amount, false); + function stake(uint256 amount) external override creditFacadeOnly returns (bool) { + _stake(amount); + return false; } /// @notice Stakes the entire balance of staking token, except the specified amount /// @param leftoverAmount Amount of staking token to keep on the account - function stakeDiff(uint256 leftoverAmount) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function stakeDiff(uint256 leftoverAmount) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); uint256 balance = IERC20(stakingToken).balanceOf(creditAccount); if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _stake(balance - leftoverAmount, leftoverAmount <= 1); + _stake(balance - leftoverAmount); } } + return false; } - /// @dev Internal implementation of `stake` and `stakeDiff` - function _stake(uint256 amount, bool disableStakingToken) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(stakingToken, type(uint256).max); - _execute(abi.encodeCall(IStakingRewards.stake, (amount))); - _approveToken(stakingToken, 1); - (tokensToEnable, tokensToDisable) = (stakedPhantomTokenMask, disableStakingToken ? stakingTokenMask : 0); + /// @dev Stakes tokens in the StakingRewards contract. Uses a special signature if the referral code is not 0. + function _stake(uint256 amount) internal { + if (referral == 0) { + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IStakingRewards.stake, (amount))); + } else { + _executeSwapSafeApprove(stakingToken, abi.encodeCall(IStakingRewardsReferral.stake, (amount, referral))); + } + } + + /// @notice Deposits into a phantom token + function depositPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); + _stake(amount); + return false; } // ----- // @@ -101,9 +100,9 @@ contract StakingRewardsAdapter is AbstractAdapter, IStakingRewardsAdapter { // ----- // /// @notice Claims rewards on the current position - function getReward() external override creditFacadeOnly returns (uint256 tokensToEnable, uint256 tokensToDisable) { + function getReward() external override creditFacadeOnly returns (bool) { _execute(abi.encodeCall(IStakingRewards.getReward, ())); - (tokensToEnable, tokensToDisable) = (rewardsTokenMask, 0); + return false; } // -------- // @@ -112,40 +111,36 @@ contract StakingRewardsAdapter is AbstractAdapter, IStakingRewardsAdapter { /// @notice Withdraws staked tokens from the StakingRewards contract /// @param amount Amount of tokens to withdraw - function withdraw(uint256 amount) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - (tokensToEnable, tokensToDisable) = _withdraw(amount, false); + function withdraw(uint256 amount) external override creditFacadeOnly returns (bool) { + _execute(abi.encodeCall(IStakingRewards.withdraw, (amount))); + return false; } /// @notice Withdraws the entire balance of staked tokens, except the specified amount /// @param leftoverAmount Amount of staked tokens to keep in the contract - function withdrawDiff(uint256 leftoverAmount) - external - override - creditFacadeOnly - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function withdrawDiff(uint256 leftoverAmount) external override creditFacadeOnly returns (bool) { address creditAccount = _creditAccount(); uint256 balance = IERC20(stakedPhantomToken).balanceOf(creditAccount); if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _withdraw(balance - leftoverAmount, leftoverAmount <= 1); + _execute(abi.encodeCall(IStakingRewards.withdraw, (balance - leftoverAmount))); } } + + return false; } - /// @dev Internal implementation of `withdraw` and `withdrawDiff` - function _withdraw(uint256 amount, bool disableStakedToken) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + /// @notice Withdraws phantom token for its underlying + function withdrawPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); _execute(abi.encodeCall(IStakingRewards.withdraw, (amount))); - (tokensToEnable, tokensToDisable) = (stakingTokenMask, disableStakedToken ? stakedPhantomTokenMask : 0); + return false; + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory) { + return abi.encode(creditManager, targetContract, stakingToken, rewardsToken, stakedPhantomToken, referral); } } diff --git a/contracts/adapters/traderjoe/TraderJoeRouterAdapter.sol b/contracts/adapters/traderjoe/TraderJoeRouterAdapter.sol new file mode 100644 index 00000000..a486dc28 --- /dev/null +++ b/contracts/adapters/traderjoe/TraderJoeRouterAdapter.sol @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; +import {BitMask} from "@gearbox-protocol/core-v3/contracts/libraries/BitMask.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {ITraderJoeRouter, Path, Version} from "../../integrations/traderjoe/ITraderJoeRouter.sol"; +import { + ITraderJoeRouterAdapter, + TraderJoePoolStatus, + TraderJoePool +} from "../../interfaces/traderjoe/ITraderJoeRouterAdapter.sol"; + +/// @title TraderJoe Router adapter +/// @notice Implements logic allowing CAs to perform swaps via TraderJoe +contract TraderJoeRouterAdapter is AbstractAdapter, ITraderJoeRouterAdapter { + using EnumerableSet for EnumerableSet.Bytes32Set; + using BitMask for uint256; + + bytes32 public constant override contractType = "ADAPTER::TRADERJOE_ROUTER"; + uint256 public constant override version = 3_10; + + /// @dev Mapping from hash(token0, token1, binStep, poolVersion) to respective tuple + mapping(bytes32 => TraderJoePool) internal _hashToPool; + + /// @dev Set of hashes of (token0, token1, binStep, poolVersion) for all supported pools + EnumerableSet.Bytes32Set internal _supportedPoolHashes; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _router TraderJoe Router address + constructor(address _creditManager, address _router) AbstractAdapter(_creditManager, _router) {} + + /// @notice Swap exact tokens for tokens + /// @param amountIn Amount of input token to spend + /// @param amountOutMin Minimum amount of output token to receive + /// @param path Path struct defining the swap route + /// @param deadline Maximum timestamp until which the transaction is valid + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + Path calldata path, + address, + uint256 deadline + ) external override creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + + (bool valid, address tokenIn) = _validatePath(path); + if (!valid) revert InvalidPathException(); + + _executeSwapSafeApprove( + tokenIn, + abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokens, (amountIn, amountOutMin, path, creditAccount, deadline) + ) + ); + + return true; + } + + /// @notice Swap exact tokens for tokens supporting fee-on-transfer tokens + /// @param amountIn Amount of input token to spend + /// @param amountOutMin Minimum amount of output token to receive + /// @param path Path struct defining the swap route + /// @param deadline Maximum timestamp until which the transaction is valid + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint256 amountIn, + uint256 amountOutMin, + Path calldata path, + address, + uint256 deadline + ) external override creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + + (bool valid, address tokenIn) = _validatePath(path); + if (!valid) revert InvalidPathException(); + + _executeSwapSafeApprove( + tokenIn, + abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens, + (amountIn, amountOutMin, path, creditAccount, deadline) + ) + ); + + return true; + } + + /// @notice Swap the entire balance of input token to output token, except the specified amount + /// @param leftoverAmount Amount of tokenIn to keep on the account + /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 + /// @param path Path struct defining the swap route + /// @param deadline Maximum timestamp until which the transaction is valid + function swapDiffTokensForTokens(uint256 leftoverAmount, uint256 rateMinRAY, Path calldata path, uint256 deadline) + external + override + creditFacadeOnly + returns (bool) + { + address creditAccount = _creditAccount(); + + (bool valid, address tokenIn) = _validatePath(path); + if (!valid) revert InvalidPathException(); + + uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); + if (amount <= leftoverAmount) return false; + + unchecked { + amount -= leftoverAmount; + } + + uint256 amountOutMin = (amount * rateMinRAY) / RAY; + + _executeSwapSafeApprove( + tokenIn, + abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokens, (amount, amountOutMin, path, creditAccount, deadline) + ) + ); + + return true; + } + + /// @notice Swap the entire balance of input token to output token, except the specified amount + /// Uses the fee-on-transfer version of the swap + /// @param leftoverAmount Amount of tokenIn to keep on the account + /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 + /// @param path Path struct defining the swap route + /// @param deadline Maximum timestamp until which the transaction is valid + function swapDiffTokensForTokensSupportingFeeOnTransferTokens( + uint256 leftoverAmount, + uint256 rateMinRAY, + Path calldata path, + uint256 deadline + ) external override creditFacadeOnly returns (bool) { + address creditAccount = _creditAccount(); + + (bool valid, address tokenIn) = _validatePath(path); + if (!valid) revert InvalidPathException(); + + uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); + if (amount <= leftoverAmount) return false; + + unchecked { + amount -= leftoverAmount; + } + + uint256 amountOutMin = (amount * rateMinRAY) / RAY; + + _executeSwapSafeApprove( + tokenIn, + abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens, + (amount, amountOutMin, path, creditAccount, deadline) + ) + ); + + return true; + } + + // ---- // + // DATA // + // ---- // + + /// @notice Returns all supported pools + function supportedPools() public view returns (TraderJoePool[] memory pools) { + bytes32[] memory poolHashes = _supportedPoolHashes.values(); + uint256 len = poolHashes.length; + + pools = new TraderJoePool[](len); + + for (uint256 i = 0; i < len; ++i) { + pools[i] = _hashToPool[poolHashes[i]]; + } + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + TraderJoePool[] memory pools = supportedPools(); + serializedData = abi.encode(creditManager, targetContract, pools); + } + + // ------------- // + // CONFIGURATION // + // ------------- // + + /// @notice Returns whether the given pool parameters are allowed + function isPoolAllowed(address token0, address token1, uint256 binStep, Version poolVersion) + public + view + override + returns (bool) + { + (token0, token1) = _sortTokens(token0, token1); + return _supportedPoolHashes.contains(_computePoolHash(token0, token1, binStep, poolVersion)); + } + + /// @notice Sets status for a batch of pools + /// @param pools Array of `TraderJoePoolStatus` objects + function setPoolStatusBatch(TraderJoePoolStatus[] calldata pools) external override configuratorOnly { + uint256 len = pools.length; + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); + bytes32 poolHash = _computePoolHash(token0, token1, pools[i].binStep, pools[i].poolVersion); + + if (pools[i].allowed) { + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + + _supportedPoolHashes.add(poolHash); + _hashToPool[poolHash] = TraderJoePool({ + token0: token0, + token1: token1, + binStep: pools[i].binStep, + poolVersion: pools[i].poolVersion + }); + } else { + _supportedPoolHashes.remove(poolHash); + delete _hashToPool[poolHash]; + } + emit SetPoolStatus(token0, token1, pools[i].binStep, pools[i].poolVersion, pools[i].allowed); + } + } + + // ------- // + // HELPERS // + // ------- // + + /// @dev Performs sanity check on a swap path + /// - Path length must be reasonable (at most 3 hops, or 4 tokens) + /// - Each hop must be through an allowed pool + function _validatePath(Path memory path) internal view returns (bool valid, address tokenIn) { + uint256 len = path.tokenPath.length; + if (len < 2 || len > 4) return (false, tokenIn); + + // Check if pairBinSteps and versions arrays have the correct length (tokens - 1) + if (path.pairBinSteps.length != len - 1 || path.versions.length != len - 1) { + return (false, tokenIn); + } + + tokenIn = address(path.tokenPath[0]); + valid = true; + + // Validate each hop in the path + for (uint256 i = 0; i < len - 1 && valid; i++) { + valid = isPoolAllowed( + address(path.tokenPath[i]), address(path.tokenPath[i + 1]), path.pairBinSteps[i], path.versions[i] + ); + } + } + + /// @dev Sorts two token addresses + function _sortTokens(address token0, address token1) internal pure returns (address, address) { + if (uint160(token0) < uint160(token1)) { + return (token0, token1); + } else { + return (token1, token0); + } + } + + /// @dev Returns the hash of a pool + function _computePoolHash(address token0, address token1, uint256 binStep, Version poolVersion) + internal + pure + returns (bytes32) + { + return keccak256(abi.encode(token0, token1, binStep, poolVersion)); + } +} diff --git a/contracts/adapters/uniswap/UniswapV2.sol b/contracts/adapters/uniswap/UniswapV2.sol index 3dcbdeec..e13224df 100644 --- a/contracts/adapters/uniswap/UniswapV2.sol +++ b/contracts/adapters/uniswap/UniswapV2.sol @@ -1,26 +1,31 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IUniswapV2Router02} from "../../integrations/uniswap/IUniswapV2Router02.sol"; -import {IUniswapV2Adapter, UniswapV2PairStatus} from "../../interfaces/uniswap/IUniswapV2Adapter.sol"; +import {IUniswapV2Adapter, UniswapV2PairStatus, UniswapV2Pair} from "../../interfaces/uniswap/IUniswapV2Adapter.sol"; /// @title Uniswap V2 Router adapter /// @notice Implements logic allowing CAs to perform swaps via Uniswap V2 and its forks contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.UNISWAP_V2_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + using EnumerableSet for EnumerableSet.Bytes32Set; - /// @dev Mapping from (token0, token1) to whether the pair can be traded through the adapter - mapping(address => mapping(address => bool)) internal _pairStatus; + bytes32 public constant override contractType = "ADAPTER::UNISWAP_V2_ROUTER"; + uint256 public constant override version = 3_10; + + /// @dev Mapping from hash(token0, token1) to respective tuple + mapping(bytes32 => UniswapV2Pair) internal _hashToPair; + + /// @dev Set of hashes of (token0, token1) for all supported pools + EnumerableSet.Bytes32Set internal _supportedPairHashes; /// @notice Constructor /// @param _creditManager Credit manager address @@ -46,22 +51,21 @@ contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { external override creditFacadeOnly // U:[UNI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[UNI2-3] - (bool valid, address tokenIn, address tokenOut) = _validatePath(path); + (bool valid, address tokenIn) = _validatePath(path); if (!valid) revert InvalidPathException(); // U:[UNI2-3] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IUniswapV2Router02.swapTokensForExactTokens, (amountOut, amountInMax, path, creditAccount, deadline) - ), - false + ) ); // U:[UNI2-3] + + return true; } /// @notice Swap given amount of input token to output token @@ -81,22 +85,21 @@ contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { external override creditFacadeOnly // U:[UNI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[UNI2-4] - (bool valid, address tokenIn, address tokenOut) = _validatePath(path); + (bool valid, address tokenIn) = _validatePath(path); if (!valid) revert InvalidPathException(); // U:[UNI2-4] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IUniswapV2Router02.swapExactTokensForTokens, (amountIn, amountOutMin, path, creditAccount, deadline) - ), - false + ) ); // U:[UNI2-4] + + return true; } /// @notice Swap the entire balance of input token to output token, except the specified amount @@ -114,36 +117,49 @@ contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { external override creditFacadeOnly // U:[UNI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[UNI2-5] - address tokenIn; - address tokenOut; - - { - bool valid; - (valid, tokenIn, tokenOut) = _validatePath(path); - if (!valid) revert InvalidPathException(); // U:[UNI2-5] - } + (bool valid, address tokenIn) = _validatePath(path); + if (!valid) revert InvalidPathException(); // U:[UNI2-5] uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); // U:[UNI2-5] - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; // U:[UNI2-5] } - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IUniswapV2Router02.swapExactTokensForTokens, (amount, (amount * rateMinRAY) / RAY, path, creditAccount, deadline) - ), - leftoverAmount <= 1 + ) ); // U:[UNI2-5] + + return true; + } + + // ---- // + // DATA // + // ---- // + + function supportedPairs() public view returns (UniswapV2Pair[] memory pairs) { + bytes32[] memory pairHashes = _supportedPairHashes.values(); + uint256 len = pairHashes.length; + + pairs = new UniswapV2Pair[](len); + + for (uint256 i = 0; i < len; ++i) { + pairs[i] = _hashToPair[pairHashes[i]]; + } + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, supportedPairs()); } // ------------- // @@ -153,7 +169,7 @@ contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { /// @notice Returns whether the (token0, token1) pair is allowed to be traded through the adapter function isPairAllowed(address token0, address token1) public view override returns (bool) { (token0, token1) = _sortTokens(token0, token1); - return _pairStatus[token0][token1]; + return _supportedPairHashes.contains(keccak256(abi.encode(token0, token1))); } /// @notice Sets status for a batch of pairs @@ -164,12 +180,23 @@ contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { configuratorOnly // U:[UNI2-6] { uint256 len = pairs.length; - unchecked { - for (uint256 i; i < len; ++i) { - (address token0, address token1) = _sortTokens(pairs[i].token0, pairs[i].token1); - _pairStatus[token0][token1] = pairs[i].allowed; // U:[UNI2-6] - emit SetPairStatus(token0, token1, pairs[i].allowed); // U:[UNI2-6] + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _sortTokens(pairs[i].token0, pairs[i].token1); + bytes32 pairHash = keccak256(abi.encode(token0, token1)); + if (pairs[i].allowed) { + /// For each added pool, we verify that the pool tokens are valid collaterals, + /// as otherwise operations with unsupported tokens would be possible, leading + /// to possibility of control flow capture + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + + _supportedPairHashes.add(pairHash); + _hashToPair[pairHash] = UniswapV2Pair({token0: token0, token1: token1}); + } else { + _supportedPairHashes.remove(pairHash); + delete _hashToPair[pairHash]; } + emit SetPairStatus(token0, token1, pairs[i].allowed); // U:[UNI2-6] } } @@ -177,19 +204,14 @@ contract UniswapV2Adapter is AbstractAdapter, IUniswapV2Adapter { // HELPERS // // ------- // - /// @dev Performs sanity check on a swap path, if path is valid also returns input and output tokens + /// @dev Performs sanity check on a swap path, if path is valid also returns the input token /// - Path length must be no more than 4 (i.e., at most 3 hops) /// - Each swap must be through an allowed pair - function _validatePath(address[] memory path) - internal - view - returns (bool valid, address tokenIn, address tokenOut) - { + function _validatePath(address[] memory path) internal view returns (bool valid, address tokenIn) { uint256 len = path.length; - if (len < 2 || len > 4) return (false, tokenIn, tokenOut); // U:[UNI2-7] + if (len < 2 || len > 4) return (false, tokenIn); // U:[UNI2-7] tokenIn = path[0]; // U:[UNI2-7] - tokenOut = path[len - 1]; // U:[UNI2-7] valid = isPairAllowed(path[0], path[1]); if (valid && len > 2) { valid = isPairAllowed(path[1], path[2]); // U:[UNI2-7] diff --git a/contracts/adapters/uniswap/UniswapV3.sol b/contracts/adapters/uniswap/UniswapV3.sol index c62bb2ac..e5e30a5e 100644 --- a/contracts/adapters/uniswap/UniswapV3.sol +++ b/contracts/adapters/uniswap/UniswapV3.sol @@ -1,26 +1,27 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {ISwapRouter} from "../../integrations/uniswap/IUniswapV3.sol"; import {BytesLib} from "../../integrations/uniswap/BytesLib.sol"; -import {IUniswapV3Adapter, UniswapV3PoolStatus} from "../../interfaces/uniswap/IUniswapV3Adapter.sol"; +import {IUniswapV3Adapter, UniswapV3PoolStatus, UniswapV3Pool} from "../../interfaces/uniswap/IUniswapV3Adapter.sol"; /// @title Uniswap V3 Router adapter /// @notice Implements logic allowing CAs to perform swaps via Uniswap V3 contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { + using EnumerableSet for EnumerableSet.Bytes32Set; using BytesLib for bytes; - AdapterType public constant override _gearboxAdapterType = AdapterType.UNISWAP_V3_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::UNISWAP_V3_ROUTER"; + uint256 public constant override version = 3_10; /// @dev The length of the bytes encoded address uint256 private constant ADDR_SIZE = 20; @@ -40,8 +41,11 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { /// @dev The length of the path with 3 hops uint256 private constant PATH_4_LENGTH = 4 * ADDR_SIZE + 3 * FEE_SIZE; - /// @dev Mapping from (token0, token1, fee) to whether the pool can be traded through the adapter - mapping(address => mapping(address => mapping(uint24 => bool))) internal _poolStatus; + /// @dev Mapping from hash(token0, token1, fee) to respective tuple + mapping(bytes32 => UniswapV3Pool) internal _hashToPool; + + /// @dev Set of hashes of (token0, token1, fee) for all supported pools + EnumerableSet.Bytes32Set internal _supportedPoolHashes; /// @notice Constructor /// @param _creditManager Credit manager address @@ -57,17 +61,17 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { external override creditFacadeOnly // U:[UNI3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (!isPoolAllowed(params.tokenIn, params.tokenOut, params.fee)) revert InvalidPathException(); + address creditAccount = _creditAccount(); // U:[UNI3-3] ISwapRouter.ExactInputSingleParams memory paramsUpdate = params; // U:[UNI3-3] paramsUpdate.recipient = creditAccount; // U:[UNI3-3] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - params.tokenIn, params.tokenOut, abi.encodeCall(ISwapRouter.exactInputSingle, (paramsUpdate)), false - ); // U:[UNI3-3] + _executeSwapSafeApprove(params.tokenIn, abi.encodeCall(ISwapRouter.exactInputSingle, (paramsUpdate))); // U:[UNI3-3] + return true; } /// @notice Swaps all balance of input token for output token through a single pool, except the specified amount @@ -76,12 +80,14 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { external override creditFacadeOnly // U:[UNI3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (!isPoolAllowed(params.tokenIn, params.tokenOut, params.fee)) revert InvalidPathException(); + address creditAccount = _creditAccount(); // U:[UNI3-4] uint256 amount = IERC20(params.tokenIn).balanceOf(creditAccount); // U:[UNI3-4] - if (amount <= params.leftoverAmount) return (0, 0); + if (amount <= params.leftoverAmount) return false; unchecked { amount -= params.leftoverAmount; // U:[UNI3-4] } @@ -97,13 +103,8 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { sqrtPriceLimitX96: params.sqrtPriceLimitX96 }); // U:[UNI3-4] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - params.tokenIn, - params.tokenOut, - abi.encodeCall(ISwapRouter.exactInputSingle, (paramsUpdate)), - params.leftoverAmount <= 1 - ); // U:[UNI3-4] + _executeSwapSafeApprove(params.tokenIn, abi.encodeCall(ISwapRouter.exactInputSingle, (paramsUpdate))); // U:[UNI3-4] + return true; } /// @notice Swaps given amount of input token for output token through multiple pools @@ -114,19 +115,18 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { external override creditFacadeOnly // U:[UNI3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[UNI3-5] - (bool valid, address tokenIn, address tokenOut) = _validatePath(params.path); + (bool valid, address tokenIn,) = _validatePath(params.path); if (!valid) revert InvalidPathException(); // U:[UNI3-5] ISwapRouter.ExactInputParams memory paramsUpdate = params; // U:[UNI3-5] paramsUpdate.recipient = creditAccount; // U:[UNI3-5] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = - _executeSwapSafeApprove(tokenIn, tokenOut, abi.encodeCall(ISwapRouter.exactInput, (paramsUpdate)), false); // U:[UNI3-5] + _executeSwapSafeApprove(tokenIn, abi.encodeCall(ISwapRouter.exactInput, (paramsUpdate))); // U:[UNI3-5] + return true; } /// @notice Swaps all balance of input token for output token through multiple pools, except the specified amount @@ -136,15 +136,15 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { external override creditFacadeOnly // U:[UNI3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[UNI3-6] - (bool valid, address tokenIn, address tokenOut) = _validatePath(params.path); + (bool valid, address tokenIn,) = _validatePath(params.path); if (!valid) revert InvalidPathException(); // U:[UNI3-6] uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); // U:[UNI3-6] - if (amount <= params.leftoverAmount) return (0, 0); + if (amount <= params.leftoverAmount) return false; unchecked { amount -= params.leftoverAmount; // U:[UNI3-6] @@ -157,10 +157,8 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { amountOutMinimum: (amount * params.rateMinRAY) / RAY }); - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - tokenIn, tokenOut, abi.encodeCall(ISwapRouter.exactInput, (paramsUpdate)), params.leftoverAmount <= 1 - ); // U:[UNI3-6] + _executeSwapSafeApprove(tokenIn, abi.encodeCall(ISwapRouter.exactInput, (paramsUpdate))); // U:[UNI3-6] + return true; } /// @notice Swaps input token for given amount of output token through a single pool @@ -170,17 +168,16 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { external override creditFacadeOnly // U:[UNI3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { + if (!isPoolAllowed(params.tokenIn, params.tokenOut, params.fee)) revert InvalidPathException(); address creditAccount = _creditAccount(); // U:[UNI3-7] ISwapRouter.ExactOutputSingleParams memory paramsUpdate = params; // U:[UNI3-7] paramsUpdate.recipient = creditAccount; // U:[UNI3-7] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( - params.tokenIn, params.tokenOut, abi.encodeCall(ISwapRouter.exactOutputSingle, (paramsUpdate)), false - ); // U:[UNI3-7] + _executeSwapSafeApprove(params.tokenIn, abi.encodeCall(ISwapRouter.exactOutputSingle, (paramsUpdate))); // U:[UNI3-7] + return true; } /// @notice Swaps input token for given amount of output token through multiple pools @@ -191,19 +188,38 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { external override creditFacadeOnly // U:[UNI3-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[UNI3-8] - (bool valid, address tokenOut, address tokenIn) = _validatePath(params.path); + (bool valid,, address tokenIn) = _validatePath(params.path); if (!valid) revert InvalidPathException(); // U:[UNI3-8] ISwapRouter.ExactOutputParams memory paramsUpdate = params; // U:[UNI3-8] paramsUpdate.recipient = creditAccount; // U:[UNI3-8] - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = - _executeSwapSafeApprove(tokenIn, tokenOut, abi.encodeCall(ISwapRouter.exactOutput, (paramsUpdate)), false); // U:[UNI3-8] + _executeSwapSafeApprove(tokenIn, abi.encodeCall(ISwapRouter.exactOutput, (paramsUpdate))); // U:[UNI3-8] + return true; + } + + // ---- // + // DATA // + // ---- // + + function supportedPools() public view returns (UniswapV3Pool[] memory pools) { + bytes32[] memory poolHashes = _supportedPoolHashes.values(); + uint256 len = poolHashes.length; + + pools = new UniswapV3Pool[](len); + + for (uint256 i = 0; i < len; ++i) { + pools[i] = _hashToPool[poolHashes[i]]; + } + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, supportedPools()); } // ------------- // @@ -213,7 +229,7 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { /// @notice Returns whether the (token0, token1, fee) pool is allowed to be traded through the adapter function isPoolAllowed(address token0, address token1, uint24 fee) public view override returns (bool) { (token0, token1) = _sortTokens(token0, token1); - return _poolStatus[token0][token1][fee]; + return _supportedPoolHashes.contains(keccak256(abi.encode(token0, token1, fee))); } /// @notice Sets status for a batch of pools @@ -224,12 +240,23 @@ contract UniswapV3Adapter is AbstractAdapter, IUniswapV3Adapter { configuratorOnly // U:[UNI3-9] { uint256 len = pools.length; - unchecked { - for (uint256 i; i < len; ++i) { - (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); - _poolStatus[token0][token1][pools[i].fee] = pools[i].allowed; // U:[UNI3-9] - emit SetPoolStatus(token0, token1, pools[i].fee, pools[i].allowed); // U:[UNI3-9] + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); + bytes32 poolHash = keccak256(abi.encode(token0, token1, pools[i].fee)); + if (pools[i].allowed) { + /// For each added pool, we verify that the pool tokens are valid collaterals, + /// as otherwise operations with unsupported tokens would be possible, leading + /// to possibility of control flow capture + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + + _supportedPoolHashes.add(poolHash); + _hashToPool[poolHash] = UniswapV3Pool({token0: token0, token1: token1, fee: pools[i].fee}); + } else { + _supportedPoolHashes.remove(poolHash); + delete _hashToPool[poolHash]; } + emit SetPoolStatus(token0, token1, pools[i].fee, pools[i].allowed); // U:[UNI3-9] } } diff --git a/contracts/adapters/uniswap/UniswapV4.sol b/contracts/adapters/uniswap/UniswapV4.sol new file mode 100644 index 00000000..30cf3903 --- /dev/null +++ b/contracts/adapters/uniswap/UniswapV4.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +import {AbstractAdapter} from "../AbstractAdapter.sol"; + +import {IUniswapV4Gateway, PoolKey} from "../../interfaces/uniswap/IUniswapV4Gateway.sol"; +import {IUniswapV4Adapter, UniswapV4PoolStatus} from "../../interfaces/uniswap/IUniswapV4Adapter.sol"; + +/// @title Uniswap V4 Router adapter +/// @notice Implements logic allowing CAs to perform swaps in Uniswap V4 pools via a gateway +contract UniswapV4Adapter is AbstractAdapter, IUniswapV4Adapter { + using EnumerableSet for EnumerableSet.Bytes32Set; + + bytes32 public constant override contractType = "ADAPTER::UNISWAP_V4_GATEWAY"; + uint256 public constant override version = 3_10; + + address public immutable weth; + + /// @dev Mapping from hash(token0, token1, fee, tickSpacing, hooks) to respective tuple + mapping(bytes32 => PoolKey) internal _hashToPoolKey; + + /// @dev Set of hashes of (token0, token1, fee, tickSpacing, hooks) for all supported pools + EnumerableSet.Bytes32Set internal _supportedPoolKeyHashes; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _gateway UniswapV4 gateway address + constructor(address _creditManager, address _gateway) AbstractAdapter(_creditManager, _gateway) { + weth = IUniswapV4Gateway(_gateway).weth(); + } + + /// @notice Swaps given amount of input token for output token through a single pool + /// @param poolKey Pool key + /// @param zeroForOne Whether the input token is token0 + /// @param amountIn Amount of input token + /// @param amountOutMinimum Minimum amount of output token + /// @dev `hookData` is ignored since it is always set to empty for safety + /// @dev In case the input token is ETH (denoted as address(0)), the gateway needs to have WETH approved to it + function swapExactInputSingle( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 amountIn, + uint128 amountOutMinimum, + bytes calldata + ) external creditFacadeOnly returns (bool) { + if (!isPoolKeyAllowed(poolKey)) revert InvalidPoolKeyException(); + + address tokenIn = zeroForOne ? poolKey.token0 : poolKey.token1; + + if (tokenIn == address(0)) tokenIn = weth; + + _swapExactInputSingle(poolKey, zeroForOne, amountIn, amountOutMinimum, tokenIn); + + return true; + } + + /// @notice Swaps all balance of input token for output token through a single pool, except the specified amount + /// @param poolKey Pool key + /// @param zeroForOne Whether the input token is token0 + /// @param leftoverAmount Amount of input token to keep on the account + /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 + /// @dev In case the input token is ETH (denoted as address(0)), the gateway needs to have WETH approved to it + function swapExactInputSingleDiff( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 leftoverAmount, + uint128 rateMinRAY + ) external creditFacadeOnly returns (bool) { + if (!isPoolKeyAllowed(poolKey)) revert InvalidPoolKeyException(); + + address tokenIn = zeroForOne ? poolKey.token0 : poolKey.token1; + + if (tokenIn == address(0)) tokenIn = weth; + + address creditAccount = _creditAccount(); + + uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); + if (amount <= leftoverAmount) return false; + + unchecked { + amount -= leftoverAmount; + } + + _swapExactInputSingle(poolKey, zeroForOne, uint128(amount), uint128(amount * rateMinRAY / RAY), tokenIn); + + return true; + } + + /// @dev Internal implementation for `swapExactInputSingle` and `swapExactInputSingleDiff` + function _swapExactInputSingle( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 amountIn, + uint128 amountOutMinimum, + address tokenIn + ) internal { + _executeSwapSafeApprove( + tokenIn, + abi.encodeCall( + IUniswapV4Gateway.swapExactInputSingle, (poolKey, zeroForOne, amountIn, amountOutMinimum, "") + ) + ); + } + + // ---- // + // DATA // + // ---- // + + /// @notice Returns all supported pool keys + function supportedPoolKeys() public view returns (PoolKey[] memory poolKeys) { + bytes32[] memory poolKeyHashes = _supportedPoolKeyHashes.values(); + uint256 len = poolKeyHashes.length; + + poolKeys = new PoolKey[](len); + + for (uint256 i = 0; i < len; ++i) { + poolKeys[i] = _hashToPoolKey[poolKeyHashes[i]]; + } + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, supportedPoolKeys()); + } + + // ------------- // + // CONFIGURATION // + // ------------- // + + /// @notice Returns whether the (token0, token1, fee, tickSpacing, hooks) pool key is allowed to be traded through the adapter + function isPoolKeyAllowed(PoolKey calldata poolKey) public view override returns (bool) { + return _supportedPoolKeyHashes.contains(keccak256(abi.encode(poolKey))); + } + + /// @notice Sets status for a batch of pool + /// @param pools Array of `UniswapV4PoolStatus` objects + function setPoolKeyStatusBatch(UniswapV4PoolStatus[] calldata pools) external override configuratorOnly { + uint256 len = pools.length; + for (uint256 i; i < len; ++i) { + bytes32 poolKeyHash = keccak256(abi.encode(pools[i].poolKey)); + if (pools[i].allowed) { + if (pools[i].poolKey.token0 == address(0)) { + _getMaskOrRevert(weth); + } else { + _getMaskOrRevert(pools[i].poolKey.token0); + } + + if (pools[i].poolKey.token1 == address(0)) { + _getMaskOrRevert(weth); + } else { + _getMaskOrRevert(pools[i].poolKey.token1); + } + + _supportedPoolKeyHashes.add(poolKeyHash); + _hashToPoolKey[poolKeyHash] = pools[i].poolKey; + } else { + _supportedPoolKeyHashes.remove(poolKeyHash); + delete _hashToPoolKey[poolKeyHash]; + } + emit SetPoolKeyStatus( + pools[i].poolKey.token0, + pools[i].poolKey.token1, + pools[i].poolKey.fee, + pools[i].poolKey.tickSpacing, + pools[i].poolKey.hooks, + pools[i].allowed + ); + } + } +} diff --git a/contracts/adapters/upshift/UpshiftVaultAdapter.sol b/contracts/adapters/upshift/UpshiftVaultAdapter.sol new file mode 100644 index 00000000..cf9c87ac --- /dev/null +++ b/contracts/adapters/upshift/UpshiftVaultAdapter.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {IStateSerializer} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IStateSerializer.sol"; +import {ERC4626Adapter} from "../erc4626/ERC4626Adapter.sol"; +import {IUpshiftVaultAdapter} from "../../interfaces/upshift/IUpshiftVaultAdapter.sol"; +import {IUpshiftVaultGateway} from "../../interfaces/upshift/IUpshiftVaultGateway.sol"; + +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +/// @title UpshiftVault adapter +/// @notice Implements logic allowing CAs to interact with the UpshiftVault vault, accounting for delayed withdrawals +contract UpshiftVaultAdapter is ERC4626Adapter, IUpshiftVaultAdapter { + uint256 public constant override(ERC4626Adapter, IVersion) version = 3_10; + bytes32 public constant override(ERC4626Adapter, IVersion) contractType = "ADAPTER::UPSHIFT_VAULT"; + + address public immutable stakedPhantomToken; + + /// @notice Constructor + /// @param _creditManager Credit manager address + /// @param _gateway UpshiftVault gateway address + /// @param _stakedPhantomToken Staked phantom token address + constructor(address _creditManager, address _gateway, address _stakedPhantomToken) + ERC4626Adapter(_creditManager, IUpshiftVaultGateway(_gateway).upshiftVault(), _gateway) + { + stakedPhantomToken = _stakedPhantomToken; + _getMaskOrRevert(stakedPhantomToken); + } + + /// @dev This always reverts, since neither the original vault nor the gateway support this function + function _withdraw(address, uint256) internal pure override returns (bool) { + revert NotImplementedException(); + } + + /// @dev This always reverts, since neither the original vault nor the gateway support this function + function _redeem(address, uint256) internal pure override returns (bool) { + revert NotImplementedException(); + } + + /// @notice Requests a redemption from the UpshiftVault vault through the gateway + /// @param shares Amount of shares to redeem + /// @dev This function does not accept `receiverAddr` and `holderAddr` parameters, + /// since the gateway function only operates on msg.sender + function requestRedeem(uint256 shares) external override creditFacadeOnly returns (bool) { + _executeSwapSafeApprove(vault, abi.encodeCall(IUpshiftVaultGateway.requestRedeem, (shares))); + return true; + } + + /// @notice Claims a redemption from the UpshiftVault vault through the gateway + /// @dev This function does not accept `receiverAddr` and date parameters, + /// since the gateway only processes a single redemption at a time. + /// However, it allows to specify an amount, to support partial liquidations. + function claim(uint256 amount) external override creditFacadeOnly returns (bool) { + _claim(amount); + return false; + } + + /// @dev Internal implementation of `claim`. + function _claim(uint256 amount) internal { + _execute(abi.encodeCall(IUpshiftVaultGateway.claim, (amount))); + } + + /// @notice Claims mature withdrawals, represented by the phantom token + function withdrawPhantomToken(address token, uint256 amount) external override creditFacadeOnly returns (bool) { + if (token != stakedPhantomToken) revert IncorrectStakedPhantomTokenException(); + _claim(amount); + return false; + } + + /// @dev It's not possible to deposit from underlying (the vault's asset) into the withdrawal phantom token, + /// hence the function is not implemented. + function depositPhantomToken(address, uint256) external view override creditFacadeOnly returns (bool) { + revert NotImplementedException(); + } + + function serialize() + external + view + virtual + override(ERC4626Adapter, IStateSerializer) + returns (bytes memory serializedData) + { + serializedData = abi.encode(creditManager, targetContract, vault, asset, stakedPhantomToken); + } +} diff --git a/contracts/adapters/velodrome/VelodromeV2RouterAdapter.sol b/contracts/adapters/velodrome/VelodromeV2RouterAdapter.sol index e1470b98..401b8fba 100644 --- a/contracts/adapters/velodrome/VelodromeV2RouterAdapter.sol +++ b/contracts/adapters/velodrome/VelodromeV2RouterAdapter.sol @@ -1,28 +1,35 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IVelodromeV2Router, Route} from "../../integrations/velodrome/IVelodromeV2Router.sol"; import { - IVelodromeV2RouterAdapter, VelodromeV2PoolStatus + IVelodromeV2RouterAdapter, + VelodromeV2PoolStatus, + VelodromeV2Pool } from "../../interfaces/velodrome/IVelodromeV2RouterAdapter.sol"; /// @title Velodrome V2 Router adapter /// @notice Implements logic allowing CAs to perform swaps via Velodrome V2 contract VelodromeV2RouterAdapter is AbstractAdapter, IVelodromeV2RouterAdapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.VELODROME_V2_ROUTER; - uint16 public constant override _gearboxAdapterVersion = 3_00; + using EnumerableSet for EnumerableSet.Bytes32Set; - /// @dev Mapping from (token0, token1, stable, factory) to whether the pool can be traded through the adapter - mapping(address => mapping(address => mapping(bool => mapping(address => bool)))) internal _poolStatus; + bytes32 public constant override contractType = "ADAPTER::VELODROME_V2_ROUTER"; + uint256 public constant override version = 3_10; + + /// @dev Mapping from hash(token0, token1, stable, factory) to respective tuple + mapping(bytes32 => VelodromeV2Pool) internal _hashToPool; + + /// @dev Set of hashes of (token0, token1, stable, factory) for all supported pools + EnumerableSet.Bytes32Set internal _supportedPoolHashes; /// @notice Constructor /// @param _creditManager Credit manager address @@ -47,22 +54,21 @@ contract VelodromeV2RouterAdapter is AbstractAdapter, IVelodromeV2RouterAdapter external override creditFacadeOnly // U: [VELO2-02] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); - (bool valid, address tokenIn, address tokenOut) = _validatePath(routes); // U: [VELO2-06] + (bool valid, address tokenIn) = _validatePath(routes); // U: [VELO2-06] if (!valid) revert InvalidPathException(); - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IVelodromeV2Router.swapExactTokensForTokens, (amountIn, amountOutMin, routes, creditAccount, deadline) - ), - false + ) ); // U: [VELO2-03] + + return true; } /// @notice Swap the entire balance of input token to output token, except the specified amount @@ -79,36 +85,50 @@ contract VelodromeV2RouterAdapter is AbstractAdapter, IVelodromeV2RouterAdapter external override creditFacadeOnly // U: [VELO2-02] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); - address tokenIn; - address tokenOut; - - { - bool valid; - (valid, tokenIn, tokenOut) = _validatePath(routes); // U: [VELO2-06] - if (!valid) revert InvalidPathException(); - } + (bool valid, address tokenIn) = _validatePath(routes); // U: [VELO2-06] + if (!valid) revert InvalidPathException(); uint256 amount = IERC20(tokenIn).balanceOf(creditAccount); - if (amount <= leftoverAmount) return (0, 0); + if (amount <= leftoverAmount) return false; unchecked { amount -= leftoverAmount; // U: [VELO2-04] } - // calling `_executeSwap` because we need to check if output token is registered as collateral token in the CM - (tokensToEnable, tokensToDisable,) = _executeSwapSafeApprove( + _executeSwapSafeApprove( tokenIn, - tokenOut, abi.encodeCall( IVelodromeV2Router.swapExactTokensForTokens, (amount, (amount * rateMinRAY) / RAY, routes, creditAccount, deadline) - ), - leftoverAmount <= 1 + ) ); // U: [VELO2-04] + + return true; + } + + // ---- // + // DATA // + // ---- // + + function supportedPools() public view returns (VelodromeV2Pool[] memory pools) { + bytes32[] memory poolHashes = _supportedPoolHashes.values(); + uint256 len = poolHashes.length; + + pools = new VelodromeV2Pool[](len); + + for (uint256 i = 0; i < len; ++i) { + pools[i] = _hashToPool[poolHashes[i]]; + } + } + + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + VelodromeV2Pool[] memory pools = supportedPools(); + serializedData = abi.encode(creditManager, targetContract, pools); } // ------------- // @@ -123,19 +143,35 @@ contract VelodromeV2RouterAdapter is AbstractAdapter, IVelodromeV2RouterAdapter returns (bool) { (token0, token1) = _sortTokens(token0, token1); - return _poolStatus[token0][token1][stable][factory]; + return _supportedPoolHashes.contains(keccak256(abi.encode(token0, token1, stable, factory))); } /// @notice Sets status for a batch of pools /// @param pools Array of `VelodromeV2PoolStatus` objects function setPoolStatusBatch(VelodromeV2PoolStatus[] calldata pools) external override configuratorOnly { uint256 len = pools.length; - unchecked { - for (uint256 i; i < len; ++i) { - (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); - _poolStatus[token0][token1][pools[i].stable][pools[i].factory] = pools[i].allowed; // U: [VELO2-05] - emit SetPoolStatus(token0, token1, pools[i].stable, pools[i].factory, pools[i].allowed); // U: [VELO2-05] + for (uint256 i; i < len; ++i) { + (address token0, address token1) = _sortTokens(pools[i].token0, pools[i].token1); + bytes32 poolHash = keccak256(abi.encode(token0, token1, pools[i].stable, pools[i].factory)); + if (pools[i].allowed) { + /// For each added pool, we verify that the pool tokens are valid collaterals, + /// as otherwise operations with unsupported tokens would be possible, leading + /// to possibility of control flow capture + _getMaskOrRevert(token0); + _getMaskOrRevert(token1); + + _supportedPoolHashes.add(poolHash); + _hashToPool[poolHash] = VelodromeV2Pool({ + token0: token0, + token1: token1, + stable: pools[i].stable, + factory: pools[i].factory + }); + } else { + _supportedPoolHashes.remove(poolHash); + delete _hashToPool[poolHash]; } + emit SetPoolStatus(token0, token1, pools[i].stable, pools[i].factory, pools[i].allowed); // U: [VELO2-05] } } @@ -146,16 +182,11 @@ contract VelodromeV2RouterAdapter is AbstractAdapter, IVelodromeV2RouterAdapter /// @dev Performs sanity check on a swap path, if path is valid also returns input and output tokens /// - Path length must be no more than 4 (i.e., at most 3 hops) /// - Each swap must be through an allowed pool - function _validatePath(Route[] memory routes) - internal - view - returns (bool valid, address tokenIn, address tokenOut) - { + function _validatePath(Route[] memory routes) internal view returns (bool valid, address tokenIn) { uint256 len = routes.length; - if (len < 1 || len > 3) return (false, tokenIn, tokenOut); + if (len < 1 || len > 3) return (false, tokenIn); tokenIn = routes[0].from; - tokenOut = routes[len - 1].to; valid = isPoolAllowed(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory); if (valid && len > 1) { valid = isPoolAllowed(routes[1].from, routes[1].to, routes[1].stable, routes[1].factory) diff --git a/contracts/adapters/yearn/YearnV2.sol b/contracts/adapters/yearn/YearnV2.sol index 49c38a53..e244ef91 100644 --- a/contracts/adapters/yearn/YearnV2.sol +++ b/contracts/adapters/yearn/YearnV2.sol @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {AbstractAdapter} from "../AbstractAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IYVault} from "../../integrations/yearn/IYVault.sol"; import {IYearnV2Adapter} from "../../interfaces/yearn/IYearnV2Adapter.sol"; @@ -14,18 +13,12 @@ import {IYearnV2Adapter} from "../../interfaces/yearn/IYearnV2Adapter.sol"; /// @title Yearn V2 Vault adapter /// @notice Implements logic allowing CAs to deposit into Yearn vaults contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { - AdapterType public constant override _gearboxAdapterType = AdapterType.YEARN_V2; - uint16 public constant override _gearboxAdapterVersion = 3_00; + bytes32 public constant override contractType = "ADAPTER::YEARN_V2"; + uint256 public constant override version = 3_10; /// @notice Vault's underlying token address address public immutable override token; - /// @notice Collateral token mask of underlying token in the credit manager - uint256 public immutable override tokenMask; - - /// @notice Collateral token mask of yToken in the credit manager - uint256 public immutable override yTokenMask; - /// @notice Constructor /// @param _creditManager Credit manager address /// @param _vault Yearn vault address @@ -33,8 +26,11 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { AbstractAdapter(_creditManager, _vault) // U:[YFI2-1] { token = IYVault(targetContract).token(); // U:[YFI2-1] - tokenMask = _getMaskOrRevert(token); // U:[YFI2-1] - yTokenMask = _getMaskOrRevert(_vault); // U:[YFI2-1] + + // We verify that the vault asset and shares are valid collaterals + // in the system before deployment + _getMaskOrRevert(token); // U:[YFI2-1] + _getMaskOrRevert(_vault); // U:[YFI2-1] } // -------- // @@ -46,16 +42,18 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[YFI2-3] uint256 balance = IERC20(token).balanceOf(creditAccount); // U:[YFI2-3] if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _deposit(balance - leftoverAmount, leftoverAmount <= 1); // U:[YFI2-3] + _deposit(balance - leftoverAmount); // U:[YFI2-3] } } + + return false; } /// @notice Deposit given amount of underlying tokens into the vault @@ -64,9 +62,10 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _deposit(amount, false); // U:[YFI2-4] + _deposit(amount); // U:[YFI2-4] + return false; } /// @notice Deposit given amount of underlying tokens into the vault @@ -76,23 +75,15 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _deposit(amount, false); // U:[YFI2-5] + _deposit(amount); // U:[YFI2-5] + return false; } /// @dev Internal implementation of `deposit` functions - /// - underlying is approved before the call because vault needs permission to transfer it - /// - yToken is enabled after the call - /// - underlying is only disabled when depositing the entire balance - function _deposit(uint256 amount, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _approveToken(token, type(uint256).max); // U:[YFI2-3,4,5] - _execute(abi.encodeWithSignature("deposit(uint256)", amount)); // U:[YFI2-3,4,5] - _approveToken(token, 1); // U:[YFI2-3,4,5] - (tokensToEnable, tokensToDisable) = (yTokenMask, disableTokenIn ? tokenMask : 0); + function _deposit(uint256 amount) internal { + _executeSwapSafeApprove(token, abi.encodeWithSignature("deposit(uint256)", amount)); // U:[YFI2-3,4,5] } // ----------- // @@ -104,7 +95,7 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[YFI2-6] @@ -112,9 +103,10 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { if (balance > leftoverAmount) { unchecked { - (tokensToEnable, tokensToDisable) = _withdraw(balance - leftoverAmount, leftoverAmount <= 1); // U:[YFI2-6] + _withdraw(balance - leftoverAmount); // U:[YFI2-6] } } + return false; } /// @notice Burn given amount of yTokens to withdraw corresponding amount of underlying from the vault @@ -123,9 +115,10 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _withdraw(maxShares, false); // U:[YFI2-7] + _withdraw(maxShares); // U:[YFI2-7] + return false; } /// @notice Burn given amount of yTokens to withdraw corresponding amount of underlying from the vault @@ -135,9 +128,10 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { - (tokensToEnable, tokensToDisable) = _withdraw(maxShares, false); // U:[YFI2-8] + _withdraw(maxShares); // U:[YFI2-8] + return false; } /// @notice Burn given amount of yTokens to withdraw corresponding amount of underlying from the vault @@ -148,33 +142,20 @@ contract YearnV2Adapter is AbstractAdapter, IYearnV2Adapter { external override creditFacadeOnly // U:[YFI2-2] - returns (uint256 tokensToEnable, uint256 tokensToDisable) + returns (bool) { address creditAccount = _creditAccount(); // U:[YFI2-9] - (tokensToEnable, tokensToDisable) = _withdraw(maxShares, creditAccount, maxLoss); // U:[YFI2-9] + _execute(abi.encodeWithSignature("withdraw(uint256,address,uint256)", maxShares, creditAccount, maxLoss)); // U:[YFI2-9] + return false; } /// @dev Internal implementation of `withdraw` functions - /// - yToken is not approved because vault doesn't need permission to burn it - /// - underlying is enabled after the call - /// - yToken is only disabled when withdrawing the entire balance - function _withdraw(uint256 maxShares, bool disableTokenIn) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { + function _withdraw(uint256 maxShares) internal { _execute(abi.encodeWithSignature("withdraw(uint256)", maxShares)); // U:[YFI2-6,7,8] - (tokensToEnable, tokensToDisable) = (tokenMask, disableTokenIn ? yTokenMask : 0); } - /// @dev Internal implementation of `withdraw` function with `maxLoss` argument - /// - yToken is not approved because vault doesn't need permission to burn it - /// - underlying is enabled after the call - /// - yToken is not disabled after the call - function _withdraw(uint256 maxShares, address creditAccount, uint256 maxLoss) - internal - returns (uint256 tokensToEnable, uint256 tokensToDisable) - { - _execute(abi.encodeWithSignature("withdraw(uint256,address,uint256)", maxShares, creditAccount, maxLoss)); // U:[YFI2-9] - (tokensToEnable, tokensToDisable) = (tokenMask, 0); + /// @notice Serialized adapter parameters + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract, token); } } diff --git a/contracts/helpers/PhantomERC20.sol b/contracts/helpers/PhantomERC20.sol new file mode 100644 index 00000000..8984055f --- /dev/null +++ b/contracts/helpers/PhantomERC20.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BUSL-1.1 +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Holdings, 2022 +pragma solidity ^0.8.10; + +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; + +/// @dev PhantomERC20 is a pseudo-ERC20 that only implements totalSupply and balanceOf +/// @notice Used to track positions that do not issue an explicit share token +/// This is an abstract contract and balanceOf is implemented by concrete instances +abstract contract PhantomERC20 is IERC20Metadata { + address public immutable underlying; + + string public symbol; + string public override name; + uint8 public immutable override decimals; + + constructor(address _underlying, string memory _name, string memory _symbol, uint8 _decimals) { + symbol = _symbol; + name = _name; + decimals = _decimals; + underlying = _underlying; + } + + function totalSupply() external view virtual override returns (uint256) { + return IERC20Metadata(underlying).totalSupply(); + } + + function transfer(address, uint256) external pure override returns (bool) { + return false; + } + + function allowance(address, address) external pure override returns (uint256) { + return 0; + } + + function approve(address, uint256) external pure override returns (bool) { + return false; + } + + function transferFrom(address, address, uint256) external pure override returns (bool) { + return false; + } +} diff --git a/contracts/helpers/aave/AaveV2_WrappedAToken.sol b/contracts/helpers/aave/AaveV2_WrappedAToken.sol deleted file mode 100644 index e7559b70..00000000 --- a/contracts/helpers/aave/AaveV2_WrappedAToken.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; - -import {WAD} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; -import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol"; - -import {IAToken} from "../../integrations/aave/IAToken.sol"; -import {ILendingPool} from "../../integrations/aave/ILendingPool.sol"; - -interface IWrappedATokenEvents { - /// @notice Emitted on deposit - /// @param account Account that performed deposit - /// @param assets Amount of deposited aTokens - /// @param shares Amount of waTokens minted to account - event Deposit(address indexed account, uint256 assets, uint256 shares); - - /// @notice Emitted on withdrawal - /// @param account Account that performed withdrawal - /// @param assets Amount of withdrawn aTokens - /// @param shares Amount of waTokens burnt from account - event Withdraw(address indexed account, uint256 assets, uint256 shares); -} - -/// @title Wrapped aToken -/// @notice Non-rebasing wrapper of Aave V2 aToken -/// @dev Ignores any Aave incentives -contract WrappedAToken is ERC20, SanityCheckTrait, IWrappedATokenEvents { - using SafeERC20 for ERC20; - - /// @notice Underlying aToken - address public immutable aToken; - - /// @notice Underlying token - address public immutable underlying; - - /// @notice Aave lending pool - address public immutable lendingPool; - - /// @dev aToken's normalized income (aka interest accumulator) at the moment of waToken creation - uint256 private immutable _normalizedIncome; - - /// @dev waToken decimals - uint8 private immutable _decimals; - - /// @notice Constructor - /// @param _aToken Underlying aToken address - constructor(address _aToken) - ERC20( - address(_aToken) != address(0) ? string(abi.encodePacked("Wrapped ", ERC20(_aToken).name())) : "", - address(_aToken) != address(0) ? string(abi.encodePacked("w", ERC20(_aToken).symbol())) : "" - ) - nonZeroAddress(_aToken) // U:[WAT-1] - { - aToken = _aToken; // U:[WAT-2] - underlying = IAToken(aToken).UNDERLYING_ASSET_ADDRESS(); // U:[WAT-2] - lendingPool = address(IAToken(aToken).POOL()); // U:[WAT-2] - _normalizedIncome = ILendingPool(lendingPool).getReserveNormalizedIncome(underlying); - _decimals = IAToken(aToken).decimals(); // U:[WAT-2] - _resetAllowance(); // U:[WAT-2] - } - - /// @notice waToken decimals, same as underlying and aToken - function decimals() public view override returns (uint8) { - return _decimals; - } - - /// @notice Returns amount of aTokens belonging to given account (increases as interest is accrued) - function balanceOfUnderlying(address account) external view returns (uint256) { - return balanceOf(account) * exchangeRate() / WAD; // U:[WAT-3] - } - - /// @notice Returns amount of aTokens per waToken, scaled by 1e18 - function exchangeRate() public view returns (uint256) { - return WAD * ILendingPool(lendingPool).getReserveNormalizedIncome(underlying) / _normalizedIncome; // U:[WAT-4] - } - - /// @notice Deposit given amount of aTokens (aToken must be approved before the call) - /// @param assets Amount of aTokens to deposit in exchange for waTokens - /// @return shares Amount of waTokens minted to the caller - function deposit(uint256 assets) external returns (uint256 shares) { - ERC20(aToken).transferFrom(msg.sender, address(this), assets); - shares = _deposit(assets); // U:[WAT-5] - } - - /// @notice Deposit given amount underlying tokens (underlying must be approved before the call) - /// @param assets Amount of underlying tokens to deposit in exchange for waTokens - /// @return shares Amount of waTokens minted to the caller - function depositUnderlying(uint256 assets) external returns (uint256 shares) { - ERC20(underlying).safeTransferFrom(msg.sender, address(this), assets); - ILendingPool(lendingPool).deposit(underlying, assets, address(this), 0); // U:[WAT-6] - _resetAllowance(); // U:[WAT-6] - shares = _deposit(assets); // U:[WAT-6] - } - - /// @notice Withdraw given amount of waTokens for aTokens - /// @param shares Amount of waTokens to burn in exchange for aTokens - /// @return assets Amount of aTokens sent to the caller - function withdraw(uint256 shares) external returns (uint256 assets) { - assets = _withdraw(shares); // U:[WAT-7] - ERC20(aToken).transfer(msg.sender, assets); - } - - /// @notice Withdraw given amount of waTokens for underlying tokens - /// @param shares Amount of waTokens to burn in exchange for underlying tokens - /// @return assets Amount of underlying tokens sent to the caller - function withdrawUnderlying(uint256 shares) external returns (uint256 assets) { - assets = _withdraw(shares); // U:[WAT-8] - ILendingPool(lendingPool).withdraw(underlying, assets, msg.sender); // U:[WAT-8] - } - - /// @dev Internal implementation of deposit - function _deposit(uint256 assets) internal returns (uint256 shares) { - shares = assets * WAD / exchangeRate(); - _mint(msg.sender, shares); // U:[WAT-5,6] - emit Deposit(msg.sender, assets, shares); // U:[WAT-5,6] - } - - /// @dev Internal implementation of withdraw - function _withdraw(uint256 shares) internal returns (uint256 assets) { - assets = shares * exchangeRate() / WAD; - _burn(msg.sender, shares); // U:[WAT-7,8] - emit Withdraw(msg.sender, assets, shares); // U:[WAT-7,8] - } - - /// @dev Gives lending pool max approval for underlying - function _resetAllowance() internal { - ERC20(underlying).forceApprove(lendingPool, type(uint256).max); - } -} diff --git a/contracts/helpers/balancer/BalancerV3RouterGateway.sol b/contracts/helpers/balancer/BalancerV3RouterGateway.sol index 7a8ab7f9..a5aa35ad 100644 --- a/contracts/helpers/balancer/BalancerV3RouterGateway.sol +++ b/contracts/helpers/balancer/BalancerV3RouterGateway.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.10; +pragma solidity ^0.8.23; +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; import {IBalancerV3Router} from "../../integrations/balancer/IBalancerV3Router.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -16,9 +17,12 @@ interface IPermit2 { /// @dev This is connector contract to allow Gearbox adapters to swap through the Balancer V3 Router. /// Since the router requires the caller to approve inputs in Permit2, we need an intermediate contract, /// which will be approved to spend the inputs and then call the Permit2 and the router. -contract BalancerV3RouterGateway is IBalancerV3Router { +contract BalancerV3RouterGateway is IBalancerV3Router, IVersion { using SafeERC20 for IERC20; + bytes32 public constant override contractType = "GATEWAY::BALANCER_V3"; + uint256 public constant override version = 3_10; + address public immutable balancerV3Router; address public immutable permit2; diff --git a/contracts/helpers/compound/CompoundV2_CEtherGateway.sol b/contracts/helpers/compound/CompoundV2_CEtherGateway.sol deleted file mode 100644 index 27cee4b2..00000000 --- a/contracts/helpers/compound/CompoundV2_CEtherGateway.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; -import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol"; - -import {ICompoundV2_Exceptions} from "../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; -import {ICEther} from "../../integrations/compound/ICEther.sol"; -import {ICErc20Actions} from "../../integrations/compound/ICErc20.sol"; - -/// @title CEther gateway -/// @notice Wrapper around CEther that uses WETH for all operations instead of ETH -contract CEtherGateway is SanityCheckTrait, ICErc20Actions, ICompoundV2_Exceptions { - /// @notice WETH token address - address public immutable weth; - - /// @notice cETH token address - address public immutable ceth; - - /// @notice Constructor - /// @param _weth WETH token address - /// @param _ceth cETH token address - constructor(address _weth, address _ceth) - nonZeroAddress(_weth) // U:[CEG-1] - nonZeroAddress(_ceth) // U:[CEG-1] - { - weth = _weth; // U:[CEG-1] - ceth = _ceth; // U:[CEG-1] - } - - /// @notice Allows receiving ETH - receive() external payable {} // U:[CEG-2] - - /// @notice Deposit given amount of WETH into Compound - /// WETH must be approved from caller to gateway before the call - /// @param mintAmount Amount of WETH to deposit - /// @return error Error code (always zero, added for compatibility) - function mint(uint256 mintAmount) external override returns (uint256 error) { - // transfer WETH from caller and unwrap it - IERC20(weth).transferFrom(msg.sender, address(this), mintAmount); - IWETH(weth).withdraw(mintAmount); // U:[CEG-3] - - // deposit ETH to Compound - ICEther(ceth).mint{value: mintAmount}(); // U:[CEG-3] - error = 0; // U:[CEG-3] - - // send cETH to caller - IERC20(ceth).transfer(msg.sender, IERC20(ceth).balanceOf(address(this))); - } - - /// @notice Burn given amount of cETH to withdraw WETH - /// cETH must be approved from caller to gateway before the call - /// @param redeemTokens Amount of cETH to burn - /// @param error Error code (always zero, added for compatibility) - function redeem(uint256 redeemTokens) external override returns (uint256 error) { - // get specified amount of cETH from caller - IERC20(ceth).transferFrom(msg.sender, address(this), redeemTokens); - - // redeem ETH from Compound - error = ICEther(ceth).redeem(redeemTokens); // U:[CEG-4] - if (error != 0) revert CTokenError(error); // U:[CEG-6] - - // wrap ETH and send to caller - uint256 ethBalance = address(this).balance; - IWETH(weth).deposit{value: ethBalance}(); // U:[CEG-4] - IERC20(weth).transfer(msg.sender, ethBalance); - } - - /// @notice Withdraw given amount of WETH from Compound - /// cETH must be approved from caller to gateway before the call - /// @param redeemAmount Amount of WETH to withdraw - /// @return error Error code (always zero, added for compatibility) - function redeemUnderlying(uint256 redeemAmount) external override returns (uint256 error) { - // transfer all cETH from caller - IERC20(ceth).transferFrom(msg.sender, address(this), IERC20(ceth).balanceOf(msg.sender)); - - // redeem ETH from Compound - error = ICEther(ceth).redeemUnderlying(redeemAmount); // U:[CEG-5] - if (error != 0) revert CTokenError(error); // U:[CEG-6] - - // return the remaining cETH (if any) back to caller - uint256 cethBalance = IERC20(ceth).balanceOf(address(this)); - if (cethBalance > 0) IERC20(ceth).transfer(msg.sender, cethBalance); - - // wrap ETH and send to caller - uint256 ethBalance = address(this).balance; - IWETH(weth).deposit{value: ethBalance}(); // U:[CEG-5] - IERC20(weth).transfer(msg.sender, ethBalance); - } -} diff --git a/contracts/helpers/convex/ConvexV1_StakedPositionToken.sol b/contracts/helpers/convex/ConvexV1_StakedPositionToken.sol index 58dc73e4..a8774eeb 100644 --- a/contracts/helpers/convex/ConvexV1_StakedPositionToken.sol +++ b/contracts/helpers/convex/ConvexV1_StakedPositionToken.sol @@ -1,21 +1,32 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {PhantomERC20} from "@gearbox-protocol/core-v2/contracts/tokens/PhantomERC20.sol"; +import {IBaseRewardPool} from "../../integrations/convex/IBaseRewardPool.sol"; +import {IBooster} from "../../integrations/convex/IBooster.sol"; +import {PhantomERC20} from "../PhantomERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; /// @title Convex staked position token /// @notice Phantom ERC-20 token that represents the balance of the staking position in Convex pools -contract ConvexStakedPositionToken is PhantomERC20 { +contract ConvexStakedPositionToken is PhantomERC20, IPhantomToken { + bytes32 public constant override contractType = "PHANTOM_TOKEN::CONVEX"; + + uint256 public constant override version = 3_10; + address public immutable pool; + address public immutable booster; + address public immutable curveToken; /// @notice Constructor /// @param _pool The Convex pool where the balance is tracked /// @param _lptoken The Convex LP token that is staked in the pool - constructor(address _pool, address _lptoken) + /// @param _booster The Convex booster associated with respective pool + constructor(address _pool, address _lptoken, address _booster) PhantomERC20( _lptoken, string(abi.encodePacked("Convex Staked Position ", IERC20Metadata(_lptoken).name())), @@ -24,6 +35,12 @@ contract ConvexStakedPositionToken is PhantomERC20 { ) { pool = _pool; + booster = _booster; + + uint256 pid = IBaseRewardPool(pool).pid(); + IBooster.PoolInfo memory pInfo = IBooster(booster).poolInfo(pid); + + curveToken = pInfo.lptoken; } /// @notice Returns the amount of Convex LP tokens staked in the pool @@ -31,4 +48,13 @@ contract ConvexStakedPositionToken is PhantomERC20 { function balanceOf(address account) public view returns (uint256) { return IERC20(pool).balanceOf(account); } + + /// @notice Returns phantom token's target contract and underlying + function getPhantomTokenInfo() external view override returns (address, address) { + return (pool, underlying); + } + + function serialize() external view override returns (bytes memory) { + return abi.encode(pool, underlying, curveToken); + } } diff --git a/contracts/helpers/curve/CurveV1_stETHGateway.sol b/contracts/helpers/curve/CurveV1_stETHGateway.sol index 544bbdc3..7bc153b5 100644 --- a/contracts/helpers/curve/CurveV1_stETHGateway.sol +++ b/contracts/helpers/curve/CurveV1_stETHGateway.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; -import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; import {N_COINS, ICurvePool2Assets} from "../../integrations/curve/ICurvePool_2.sol"; import {ICurvePoolStETH} from "../../integrations/curve/ICurvePoolStETH.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -11,15 +12,19 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol // EXCEPTIONS import { - ZeroAddressException, NotImplementedException -} from "@gearbox-protocol/core-v2/contracts/interfaces/IErrors.sol"; + ZeroAddressException, + NotImplementedException +} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; /// @title CurveV1StETHPoolGateway /// @dev This is connector contract to connect creditAccounts and Curve stETH pool /// it converts WETH to ETH and vice versa for operational purposes -contract CurveV1StETHPoolGateway is ICurvePool2Assets { +contract CurveV1StETHPoolGateway is ICurvePool2Assets, IVersion { using SafeERC20 for IERC20; + bytes32 public constant override contractType = "GATEWAY::CURVE_V1"; + uint256 public constant override version = 3_10; + /// @dev Address of the token with index 0 (WETH) address public immutable token0; diff --git a/contracts/helpers/fluid/FluidDexETHGateway.sol b/contracts/helpers/fluid/FluidDexETHGateway.sol new file mode 100644 index 00000000..af2d8aad --- /dev/null +++ b/contracts/helpers/fluid/FluidDexETHGateway.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; +import {ZeroAddressException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +import {IFluidDex, ConstantViews} from "../../integrations/fluid/IFluidDex.sol"; + +/// @title FluidDexETHGateway +/// @notice Gateway contract to connect credit accounts with FluidDex pools that use native ETH +/// @dev Converts WETH to ETH and vice versa for operational purposes +contract FluidDexETHGateway is IVersion { + using SafeERC20 for IERC20; + + bytes32 public constant override contractType = "GATEWAY::FLUID_DEX_ETH"; + uint256 public constant override version = 3_10; + + /// @notice Special address used by Fluid to represent native ETH + address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + /// @notice The underlying FluidDex pool + address public immutable pool; + + /// @notice WETH token address + address public immutable weth; + + /// @notice The other token in the pair (not ETH) + address public immutable otherToken; + + /// @notice Whether ETH is token0 in the pool (if false, it's token1) + bool public immutable ethIsToken0; + + /// @notice Constructor + /// @param _pool Address of the FluidDex pool + /// @param _weth WETH token address + constructor(address _pool, address _weth) { + if (_pool == address(0) || _weth == address(0)) { + revert ZeroAddressException(); + } + + pool = _pool; + weth = _weth; + + // Get token addresses from the pool + ConstantViews memory views = IFluidDex(_pool).constantsView(); + + // Determine which token is ETH and which is the other token + if (views.token0 == ETH) { + ethIsToken0 = true; + otherToken = views.token1; + } else if (views.token1 == ETH) { + ethIsToken0 = false; + otherToken = views.token0; + } else { + revert("Pool does not contain ETH"); + } + + // Approve the other token to be spent by the pool + IERC20(otherToken).forceApprove(_pool, type(uint256).max); + } + + /// @notice Swaps tokens through the FluidDex pool + /// @param swap0to1 Direction of swap (true for token0 to token1, false for token1 to token0) + /// @param amountIn Amount of input token to swap + /// @param amountOutMin Minimum amount of output token to receive + /// @param to Recipient of the swap output + /// @return amountOut Amount of tokens received + function swapIn(bool swap0to1, uint256 amountIn, uint256 amountOutMin, address to) + external + returns (uint256 amountOut) + { + bool swapFromWeth = (ethIsToken0 && swap0to1) || (!ethIsToken0 && !swap0to1); + + if (swapFromWeth) { + IERC20(weth).safeTransferFrom(msg.sender, address(this), amountIn); + IWETH(weth).withdraw(amountIn); + amountOut = IFluidDex(pool).swapIn{value: amountIn}(swap0to1, amountIn, amountOutMin, to); + } else { + uint256 balance = IERC20(otherToken).balanceOf(address(this)); + IERC20(otherToken).safeTransferFrom(msg.sender, address(this), amountIn); + + amountIn = IERC20(otherToken).balanceOf(address(this)) - balance; + IFluidDex(pool).swapIn(swap0to1, amountIn, amountOutMin, address(this)); + + IWETH(weth).deposit{value: address(this).balance}(); + amountOut = _transferAllTokensOf(weth, to); + } + + return amountOut; + } + + /// @notice Returns the constant views from the underlying pool + /// @return views The constant views structure + function constantsView() external view returns (ConstantViews memory) { + ConstantViews memory views = IFluidDex(pool).constantsView(); + + // Replace ETH with WETH in the returned structure + if (ethIsToken0) { + views.token0 = weth; + } else { + views.token1 = weth; + } + + return views; + } + + /// @dev Transfers the current balance of a token to sender (minus 1 for gas savings) + /// @param _token Token to transfer + function _transferAllTokensOf(address _token, address _to) internal returns (uint256) { + uint256 balance = IERC20(_token).balanceOf(address(this)); + if (balance > 1) { + unchecked { + IERC20(_token).safeTransfer(_to, balance - 1); + return balance - 1; + } + } + return 0; + } + + /// @dev Allows the contract to receive ETH + receive() external payable {} +} diff --git a/contracts/helpers/infinifi/InfinifiUnwindingGateway.sol b/contracts/helpers/infinifi/InfinifiUnwindingGateway.sol new file mode 100644 index 00000000..62f3f883 --- /dev/null +++ b/contracts/helpers/infinifi/InfinifiUnwindingGateway.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol"; + +import { + IInfinifiGateway, + IInfinifiLockingController, + IInfinifiUnwindingModule, + UnwindingPosition +} from "../../integrations/infinifi/IInfinifiGateway.sol"; + +import {IInfinifiUnwindingGateway, UserUnwindingData} from "../../interfaces/infinifi/IInfinifiUnwindingGateway.sol"; + +/// @title Infinifi Withdrawal Gateway +contract InfinifiUnwindingGateway is IInfinifiUnwindingGateway { + bytes32 public constant override contractType = "GATEWAY::INFINIFI_UNWINDING"; + uint256 public constant override version = 3_10; + + uint256 internal constant EPOCH = 1 weeks; + uint256 internal constant EPOCH_OFFSET = 3 days; + + address public immutable iUSD; + + address public immutable infinifiGateway; + + address public immutable lockingController; + + address public immutable unwindingModule; + + uint256 public lastUnwindingTimestamp; + + mapping(address => UserUnwindingData) internal userToUnwindingData; + + constructor(address _infinifiGateway) { + infinifiGateway = _infinifiGateway; + iUSD = IInfinifiGateway(infinifiGateway).getAddress("receiptToken"); + lockingController = IInfinifiGateway(infinifiGateway).getAddress("lockingController"); + unwindingModule = IInfinifiLockingController(lockingController).unwindingModule(); + } + + function startUnwinding(uint256 shares, uint32 unwindingEpochs) external { + if (block.timestamp == lastUnwindingTimestamp) revert MoreThanOneUnwindingPerBlockException(); + + UserUnwindingData storage userUnwindingData = userToUnwindingData[msg.sender]; + if (userUnwindingData.unwindingTimestamp != 0) revert UserAlreadyUnwindingException(); + + address lockedToken = IInfinifiLockingController(lockingController).shareToken(unwindingEpochs); + + IERC20(lockedToken).transferFrom(msg.sender, address(this), shares); + IERC20(lockedToken).approve(infinifiGateway, shares); + + userUnwindingData.shares = shares; + userUnwindingData.unwindingTimestamp = block.timestamp; + userUnwindingData.isWithdrawn = false; + userUnwindingData.unwindingEpochs = unwindingEpochs; + lastUnwindingTimestamp = block.timestamp; + + IInfinifiGateway(infinifiGateway).startUnwinding(shares, unwindingEpochs); + } + + function withdraw(uint256 amount) external { + UserUnwindingData memory userUnwindingData = userToUnwindingData[msg.sender]; + if (userUnwindingData.unwindingTimestamp == 0) revert UserNotUnwindingException(); + + uint256 claimableTimestamp = _getClaimableTimestamp(userUnwindingData); + + if (block.timestamp < claimableTimestamp) revert UnwindingNotClaimableException(); + + if (!userUnwindingData.isWithdrawn) { + uint256 balanceBefore = IERC20(iUSD).balanceOf(address(this)); + IInfinifiGateway(infinifiGateway).withdraw(userUnwindingData.unwindingTimestamp); + userUnwindingData.isWithdrawn = true; + userUnwindingData.unclaimedAssets = IERC20(iUSD).balanceOf(address(this)) - balanceBefore; + } + + uint256 pendingAssets = _getPendingAssets(userUnwindingData); + if (pendingAssets < amount) revert InsufficientPendingAssetsException(); + + userUnwindingData.unclaimedAssets -= amount; + IERC20(iUSD).transfer(msg.sender, amount); + + if (userUnwindingData.unclaimedAssets <= 1) { + userUnwindingData.unwindingTimestamp = 0; + userUnwindingData.shares = 0; + userUnwindingData.unclaimedAssets = 0; + userUnwindingData.unwindingEpochs = 0; + userUnwindingData.isWithdrawn = false; + } + + userToUnwindingData[msg.sender] = userUnwindingData; + } + + function getPendingAssets(address user) public view returns (uint256) { + return _getPendingAssets(userToUnwindingData[user]); + } + + function getUserUnwindingData(address user) external view returns (UserUnwindingData memory) { + return userToUnwindingData[user]; + } + + function _getPendingAssets(UserUnwindingData memory userUnwindingData) internal view returns (uint256) { + if (userUnwindingData.unwindingTimestamp == 0) return 0; + + return userUnwindingData.isWithdrawn + ? userUnwindingData.unclaimedAssets + : IInfinifiUnwindingModule(unwindingModule).balanceOf(address(this), userUnwindingData.unwindingTimestamp); + } + + function _getClaimableTimestamp(UserUnwindingData memory userUnwindingData) internal view returns (uint256) { + UnwindingPosition memory position = + IInfinifiUnwindingModule(unwindingModule).positions(_unwindingId(userUnwindingData.unwindingTimestamp)); + + uint256 claimableEpoch = position.toEpoch; + + return claimableEpoch * EPOCH + EPOCH_OFFSET; + } + + function _unwindingId(uint256 unwindingTimestamp) internal view returns (bytes32) { + return keccak256(abi.encode(address(this), unwindingTimestamp)); + } +} diff --git a/contracts/helpers/infinifi/InfinifiUnwindingPhantomToken.sol b/contracts/helpers/infinifi/InfinifiUnwindingPhantomToken.sol new file mode 100644 index 00000000..5e753391 --- /dev/null +++ b/contracts/helpers/infinifi/InfinifiUnwindingPhantomToken.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {PhantomERC20} from "../PhantomERC20.sol"; +import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; +import {IInfinifiUnwindingGateway} from "../../interfaces/infinifi/IInfinifiUnwindingGateway.sol"; + +/// @title Infinifi Unwinding phantom token +/// @notice Phantom ERC-20 token that represents the balance of the pending and claimable withdrawals in Infinifi Unwinding Gateway +contract InfinifiUnwindingPhantomToken is PhantomERC20, Ownable, IPhantomToken { + event SetClaimer(address indexed claimer); + + error SubvaultClaimerMismatchException(); + + bytes32 public constant override contractType = "PHANTOM_TOKEN::INFINIFI_UNWIND"; + + uint256 public constant override version = 3_10; + + address public immutable infinifiUnwindingGateway; + + /// @notice Constructor + /// @param _infinifiUnwindingGateway The Infinifi Unwinding Gateway where the pending assets are tracked + constructor(address _infinifiUnwindingGateway) + PhantomERC20( + IInfinifiUnwindingGateway(_infinifiUnwindingGateway).iUSD(), + "Infinifi Unwinding iUSD", + "wdiUSD", + IERC20Metadata(IInfinifiUnwindingGateway(_infinifiUnwindingGateway).iUSD()).decimals() + ) + { + infinifiUnwindingGateway = _infinifiUnwindingGateway; + } + + /// @notice Returns the amount of assets pending/claimable for withdrawal + /// @param account The account for which the calculation is performed + function balanceOf(address account) public view returns (uint256 balance) { + return IInfinifiUnwindingGateway(infinifiUnwindingGateway).getPendingAssets(account); + } + + /// @notice Returns phantom token's target contract and underlying + function getPhantomTokenInfo() external view override returns (address, address) { + return (infinifiUnwindingGateway, underlying); + } + + function serialize() external view override returns (bytes memory) { + return abi.encode(infinifiUnwindingGateway, underlying); + } +} diff --git a/contracts/helpers/infrared/InfraredVaultPhantomToken.sol b/contracts/helpers/infrared/InfraredVaultPhantomToken.sol new file mode 100644 index 00000000..b24594d8 --- /dev/null +++ b/contracts/helpers/infrared/InfraredVaultPhantomToken.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IInfraredVault} from "../../integrations/infrared/IInfraredVault.sol"; +import {PhantomERC20} from "../PhantomERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; + +/// @title InfraredVault position token +/// @notice Phantom ERC-20 token that represents the balance of the staked position in an InfraredVault +contract InfraredVaultPhantomToken is PhantomERC20, IPhantomToken { + bytes32 public constant override contractType = "PHANTOM_TOKEN::INFRARED"; + + uint256 public constant override version = 3_10; + + /// @notice Address of the InfraredVault contract + address public immutable vault; + + /// @notice Constructor + /// @param _vault The InfraredVault contract where the balance is tracked + constructor(address _vault) + PhantomERC20( + IInfraredVault(_vault).stakingToken(), + string.concat("Infrared staked position ", IERC20Metadata(IInfraredVault(_vault).stakingToken()).name()), + string.concat("ir", IERC20Metadata(IInfraredVault(_vault).stakingToken()).symbol()), + IERC20Metadata(IInfraredVault(_vault).stakingToken()).decimals() + ) + { + vault = _vault; + } + + /// @notice Returns the amount of tokens staked in the InfraredVault + /// @param account The account for which the calculation is performed + function balanceOf(address account) public view override returns (uint256) { + return IInfraredVault(vault).balanceOf(account); + } + + /// @notice Returns phantom token's target contract and underlying + function getPhantomTokenInfo() external view override returns (address, address) { + return (vault, underlying); + } + + function serialize() external view override returns (bytes memory) { + return abi.encode(vault, underlying); + } +} diff --git a/contracts/helpers/kodiak/KodiakIslandGateway.sol b/contracts/helpers/kodiak/KodiakIslandGateway.sol new file mode 100644 index 00000000..e1f1d51b --- /dev/null +++ b/contracts/helpers/kodiak/KodiakIslandGateway.sol @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +import {WAD} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +import {IKodiakIslandGateway, Ratios} from "../../interfaces/kodiak/IKodiakIslandGateway.sol"; +import {IKodiakIsland, IKodiakPool} from "../../integrations/kodiak/IKodiakIsland.sol"; +import {IKodiakIslandRouter} from "../../integrations/kodiak/IKodiakIslandRouter.sol"; +import {IKodiakQuoter, QuoteExactInputSingleParams} from "../../integrations/kodiak/IKodiakQuoter.sol"; +import {IKodiakSwapRouter, ExactInputSingleParams} from "../../integrations/kodiak/IKodiakSwapRouter.sol"; + +contract KodiakIslandGateway is IKodiakIslandGateway { + using SafeERC20 for IERC20; + using Math for uint256; + + bytes32 public immutable contractType = "GATEWAY::KODIAK_ISLAND"; + uint256 public immutable version = 3_10; + + /// @notice The Kodiak Island router. + address public immutable kodiakIslandRouter; + + /// @notice The Kodiak Swap router. + address public immutable kodiakSwapRouter; + + /// @notice The Kodiak Quoter. + address public immutable kodiakQuoter; + + uint256 public constant BALANCED_PROPORTION = WAD / 2; + + constructor(address _kodiakIslandRouter, address _kodiakSwapRouter, address _kodiakQuoter) { + kodiakIslandRouter = _kodiakIslandRouter; + kodiakSwapRouter = _kodiakSwapRouter; + kodiakQuoter = _kodiakQuoter; + } + + /// SWAP + + function swap(address island, address tokenIn, uint256 amountIn, uint256 amountOutMin) + external + returns (uint256 amountOut) + { + (address token0, address token1) = _getIslandTokens(island); + + if (tokenIn != token0 && tokenIn != token1) revert InvalidTokenInException(); + + uint24 fee = IKodiakPool(IKodiakIsland(island).pool()).fee(); + + ExactInputSingleParams memory params = ExactInputSingleParams({ + tokenIn: tokenIn, + tokenOut: tokenIn == token0 ? token1 : token0, + fee: fee, + recipient: msg.sender, + deadline: block.timestamp, + amountIn: amountIn, + amountOutMinimum: amountOutMin, + sqrtPriceLimitX96: 0 + }); + + IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn); + IERC20(tokenIn).forceApprove(kodiakSwapRouter, amountIn); + amountOut = IKodiakSwapRouter(kodiakSwapRouter).exactInputSingle(params); + } + + function estimateSwap(address island, address tokenIn, uint256 amountIn) external returns (uint256 amountOut) { + (address token0, address token1) = _getIslandTokens(island); + if (tokenIn != token0 && tokenIn != token1) revert InvalidTokenInException(); + + uint24 fee = IKodiakPool(IKodiakIsland(island).pool()).fee(); + + QuoteExactInputSingleParams memory params = QuoteExactInputSingleParams({ + tokenIn: tokenIn, + tokenOut: tokenIn == token0 ? token1 : token0, + amountIn: amountIn, + fee: fee, + sqrtPriceLimitX96: 0 + }); + + (amountOut,,,) = IKodiakQuoter(kodiakQuoter).quoteExactInputSingle(params); + } + + /// ADD LIQUIDITY + + /// @notice Add liquidity to an island with an imbalanced ratio. This function will compute the ratios automatically, + /// which will make a deposit closer to the optimal ratio and yield a slightly better result, at a significant additional gas cost. + function addLiquidityImbalanced( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver + ) external returns (uint256 lpAmount) { + (address token0, address token1) = _getIslandTokens(island); + Ratios memory ratios = _getRatios(island, token0, token1, amount0, amount1); + lpAmount = _addLiquidityImbalanced(island, token0, token1, amount0, amount1, minLPAmount, receiver, ratios); + } + + /// @notice Add liquidity to an island with an imbalanced ratio. This function accepts ratios that were computed elsewhere. + function addLiquidityImbalancedAssisted( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver, + Ratios memory ratios + ) external returns (uint256 lpAmount) { + (address token0, address token1) = _getIslandTokens(island); + lpAmount = _addLiquidityImbalanced(island, token0, token1, amount0, amount1, minLPAmount, receiver, ratios); + } + + /// @dev Internal function for adding liquidity to an island with an imbalanced ratio. + function _addLiquidityImbalanced( + address island, + address token0, + address token1, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver, + Ratios memory ratios + ) internal returns (uint256 lpAmount) { + IERC20(token0).safeTransferFrom(msg.sender, address(this), amount0); + IERC20(token1).safeTransferFrom(msg.sender, address(this), amount1); + + uint256 amountIn = _getSwappedAmount(amount0, amount1, ratios); + + uint256 amountOut = _swapExtra(island, token0, token1, amountIn, false, ratios.is0to1); + + uint256 depositAmount0 = ratios.is0to1 ? amount0 - amountIn : amount0 + amountOut; + uint256 depositAmount1 = ratios.is0to1 ? amount1 + amountOut : amount1 - amountIn; + + IERC20(token0).forceApprove(kodiakIslandRouter, depositAmount0); + IERC20(token1).forceApprove(kodiakIslandRouter, depositAmount1); + + (,, lpAmount) = IKodiakIslandRouter(kodiakIslandRouter).addLiquidity( + island, depositAmount0, depositAmount1, 0, 0, minLPAmount, receiver + ); + + _sweepTokens(token0, token1, receiver); + } + + /// @notice Estimate the amount of LP tokens that will be received when adding liquidity to an island with an imbalanced ratio. + /// Also returns precomputed deposit and price ratios to perform a swap during execution. + function estimateAddLiquidityImbalanced(address island, uint256 amount0, uint256 amount1) + external + returns (uint256 lpAmount, Ratios memory ratios) + { + (address token0, address token1) = _getIslandTokens(island); + + ratios = _getRatios(island, token0, token1, amount0, amount1); + + uint256 amountIn = _getSwappedAmount(amount0, amount1, ratios); + + uint256 amountOut = _swapExtra(island, token0, token1, amountIn, true, ratios.is0to1); + + uint256 depositAmount0 = ratios.is0to1 ? amount0 - amountIn : amount0 + amountOut; + uint256 depositAmount1 = ratios.is0to1 ? amount1 + amountOut : amount1 - amountIn; + + lpAmount = _getSwapAdjustedMintAmounts(island, amountIn, amountOut, depositAmount0, depositAmount1, ratios); + } + + /// REMOVE LIQUIDITY + + function removeLiquiditySingle( + address island, + uint256 lpAmount, + address tokenOut, + uint256 minAmountOut, + address receiver + ) external returns (uint256 amountOut) { + IERC20(island).safeTransferFrom(msg.sender, address(this), lpAmount); + + (uint256 amount0, uint256 amount1) = _removeLiquidity(island, lpAmount); + + (address token0, address token1) = _getIslandTokens(island); + + bool is0to1 = tokenOut == token1; + + _swapExtra(island, token0, token1, is0to1 ? amount0 : amount1, false, is0to1); + + (amount0, amount1) = _sweepTokens(token0, token1, receiver); + + amountOut = is0to1 ? amount1 : amount0; + + if (amountOut < minAmountOut) revert InsufficientAmountOutException(); + + return amountOut; + } + + /// @dev Internal function to remove balanced liquidity from an island. + function _removeLiquidity(address island, uint256 lpAmount) internal returns (uint256 amount0, uint256 amount1) { + IERC20(island).forceApprove(kodiakIslandRouter, lpAmount); + (amount0, amount1,) = + IKodiakIslandRouter(kodiakIslandRouter).removeLiquidity(island, lpAmount, 0, 0, address(this)); + } + + /// @notice Estimate the amount of tokens that will be received when removing liquidity from an island with an imbalanced ratio. + function estimateRemoveLiquiditySingle(address island, uint256 lpAmount, address tokenOut) + external + returns (uint256 amountOut) + { + (address token0, address token1) = _getIslandTokens(island); + + (uint256 balance0, uint256 balance1) = IKodiakIsland(island).getUnderlyingBalances(); + + uint256 totalSupply = IERC20(island).totalSupply(); + + uint256 amount0 = lpAmount.mulDiv(balance0, totalSupply); + uint256 amount1 = lpAmount.mulDiv(balance1, totalSupply); + + bool is0to1 = tokenOut == token1; + + amountOut = _swapExtra(island, token0, token1, is0to1 ? amount0 : amount1, true, is0to1); + + amountOut += is0to1 ? amount1 : amount0; + } + + /// HELPERS + + /// @dev Internal function to quote or execute a swap between island tokens. + function _swapExtra(address island, address token0, address token1, uint256 amountIn, bool isQuote, bool is0to1) + internal + returns (uint256 amountOut) + { + if (amountIn == 0) return 0; + + uint24 fee = IKodiakPool(IKodiakIsland(island).pool()).fee(); + + if (isQuote) { + QuoteExactInputSingleParams memory params = QuoteExactInputSingleParams({ + tokenIn: is0to1 ? token0 : token1, + tokenOut: is0to1 ? token1 : token0, + amountIn: amountIn, + fee: fee, + sqrtPriceLimitX96: 0 + }); + + (amountOut,,,) = IKodiakQuoter(kodiakQuoter).quoteExactInputSingle(params); + } else { + ExactInputSingleParams memory params = ExactInputSingleParams({ + tokenIn: is0to1 ? token0 : token1, + tokenOut: is0to1 ? token1 : token0, + fee: fee, + recipient: address(this), + deadline: block.timestamp, + amountIn: amountIn, + amountOutMinimum: 0, + sqrtPriceLimitX96: 0 + }); + + IERC20(is0to1 ? token0 : token1).forceApprove(kodiakSwapRouter, amountIn); + amountOut = IKodiakSwapRouter(kodiakSwapRouter).exactInputSingle(params); + } + } + + /// @dev Internal function to compute the deposit and price ratios required to balance amounts while adding liquidity. + /// @return ratios A struct with three values: + /// - priceRatio: The exchange price between token0 and token1, which is determined by querying a swap with one unit of the token. + /// - balance0: The balance of token0 in the island. + /// - balance1: The balance of token1 in the island. + /// - swapAll: Whether to swap all of the input amount of the token that needs to be swapped. + /// - is0to1: Whether token0 needs to be swapped to token1, or vice versa. + function _getRatios(address island, address token0, address token1, uint256 input0, uint256 input1) + internal + returns (Ratios memory ratios) + { + (uint256 balance0, uint256 balance1) = IKodiakIsland(island).getUnderlyingBalances(); + + ratios.balance0 = balance0; + ratios.balance1 = balance1; + + /// If the current price is outside the Kodiak Island range, we need to swap one token to another entirely + if (balance0 == 0) { + ratios.swapAll = true; + ratios.is0to1 = true; + return ratios; + } else if (balance1 == 0) { + ratios.swapAll = true; + ratios.is0to1 = false; + return ratios; + } + + uint24 fee = IKodiakPool(IKodiakIsland(island).pool()).fee(); + + /// If amount0 / amount1 is greater than the required deposit ratio of the island, then we need to swap token0 to token1. + /// Otherwise, we need to swap token1 to token0. + if (balance0 * input1 < balance1 * input0) { + uint256 amountIn = 10 ** IERC20Metadata(token0).decimals(); + + QuoteExactInputSingleParams memory params = QuoteExactInputSingleParams({ + tokenIn: token0, + tokenOut: token1, + amountIn: amountIn, + fee: fee, + sqrtPriceLimitX96: 0 + }); + + (uint256 amountOut,,,) = IKodiakQuoter(kodiakQuoter).quoteExactInputSingle(params); + + ratios.priceRatio = amountOut.mulDiv(WAD, amountIn); + + ratios.is0to1 = true; + } else { + uint256 amountIn = 10 ** IERC20Metadata(token1).decimals(); + + QuoteExactInputSingleParams memory params = QuoteExactInputSingleParams({ + tokenIn: token1, + tokenOut: token0, + amountIn: amountIn, + fee: fee, + sqrtPriceLimitX96: 0 + }); + + (uint256 amountOut,,,) = IKodiakQuoter(kodiakQuoter).quoteExactInputSingle(params); + + ratios.priceRatio = amountOut.mulDiv(WAD, amountIn); + + ratios.is0to1 = false; + } + } + + /// @dev Internal function to compute the amount of tokens to swap in order to balance amounts while adding liquidity. + /// @dev This returns a solution to the equation (x - dx) / (y + dx * p) = r. + function _getSwappedAmount(uint256 amount0, uint256 amount1, Ratios memory ratios) + internal + pure + returns (uint256 amountIn) + { + if (ratios.swapAll) return ratios.is0to1 ? amount0 : amount1; + + if (!ratios.is0to1) (amount0, amount1) = (amount1, amount0); + + (uint256 balance0, uint256 balance1) = (ratios.balance0, ratios.balance1); + + if (!ratios.is0to1) (balance0, balance1) = (balance1, balance0); + + uint256 numerator = amount0 * balance1 - amount1 * balance0; + uint256 denominator = (amount0 + balance0).mulDiv(ratios.priceRatio, WAD) + balance1 + amount1; + + return numerator / denominator; + } + + /// @dev Computes amount of tokens that will be minted with updated island balances after the swap + /// @dev In the case where the swap moves the price outside the Island range, we approximate the change in the second token's balance + /// proportionally to the remaining capacity in the first token. Otherwise, we update with exact amounts. + function _getSwapAdjustedMintAmounts( + address island, + uint256 amountIn, + uint256 amountOut, + uint256 depositAmount0, + uint256 depositAmount1, + Ratios memory ratios + ) internal view returns (uint256 lpAmount) { + (uint256 balance0, uint256 balance1) = (ratios.balance0, ratios.balance1); + + if (ratios.is0to1) { + if (balance1 < amountOut) { + balance0 = balance0 + balance1 * amountIn / amountOut; + balance1 = 0; + } else { + balance0 = balance0 + amountIn; + balance1 = balance1 - amountOut; + } + } else { + if (balance0 < amountOut) { + balance1 = balance1 + balance0 * amountIn / amountOut; + balance0 = 0; + } else { + balance0 = balance0 - amountOut; + balance1 = balance1 + amountIn; + } + } + + uint256 totalSupply = IERC20(island).totalSupply(); + + if (balance0 == 0) { + lpAmount = depositAmount1 * totalSupply / balance1; + } else if (balance1 == 0) { + lpAmount = depositAmount0 * totalSupply / balance0; + } else { + uint256 amount0Mint = depositAmount0 * totalSupply / balance0; + uint256 amount1Mint = depositAmount1 * totalSupply / balance1; + + lpAmount = amount0Mint < amount1Mint ? amount0Mint : amount1Mint; + } + } + + /// @dev Internal function to get the island tokens. + function _getIslandTokens(address island) internal view returns (address token0, address token1) { + token0 = IKodiakIsland(island).token0(); + token1 = IKodiakIsland(island).token1(); + } + + /// @dev Internal function to transfer all remaining island tokens to a receiver. + function _sweepTokens(address token0, address token1, address receiver) + internal + returns (uint256 balance0, uint256 balance1) + { + balance0 = IERC20(token0).balanceOf(address(this)); + balance1 = IERC20(token1).balanceOf(address(this)); + + if (balance0 > 1) IERC20(token0).safeTransfer(receiver, balance0 - 1); + if (balance1 > 1) IERC20(token1).safeTransfer(receiver, balance1 - 1); + } +} diff --git a/contracts/helpers/lido/LidoV1_WETHGateway.sol b/contracts/helpers/lido/LidoV1_WETHGateway.sol index 284bf182..f51f78ca 100644 --- a/contracts/helpers/lido/LidoV1_WETHGateway.sol +++ b/contracts/helpers/lido/LidoV1_WETHGateway.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; pragma abicoder v1; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol"; import {ReceiveIsNotAllowedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; @@ -13,7 +14,10 @@ import {IstETH} from "../../integrations/lido/IstETH.sol"; /// @title LidoV1 Gateway /// @notice Allows to submit WETH directly into stETH contract -contract LidoV1Gateway is SanityCheckTrait { +contract LidoV1Gateway is SanityCheckTrait, IVersion { + bytes32 public constant override contractType = "GATEWAY::LIDO_V1"; + uint256 public constant override version = 3_10; + /// @notice WETH token address public immutable weth; diff --git a/contracts/helpers/mellow/MellowWithdrawalPhantomToken.sol b/contracts/helpers/mellow/MellowWithdrawalPhantomToken.sol new file mode 100644 index 00000000..7c7a528b --- /dev/null +++ b/contracts/helpers/mellow/MellowWithdrawalPhantomToken.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IMellowMultiVault, IMellowWithdrawalQueue, Subvault} from "../../integrations/mellow/IMellowMultiVault.sol"; +import {PhantomERC20} from "../PhantomERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; + +/// @title MellowLRT withdrawal phantom token +/// @notice Phantom ERC-20 token that represents the balance of the pending and claimable withdrawals in Mellow vaults +contract MellowWithdrawalPhantomToken is PhantomERC20, Ownable, IPhantomToken { + event SetClaimer(address indexed claimer); + + error SubvaultClaimerMismatchException(); + + bytes32 public constant override contractType = "PHANTOM_TOKEN::MELLOW_WITHDRAWAL"; + + uint256 public constant override version = 3_11; + + address public immutable multiVault; + + address public claimer; + + /// @notice Constructor + /// @param _ioProxy The address of the Instance Owner proxy + /// @param _multiVault The MultiVault where the pending assets are tracked + /// @param _claimer The address of the initial Claimer contract + constructor(address _ioProxy, address _multiVault, address _claimer) + PhantomERC20( + IERC4626(_multiVault).asset(), + string.concat("Mellow withdrawn ", IERC20Metadata(IERC4626(_multiVault).asset()).name()), + string.concat("wd", IERC20Metadata(IERC4626(_multiVault).asset()).symbol()), + IERC20Metadata(IERC4626(_multiVault).asset()).decimals() + ) + { + _transferOwnership(_ioProxy); + + multiVault = _multiVault; + claimer = _claimer; + } + + /// @notice Returns the amount of assets pending/claimable for withdrawal + /// @param account The account for which the calculation is performed + function balanceOf(address account) public view returns (uint256 balance) { + uint256 nSubvaults = IMellowMultiVault(multiVault).subvaultsCount(); + + for (uint256 i = 0; i < nSubvaults; ++i) { + Subvault memory subvault = IMellowMultiVault(multiVault).subvaultAt(i); + + if (subvault.withdrawalQueue == address(0)) continue; + + balance += IMellowWithdrawalQueue(subvault.withdrawalQueue).pendingAssetsOf(account) + + IMellowWithdrawalQueue(subvault.withdrawalQueue).claimableAssetsOf(account); + } + } + + /// @notice Returns phantom token's target contract and underlying + function getPhantomTokenInfo() external view override returns (address, address) { + return (claimer, underlying); + } + + function serialize() external view override returns (bytes memory) { + return abi.encode(claimer, underlying); + } + + /// @notice Sets the address of the Claimer contract + function setClaimer(address _claimer) external onlyOwner { + if (_claimer != claimer) { + uint256 nSubvaults = IMellowMultiVault(multiVault).subvaultsCount(); + + for (uint256 i = 0; i < nSubvaults; ++i) { + Subvault memory subvault = IMellowMultiVault(multiVault).subvaultAt(i); + + if (subvault.withdrawalQueue == address(0)) continue; + + address queueClaimer = IMellowWithdrawalQueue(subvault.withdrawalQueue).claimer(); + + if (queueClaimer != _claimer) revert SubvaultClaimerMismatchException(); + } + + claimer = _claimer; + emit SetClaimer(_claimer); + } + } +} diff --git a/contracts/helpers/sky/StakingRewardsPhantomToken.sol b/contracts/helpers/sky/StakingRewardsPhantomToken.sol index 3118f0a9..a5d78d73 100644 --- a/contracts/helpers/sky/StakingRewardsPhantomToken.sol +++ b/contracts/helpers/sky/StakingRewardsPhantomToken.sol @@ -1,16 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {PhantomERC20} from "@gearbox-protocol/core-v2/contracts/tokens/PhantomERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IStakingRewards} from "../../integrations/sky/IStakingRewards.sol"; +import {PhantomERC20} from "../PhantomERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; /// @title StakingRewards position token /// @notice Phantom ERC-20 token that represents the balance of the staked position in a StakingRewards pool -contract StakingRewardsPhantomToken is PhantomERC20 { +contract StakingRewardsPhantomToken is PhantomERC20, IPhantomToken { + bytes32 public constant override contractType = "PHANTOM_TOKEN::STAKING_REWARDS"; + + uint256 public constant override version = 3_10; + address public immutable pool; /// @notice Constructor @@ -35,4 +41,13 @@ contract StakingRewardsPhantomToken is PhantomERC20 { function balanceOf(address account) public view returns (uint256) { return IERC20(pool).balanceOf(account); } + + /// @notice Returns phantom token's target contract and underlying + function getPhantomTokenInfo() external view override returns (address, address) { + return (pool, underlying); + } + + function serialize() external view override returns (bytes memory) { + return abi.encode(pool, underlying); + } } diff --git a/contracts/helpers/uniswap/UniswapV4Gateway.sol b/contracts/helpers/uniswap/UniswapV4Gateway.sol new file mode 100644 index 00000000..e52c4aba --- /dev/null +++ b/contracts/helpers/uniswap/UniswapV4Gateway.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import { + IUniversalRouter, + UniswapV4ExactInputSingleParams, + PoolKey, + COMMAND_V4_SWAP, + ACTION_SWAP_IN_SINGLE, + ACTION_SETTLE_ALL, + ACTION_TAKE_ALL +} from "../../integrations/uniswap/IUniswapUniversalRouter.sol"; +import {IUniswapV4Gateway} from "../../interfaces/uniswap/IUniswapV4Gateway.sol"; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; + +interface IPermit2 { + function approve(address token, address spender, uint160 amount, uint48 expiration) external; +} + +/// @title UniswapV4Gateway +/// @dev This is connector contract to allow Gearbox adapters to swap through Uniswap V4 pools via Uniswap Universal Router. +/// Since Uniswap V4 works with native ETH and requires approval in Permit2, we need an intermediate contract. +contract UniswapV4Gateway is IUniswapV4Gateway, IVersion { + using SafeERC20 for IERC20; + + bytes32 public constant override contractType = "GATEWAY::UNISWAP_V4"; + uint256 public constant override version = 3_10; + + address public immutable universalRouter; + address public immutable poolManager; + address public immutable permit2; + address public immutable weth; + + constructor(address _universalRouter, address _permit2, address _weth) { + universalRouter = _universalRouter; + poolManager = IUniversalRouter(_universalRouter).poolManager(); + permit2 = _permit2; + weth = _weth; + } + + function swapExactInputSingle( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 amountIn, + uint128 amountOutMinimum, + bytes calldata hookData + ) external returns (uint256 amountOut) { + address tokenIn = zeroForOne ? poolKey.token0 : poolKey.token1; + address tokenOut = zeroForOne ? poolKey.token1 : poolKey.token0; + + amountIn = uint128(_transferIn(tokenIn, msg.sender, amountIn)); + + (bytes memory commands, bytes[] memory inputs) = + _getInputData(poolKey, zeroForOne, amountIn, amountOutMinimum, hookData); + + amountOut = _swap(commands, inputs, tokenIn, tokenOut, amountIn); + + _transferOut(tokenOut, msg.sender, amountOut); + } + + function _swap(bytes memory commands, bytes[] memory inputs, address tokenIn, address tokenOut, uint128 amountIn) + internal + returns (uint256 amountOut) + { + if (tokenIn == address(0)) { + uint256 balanceBefore = _getBalance(tokenOut); + IUniversalRouter(universalRouter).execute{value: amountIn}(commands, inputs); + amountOut = _getBalance(tokenOut) - balanceBefore; + } else { + IERC20(tokenIn).forceApprove(permit2, amountIn); + IPermit2(permit2).approve(address(tokenIn), universalRouter, uint160(amountIn), uint48(block.timestamp)); + + uint256 balanceBefore = _getBalance(tokenOut); + IUniversalRouter(universalRouter).execute(commands, inputs); + amountOut = _getBalance(tokenOut) - balanceBefore; + } + } + + function _getInputData( + PoolKey memory poolKey, + bool zeroForOne, + uint128 amountIn, + uint128 amountOutMinimum, + bytes calldata hookData + ) internal pure returns (bytes memory commands, bytes[] memory inputs) { + commands = abi.encodePacked(uint8(COMMAND_V4_SWAP)); + + inputs = new bytes[](1); + bytes memory actions = + abi.encodePacked(uint8(ACTION_SWAP_IN_SINGLE), uint8(ACTION_SETTLE_ALL), uint8(ACTION_TAKE_ALL)); + + bytes[] memory params = new bytes[](3); + params[0] = abi.encode( + UniswapV4ExactInputSingleParams({ + poolKey: poolKey, + zeroForOne: zeroForOne, + amountIn: amountIn, + amountOutMinimum: amountOutMinimum, + hookData: hookData + }) + ); + + params[1] = abi.encode(zeroForOne ? poolKey.token0 : poolKey.token1, amountIn); + + params[2] = abi.encode(zeroForOne ? poolKey.token1 : poolKey.token0, amountOutMinimum); + + inputs[0] = abi.encode(actions, params); + } + + function _transferIn(address token, address from, uint256 amount) internal returns (uint256 transferredAmount) { + if (token == address(0)) { + uint256 balanceBefore = IERC20(weth).balanceOf(address(this)); + IERC20(weth).safeTransferFrom(from, address(this), amount); + transferredAmount = IERC20(weth).balanceOf(address(this)) - balanceBefore; + IWETH(weth).withdraw(transferredAmount); + } else { + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); + IERC20(token).safeTransferFrom(from, address(this), amount); + transferredAmount = IERC20(token).balanceOf(address(this)) - balanceBefore; + } + return transferredAmount; + } + + function _getBalance(address token) internal view returns (uint256 balance) { + if (token == address(0)) { + return address(this).balance; + } else { + return IERC20(token).balanceOf(address(this)); + } + } + + function _transferOut(address token, address to, uint256 amount) internal { + if (token == address(0)) { + IWETH(weth).deposit{value: amount}(); + IERC20(weth).safeTransfer(to, amount); + } else { + IERC20(token).safeTransfer(to, amount); + } + } + + receive() external payable { + if (msg.sender != poolManager && msg.sender != weth) { + revert UnexpectedETHTransferException(); + } + } +} diff --git a/contracts/helpers/upshift/UpshiftVaultGateway.sol b/contracts/helpers/upshift/UpshiftVaultGateway.sol new file mode 100644 index 00000000..ba9f1f96 --- /dev/null +++ b/contracts/helpers/upshift/UpshiftVaultGateway.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {ReentrancyGuardTrait} from "@gearbox-protocol/core-v3/contracts/traits/ReentrancyGuardTrait.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IUpshiftVault} from "../../integrations/upshift/IUpshiftVault.sol"; +import {IUpshiftVaultGateway} from "../../interfaces/upshift/IUpshiftVaultGateway.sol"; + +struct PendingRedeem { + uint256 claimableTimestamp; + uint256 assets; + uint256 year; + uint256 month; + uint256 day; +} + +contract UpshiftVaultGateway is ReentrancyGuardTrait, IUpshiftVaultGateway { + using SafeERC20 for IERC20; + + bytes32 public constant override contractType = "GATEWAY::UPSHIFT_VAULT"; + uint256 public constant override version = 3_10; + + address public immutable upshiftVault; + + address public immutable asset; + + mapping(address => PendingRedeem) public pendingRedeems; + + constructor(address _upshiftVault) { + upshiftVault = _upshiftVault; + asset = IERC4626(_upshiftVault).asset(); + } + + function deposit(uint256 assets, address receiver) external nonReentrant { + IERC20(asset).safeTransferFrom(msg.sender, address(this), assets); + IERC20(asset).forceApprove(upshiftVault, assets); + IERC4626(upshiftVault).deposit(assets, receiver); + } + + function mint(uint256 shares, address receiver) external nonReentrant { + uint256 amount = IERC4626(upshiftVault).previewMint(shares); + + IERC20(asset).safeTransferFrom(msg.sender, address(this), amount); + IERC20(asset).forceApprove(upshiftVault, amount); + IERC4626(upshiftVault).mint(shares, receiver); + } + + function requestRedeem(uint256 shares) external nonReentrant { + if (pendingRedeems[msg.sender].assets > 0) { + revert("UpshiftVaultGateway: user has a pending redeem"); + } + + (uint256 year, uint256 month, uint256 day, uint256 claimableTimestamp) = + IUpshiftVault(upshiftVault).getWithdrawalEpoch(); + + uint256 assets = IERC4626(upshiftVault).previewRedeem(shares); + + pendingRedeems[msg.sender] = + PendingRedeem({claimableTimestamp: claimableTimestamp, assets: assets, year: year, month: month, day: day}); + + IUpshiftVault(upshiftVault).requestRedeem({shares: shares, receiverAddr: address(this), holderAddr: msg.sender}); + } + + function claim(uint256 amount) external nonReentrant { + PendingRedeem memory pendingRedeem = pendingRedeems[msg.sender]; + + if (pendingRedeem.assets == 0) { + revert("UpshiftVaultGateway: user does not have a pending redeem"); + } + + if (amount > pendingRedeem.assets) { + revert("UpshiftVaultGateway: amount is greater than the pending redeem"); + } + + if (pendingRedeem.claimableTimestamp > block.timestamp) { + revert("UpshiftVaultGateway: redeem is not claimable yet"); + } + + uint256 totalClaimableAssets = IUpshiftVault(upshiftVault).getClaimableAmountByReceiver( + pendingRedeem.year, pendingRedeem.month, pendingRedeem.day, address(this) + ); + + if (totalClaimableAssets > 0) { + IUpshiftVault(upshiftVault).claim(pendingRedeem.year, pendingRedeem.month, pendingRedeem.day, address(this)); + } + + pendingRedeems[msg.sender].assets -= amount; + + IERC20(asset).safeTransfer(msg.sender, amount); + } + + function pendingAssetsOf(address holderAddr) external view returns (uint256) { + return pendingRedeems[holderAddr].assets; + } + + function previewDeposit(uint256 assets) external view returns (uint256) { + return IERC4626(upshiftVault).previewDeposit(assets); + } + + function previewRedeem(uint256 shares) external view returns (uint256) { + return IERC4626(upshiftVault).previewRedeem(shares); + } + + function convertToAssets(uint256 shares) external view returns (uint256) { + return IERC4626(upshiftVault).convertToAssets(shares); + } + + function convertToShares(uint256 assets) external view returns (uint256) { + return IERC4626(upshiftVault).convertToShares(assets); + } + + function decimals() external view returns (uint8) { + return IERC4626(upshiftVault).decimals(); + } + + function name() external view returns (string memory) { + return IERC4626(upshiftVault).name(); + } + + function symbol() external view returns (string memory) { + return IERC4626(upshiftVault).symbol(); + } +} diff --git a/contracts/helpers/upshift/UpshiftVaultWithdrawalPhantomToken.sol b/contracts/helpers/upshift/UpshiftVaultWithdrawalPhantomToken.sol new file mode 100644 index 00000000..cc3eda9a --- /dev/null +++ b/contracts/helpers/upshift/UpshiftVaultWithdrawalPhantomToken.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IUpshiftVault} from "../../integrations/upshift/IUpshiftVault.sol"; +import {IUpshiftVaultGateway} from "../../interfaces/upshift/IUpshiftVaultGateway.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {PhantomERC20} from "../PhantomERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; + +/// @title UpshiftVault withdrawal phantom token +/// @notice Phantom ERC-20 token that represents the balance of the pending and claimable withdrawals in UpshiftVault vaults +contract UpshiftVaultWithdrawalPhantomToken is PhantomERC20, IPhantomToken { + bytes32 public constant override contractType = "PHANTOM_TOKEN::UPSHIFT_WITHDRAW"; + + uint256 public constant override version = 3_10; + + address public immutable vault; + + address public immutable gateway; + + /// @notice Constructor + /// @param _vault The vault where the balance is tracked + constructor(address _vault, address _gateway) + PhantomERC20( + IERC4626(_vault).asset(), + string.concat("UpshiftVault withdrawn ", IERC20Metadata(IERC4626(_vault).asset()).name()), + string.concat("wd", IERC20Metadata(IERC4626(_vault).asset()).symbol()), + IERC20Metadata(IERC4626(_vault).asset()).decimals() + ) + { + vault = _vault; + gateway = _gateway; + } + + /// @notice Returns the amount of assets pending/claimable for withdrawal + /// @param account The account for which the calculation is performed + function balanceOf(address account) public view returns (uint256) { + return IUpshiftVaultGateway(gateway).pendingAssetsOf(account); + } + + /// @notice Returns phantom token's target contract and underlying + function getPhantomTokenInfo() external view override returns (address, address) { + return (gateway, underlying); + } + + function serialize() external view override returns (bytes memory) { + return abi.encode(gateway, underlying); + } +} diff --git a/contracts/integrations/TokenType.sol b/contracts/integrations/TokenType.sol index 956dacb4..f9d198fc 100644 --- a/contracts/integrations/TokenType.sol +++ b/contracts/integrations/TokenType.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; enum TokenType { diff --git a/contracts/integrations/balancer/IBalancerV3Pool.sol b/contracts/integrations/balancer/IBalancerV3Pool.sol index df16eea0..46b8405d 100644 --- a/contracts/integrations/balancer/IBalancerV3Pool.sol +++ b/contracts/integrations/balancer/IBalancerV3Pool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/integrations/balancer/IBalancerV3Router.sol b/contracts/integrations/balancer/IBalancerV3Router.sol index 764c6e84..2308cea0 100644 --- a/contracts/integrations/balancer/IBalancerV3Router.sol +++ b/contracts/integrations/balancer/IBalancerV3Router.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/contracts/integrations/equalizer/IEqualizerRouter.sol b/contracts/integrations/equalizer/IEqualizerRouter.sol index 835d6132..cbc45100 100644 --- a/contracts/integrations/equalizer/IEqualizerRouter.sol +++ b/contracts/integrations/equalizer/IEqualizerRouter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; struct Route { address from; diff --git a/contracts/integrations/erc4626/IERC4626Referral.sol b/contracts/integrations/erc4626/IERC4626Referral.sol new file mode 100644 index 00000000..a75655ee --- /dev/null +++ b/contracts/integrations/erc4626/IERC4626Referral.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +interface IERC4626Referral { + function deposit(uint256 assets, address receiver, uint16 referral) external returns (uint256 shares); + function mint(uint256 shares, address receiver, uint16 referral) external returns (uint256 assets); +} diff --git a/contracts/integrations/fluid/IFluidDex.sol b/contracts/integrations/fluid/IFluidDex.sol new file mode 100644 index 00000000..76ba4fbc --- /dev/null +++ b/contracts/integrations/fluid/IFluidDex.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +struct Implementations { + address shift; + address admin; + address colOperations; + address debtOperations; + address perfectOperationsAndOracle; +} + +struct ConstantViews { + uint256 dexId; + address liquidity; + address factory; + Implementations implementations; + address deployerContract; + address token0; + address token1; + bytes32 supplyToken0Slot; + bytes32 borrowToken0Slot; + bytes32 supplyToken1Slot; + bytes32 borrowToken1Slot; + bytes32 exchangePriceToken0Slot; + bytes32 exchangePriceToken1Slot; + uint256 oracleMapping; +} + +interface IFluidDex { + function swapIn(bool swap0to1, uint256 amountIn, uint256 amountOutMin, address to) + external + payable + returns (uint256 amountOut); + + function constantsView() external view returns (ConstantViews memory); +} diff --git a/contracts/integrations/infinifi/IInfinifiGateway.sol b/contracts/integrations/infinifi/IInfinifiGateway.sol new file mode 100644 index 00000000..3abceb89 --- /dev/null +++ b/contracts/integrations/infinifi/IInfinifiGateway.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +struct UnwindingPosition { + uint256 shares; + uint32 fromEpoch; + uint32 toEpoch; + uint256 fromRewardWeight; + uint256 rewardWeightDecrease; +} + +interface IInfinifiGateway { + function mint(address to, uint256 amount) external; + + function stake(address to, uint256 amount) external; + + function unstake(address to, uint256 amount) external; + + function createPosition(uint256 amount, uint32 unwindingEpochs, address recipient) external; + + function startUnwinding(uint256 shares, uint32 unwindingEpochs) external; + + function withdraw(uint256 unwindingTimestamp) external; + + function redeem(address to, uint256 amount, uint256 minAssetsOut) external; + + function claimRedemption() external; + + function getAddress(string memory name) external view returns (address); +} + +interface IInfinifiMintController { + function receiptToken() external view returns (address); + + function assetToReceipt(uint256 _assetAmount) external view returns (uint256); +} + +interface IInfinifiLockingController { + function getEnabledBuckets() external view returns (uint32[] memory); + + function shareToken(uint32 unwindingEpochs) external view returns (address); + + function unwindingModule() external view returns (address); + + function exchangeRate(uint32 unwindingEpochs) external view returns (uint256); +} + +interface IInfinifiUnwindingModule { + function balanceOf(address user, uint256 unwindingTimestamp) external view returns (uint256); + + function positions(bytes32 id) external view returns (UnwindingPosition memory); +} + +interface IInfinifiRedeemController { + function receiptToAsset(uint256 amount) external view returns (uint256); + + function accounting() external view returns (address); +} + +interface IInfinifiAccounting { + function totalAssetsOf(address asset, uint256 farmType) external view returns (uint256); +} diff --git a/contracts/integrations/infrared/IInfraredVault.sol b/contracts/integrations/infrared/IInfraredVault.sol new file mode 100644 index 00000000..ec584aee --- /dev/null +++ b/contracts/integrations/infrared/IInfraredVault.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +struct UserReward { + address token; + uint256 amount; +} + +interface IInfraredVault { + function totalSupply() external view returns (uint256); + function stake(uint256 amount) external; + function withdraw(uint256 amount) external; + function getReward() external; + function exit() external; + function balanceOf(address account) external view returns (uint256); + function earned(address account, address _rewardsToken) external view returns (uint256); + function getRewardForUser(address _user) external; + function getAllRewardTokens() external view returns (address[] memory); + function getAllRewardsForUser(address _user) external view returns (UserReward[] memory); + function infrared() external view returns (address); + function rewardsVault() external view returns (address); + function stakingToken() external view returns (address); +} diff --git a/contracts/integrations/kodiak/IKodiakIsland.sol b/contracts/integrations/kodiak/IKodiakIsland.sol new file mode 100644 index 00000000..170b0c09 --- /dev/null +++ b/contracts/integrations/kodiak/IKodiakIsland.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +interface IKodiakIsland { + function getUnderlyingBalances() external view returns (uint256 balance0, uint256 balance1); + + function getMintAmounts(uint256 amount0, uint256 amount1) + external + view + returns (uint256 amount0Min, uint256 amount1Min, uint256 lpAmount); + + function token0() external view returns (address); + + function token1() external view returns (address); + + function pool() external view returns (address); +} + +interface IKodiakPool { + function fee() external view returns (uint24); +} diff --git a/contracts/integrations/kodiak/IKodiakIslandRouter.sol b/contracts/integrations/kodiak/IKodiakIslandRouter.sol new file mode 100644 index 00000000..aaec6616 --- /dev/null +++ b/contracts/integrations/kodiak/IKodiakIslandRouter.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +interface IKodiakIslandRouter { + function addLiquidity( + address island, + uint256 amount0Max, + uint256 amount1Max, + uint256 amount0Min, + uint256 amount1Min, + uint256 minLPAmount, + address receiver + ) external returns (uint256 amount0, uint256 amount1, uint256 mintAmount); + + function removeLiquidity(address island, uint256 lpAmount, uint256 amount0Min, uint256 amount1Min, address receiver) + external + returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); +} diff --git a/contracts/integrations/kodiak/IKodiakQuoter.sol b/contracts/integrations/kodiak/IKodiakQuoter.sol new file mode 100644 index 00000000..16320008 --- /dev/null +++ b/contracts/integrations/kodiak/IKodiakQuoter.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +struct QuoteExactInputSingleParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint24 fee; + uint160 sqrtPriceLimitX96; +} + +interface IKodiakQuoter { + function quoteExactInputSingle(QuoteExactInputSingleParams memory params) + external + returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); +} diff --git a/contracts/integrations/kodiak/IKodiakSwapRouter.sol b/contracts/integrations/kodiak/IKodiakSwapRouter.sol new file mode 100644 index 00000000..419fab1f --- /dev/null +++ b/contracts/integrations/kodiak/IKodiakSwapRouter.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; +} + +interface IKodiakSwapRouter { + function exactInputSingle(ExactInputSingleParams memory params) external returns (uint256 amountOut); +} diff --git a/contracts/integrations/lido/ILidoWithdrawalQueue.sol b/contracts/integrations/lido/ILidoWithdrawalQueue.sol new file mode 100644 index 00000000..d4f055a3 --- /dev/null +++ b/contracts/integrations/lido/ILidoWithdrawalQueue.sol @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.23; + +struct WithdrawalRequestStatus { + uint256 amountOfStETH; + uint256 amountOfShares; + address owner; + uint256 timestamp; + bool isFinalized; + bool isClaimed; +} + +interface ILidoWithdrawalQueue { + function requestWithdrawals(uint256[] memory amounts, address owner) + external + returns (uint256[] memory requestIds); + + function requestWithdrawalsWstETH(uint256[] calldata amounts, address owner) + external + returns (uint256[] memory requestIds); + + function getWithdrawalStatus(uint256[] calldata _requestIds) + external + view + returns (WithdrawalRequestStatus[] memory statuses); + + function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external; + + function findCheckpointHints(uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex) + external + view + returns (uint256[] memory hintIds); + + function getClaimableEther(uint256[] calldata _requestIds, uint256[] calldata _hints) + external + view + returns (uint256[] memory amounts); + + function getLastCheckpointIndex() external view returns (uint256); + + function getLastFinalizedRequestId() external view returns (uint256); + + function STETH() external view returns (address); + + function WSTETH() external view returns (address); + + function unfinalizedStETH() external view returns (uint256); +} diff --git a/contracts/integrations/mellow/IMellowClaimer.sol b/contracts/integrations/mellow/IMellowClaimer.sol new file mode 100644 index 00000000..fb5d7dea --- /dev/null +++ b/contracts/integrations/mellow/IMellowClaimer.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +interface IMellowClaimer { + function multiAcceptAndClaim( + address multiVault, + uint256[] calldata subvaultIndices, + uint256[][] calldata indices, + address recipient, + uint256 maxAssets + ) external returns (uint256 assets); +} diff --git a/contracts/integrations/mellow/IMellowMultiVault.sol b/contracts/integrations/mellow/IMellowMultiVault.sol new file mode 100644 index 00000000..153f4484 --- /dev/null +++ b/contracts/integrations/mellow/IMellowMultiVault.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +enum MellowProtocol { + SYMBIOTIC, + EIGEN_LAYER, + ERC4626 +} + +struct Subvault { + MellowProtocol protocol; + address vault; + address withdrawalQueue; +} + +interface IMellowMultiVault { + function asset() external view returns (address); + function withdrawalQueue() external view returns (address); + function subvaultsCount() external view returns (uint256); + function subvaultAt(uint256 index) external view returns (Subvault memory); + function depositWhitelist() external view returns (bool); +} + +interface IMellowWithdrawalQueue { + function pendingAssetsOf(address account) external view returns (uint256); + function claimableAssetsOf(address account) external view returns (uint256); + function claimer() external view returns (address); +} + +interface IEigenLayerWithdrawalQueue { + function getAccountData( + address account, + uint256 withdrawalsLimit, + uint256 withdrawalsOffset, + uint256 transferredWithdrawalsLimit, + uint256 transferredWithdrawalsOffset + ) + external + view + returns (uint256 claimableAssets, uint256[] memory withdrawals, uint256[] memory transferredWithdrawals); +} diff --git a/contracts/integrations/mellow/IMellowSimpleLRTVault.sol b/contracts/integrations/mellow/IMellowSimpleLRTVault.sol new file mode 100644 index 00000000..7c9b22b0 --- /dev/null +++ b/contracts/integrations/mellow/IMellowSimpleLRTVault.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +interface IMellowSimpleLRTVault { + function asset() external view returns (address); + function withdrawalQueue() external view returns (address); + function claim(address account, address recipient, uint256 maxAmount) external returns (uint256); + function pendingAssetsOf(address account) external view returns (uint256); + function claimableAssetsOf(address account) external view returns (uint256); +} + +interface IMellowWithdrawalQueue { + function balanceOf(address account) external view returns (uint256); +} diff --git a/contracts/integrations/mellow/IMellowVault.sol b/contracts/integrations/mellow/IMellowVault.sol index a9e8ec22..298eaed2 100644 --- a/contracts/integrations/mellow/IMellowVault.sol +++ b/contracts/integrations/mellow/IMellowVault.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; interface IMellowVault { /// @notice Returns an array of underlying tokens of the vault. diff --git a/contracts/integrations/mellow/IMellowWrapper.sol b/contracts/integrations/mellow/IMellowWrapper.sol new file mode 100644 index 00000000..04690f47 --- /dev/null +++ b/contracts/integrations/mellow/IMellowWrapper.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +interface IMellowWrapper { + function deposit(address depositToken, uint256 amount, address vault, address receiver, address referral) + external + returns (uint256 shares); + + function WETH() external view returns (address); +} diff --git a/contracts/integrations/pendle/IPendleRouter.sol b/contracts/integrations/pendle/IPendleRouter.sol index 11091aab..d6202827 100644 --- a/contracts/integrations/pendle/IPendleRouter.sol +++ b/contracts/integrations/pendle/IPendleRouter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; struct SwapData { SwapType swapType; diff --git a/contracts/integrations/sky/IDaiUsds.sol b/contracts/integrations/sky/IDaiUsds.sol index e6d3918b..646ecb09 100644 --- a/contracts/integrations/sky/IDaiUsds.sol +++ b/contracts/integrations/sky/IDaiUsds.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; interface IDaiUsds { function daiToUsds(address usr, uint256 wad) external; diff --git a/contracts/integrations/sky/IStakingRewards.sol b/contracts/integrations/sky/IStakingRewards.sol index 348f4d88..3287e868 100644 --- a/contracts/integrations/sky/IStakingRewards.sol +++ b/contracts/integrations/sky/IStakingRewards.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; /// @title Sky Staking Rewards Interface /// @notice Interface for the Sky StakingRewards contract @@ -12,3 +12,7 @@ interface IStakingRewards { function getReward() external; function earned(address account) external view returns (uint256); } + +interface IStakingRewardsReferral { + function stake(uint256 amount, uint16 referral) external; +} diff --git a/contracts/integrations/traderjoe/ITraderJoeRouter.sol b/contracts/integrations/traderjoe/ITraderJoeRouter.sol new file mode 100644 index 00000000..91842afe --- /dev/null +++ b/contracts/integrations/traderjoe/ITraderJoeRouter.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.10; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +enum Version { + V1, + V2, + V2_1, + V2_2 +} + +struct Path { + uint256[] pairBinSteps; + Version[] versions; + IERC20[] tokenPath; +} + +interface ITraderJoeRouter { + function getSwapOut(address lbPair, uint128 amountIn, bool swapForY) + external + view + returns (uint128 amountInLeft, uint128 amountOut, uint128 fee); + + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + Path memory path, + address to, + uint256 deadline + ) external returns (uint256 amountOut); + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint256 amountIn, + uint256 amountOutMin, + Path memory path, + address to, + uint256 deadline + ) external returns (uint256 amountOut); +} diff --git a/contracts/integrations/uniswap/IUniswapUniversalRouter.sol b/contracts/integrations/uniswap/IUniswapUniversalRouter.sol new file mode 100644 index 00000000..a97869e5 --- /dev/null +++ b/contracts/integrations/uniswap/IUniswapUniversalRouter.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +struct PoolKey { + address token0; + address token1; + uint24 fee; + int24 tickSpacing; + address hooks; +} + +struct UniswapV4ExactInputSingleParams { + PoolKey poolKey; + bool zeroForOne; + uint128 amountIn; + uint128 amountOutMinimum; + bytes hookData; +} + +uint256 constant COMMAND_V4_SWAP = 0x10; +uint256 constant ACTION_SWAP_IN_SINGLE = 0x06; +uint256 constant ACTION_SETTLE_ALL = 0x0c; +uint256 constant ACTION_TAKE_ALL = 0x0f; + +interface IUniversalRouter { + function poolManager() external view returns (address); + function execute(bytes calldata commands, bytes[] calldata inputs) external payable; +} diff --git a/contracts/integrations/upshift/IUpshiftVault.sol b/contracts/integrations/upshift/IUpshiftVault.sol new file mode 100644 index 00000000..bcc6c16a --- /dev/null +++ b/contracts/integrations/upshift/IUpshiftVault.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +interface IUpshiftVault { + function requestRedeem(uint256 shares, address receiverAddr, address holderAddr) external; + + function claim(uint256 year, uint256 month, uint256 day, address receiverAddr) external; + + function getWithdrawalEpoch() + external + view + returns (uint256 year, uint256 month, uint256 day, uint256 claimableEpoch); + + function getClaimableAmountByReceiver(uint256 year, uint256 month, uint256 day, address receiverAddr) + external + view + returns (uint256); +} diff --git a/contracts/integrations/velodrome/IVelodromeV2Router.sol b/contracts/integrations/velodrome/IVelodromeV2Router.sol index 8a626692..61284afa 100644 --- a/contracts/integrations/velodrome/IVelodromeV2Router.sol +++ b/contracts/integrations/velodrome/IVelodromeV2Router.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; struct Route { address from; diff --git a/contracts/interfaces/IPhantomTokenAdapter.sol b/contracts/interfaces/IPhantomTokenAdapter.sol new file mode 100644 index 00000000..f64fa2b3 --- /dev/null +++ b/contracts/interfaces/IPhantomTokenAdapter.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; +import {IPhantomTokenWithdrawer} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; + +/// @title Phantom token adapter interface +interface IPhantomTokenAdapter is IAdapter, IPhantomTokenWithdrawer { + /// @notice Thrown when attempting to deposit or withdraw a token that is not the staked phantom token + error IncorrectStakedPhantomTokenException(); + + /// @notice Provides a generic interface for deposits, which is useful for external integrations, + /// e.g., when one needs to move an arbitrary phantom token between accounts. + function depositPhantomToken(address token, uint256 amount) external returns (bool); +} diff --git a/contracts/interfaces/LICENSE b/contracts/interfaces/LICENSE index 8b1f1059..32b13cf8 100644 --- a/contracts/interfaces/LICENSE +++ b/contracts/interfaces/LICENSE @@ -1,4 +1,4 @@ -(c) Gearbox Foundation, 2023 +(c) Gearbox Foundation, 2024 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/contracts/interfaces/aave/IAaveV2_LendingPoolAdapter.sol b/contracts/interfaces/aave/IAaveV2_LendingPoolAdapter.sol deleted file mode 100644 index 894a0db9..00000000 --- a/contracts/interfaces/aave/IAaveV2_LendingPoolAdapter.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; - -/// @title Aave V2 LendingPool adapter interface -interface IAaveV2_LendingPoolAdapter is IAdapter { - function deposit(address asset, uint256 amount, address, uint16) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function depositDiff(address asset, uint256 leftoverAmount) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdraw(address asset, uint256 amount, address) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawDiff(address asset, uint256 leftoverAmount) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); -} diff --git a/contracts/interfaces/aave/IAaveV2_WrappedATokenAdapter.sol b/contracts/interfaces/aave/IAaveV2_WrappedATokenAdapter.sol deleted file mode 100644 index 6bbd2286..00000000 --- a/contracts/interfaces/aave/IAaveV2_WrappedATokenAdapter.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; - -/// @title Aave V2 Wrapped aToken adapter interface -interface IAaveV2_WrappedATokenAdapter is IAdapter { - function aToken() external view returns (address); - - function underlying() external view returns (address); - - function waTokenMask() external view returns (uint256); - - function aTokenMask() external view returns (uint256); - - function tokenMask() external view returns (uint256); - - function deposit(uint256 assets) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function depositDiff(uint256 leftoverAssets) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function depositUnderlying(uint256 assets) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function depositDiffUnderlying(uint256 leftoverAssets) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdraw(uint256 shares) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawDiff(uint256 leftoverShares) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawUnderlying(uint256 shares) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawDiffUnderlying(uint256 leftoverShares) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); -} diff --git a/contracts/interfaces/balancer/IBalancerV2VaultAdapter.sol b/contracts/interfaces/balancer/IBalancerV2VaultAdapter.sol index a551b2f6..5e9dcca9 100644 --- a/contracts/interfaces/balancer/IBalancerV2VaultAdapter.sol +++ b/contracts/interfaces/balancer/IBalancerV2VaultAdapter.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import { IAsset, @@ -18,7 +18,8 @@ import { enum PoolStatus { NOT_ALLOWED, ALLOWED, - SWAP_ONLY + SWAP_ONLY, + WITHDRAWAL_ONLY } struct SingleSwapDiff { @@ -29,29 +30,24 @@ struct SingleSwapDiff { bytes userData; } -interface IBalancerV2VaultAdapterEvents { +/// @title Balancer V2 Vault adapter interface +interface IBalancerV2VaultAdapter is IAdapter { /// @notice Emitted when new status is set for a pool with given ID event SetPoolStatus(bytes32 indexed poolId, PoolStatus newStatus); -} -interface IBalancerV2VaultAdapterExceptions { /// @notice Thrown when attempting to swap or change liqudity in the pool that is not supported for that action error PoolNotSupportedException(); -} - -/// @title Balancer V2 Vault adapter interface -interface IBalancerV2VaultAdapter is IAdapter, IBalancerV2VaultAdapterEvents, IBalancerV2VaultAdapterExceptions { // ----- // // SWAPS // // ----- // function swap(SingleSwap memory singleSwap, FundManagement memory, uint256 limit, uint256 deadline) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function swapDiff(SingleSwapDiff memory singleSwapDiff, uint256 limitRateRAY, uint256 deadline) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function batchSwap( SwapKind kind, @@ -60,7 +56,7 @@ interface IBalancerV2VaultAdapter is IAdapter, IBalancerV2VaultAdapterEvents, IB FundManagement memory, int256[] memory limits, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); // --------- // // JOIN POOL // @@ -68,15 +64,15 @@ interface IBalancerV2VaultAdapter is IAdapter, IBalancerV2VaultAdapterEvents, IB function joinPool(bytes32 poolId, address, address, JoinPoolRequest memory request) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function joinPoolSingleAsset(bytes32 poolId, IAsset assetIn, uint256 amountIn, uint256 minAmountOut) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function joinPoolSingleAssetDiff(bytes32 poolId, IAsset assetIn, uint256 leftoverAmount, uint256 minRateRAY) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); // --------- // // EXIT POOL // @@ -84,15 +80,15 @@ interface IBalancerV2VaultAdapter is IAdapter, IBalancerV2VaultAdapterEvents, IB function exitPool(bytes32 poolId, address, address payable, ExitPoolRequest memory request) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function exitPoolSingleAsset(bytes32 poolId, IAsset assetOut, uint256 amountIn, uint256 minAmountOut) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function exitPoolSingleAssetDiff(bytes32 poolId, IAsset assetOut, uint256 leftoverAmount, uint256 minRateRAY) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/balancer/IBalancerV3RouterAdapter.sol b/contracts/interfaces/balancer/IBalancerV3RouterAdapter.sol index c5a9ab48..6d9c5aa0 100644 --- a/contracts/interfaces/balancer/IBalancerV3RouterAdapter.sol +++ b/contracts/interfaces/balancer/IBalancerV3RouterAdapter.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IBalancerV3RouterAdapterEvents { @@ -30,7 +30,7 @@ interface IBalancerV3RouterAdapter is IAdapter, IBalancerV3RouterAdapterEvents, uint256 deadline, bool wethIsEth, bytes calldata userData - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool); function swapSingleTokenDiffIn( address pool, @@ -39,7 +39,7 @@ interface IBalancerV3RouterAdapter is IAdapter, IBalancerV3RouterAdapterEvents, uint256 leftoverAmount, uint256 rateMinRAY, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/camelot/ICamelotV3Adapter.sol b/contracts/interfaces/camelot/ICamelotV3Adapter.sol index 70490d6f..ddfd5410 100644 --- a/contracts/interfaces/camelot/ICamelotV3Adapter.sol +++ b/contracts/interfaces/camelot/ICamelotV3Adapter.sol @@ -1,12 +1,17 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {ICamelotV3Router} from "../../integrations/camelot/ICamelotV3Router.sol"; +struct CamelotV3Pool { + address token0; + address token1; +} + struct CamelotV3PoolStatus { address token0; address token1; @@ -43,54 +48,37 @@ interface ICamelotV3AdapterTypes { } } -interface ICamelotV3AdapterEvents { +/// @title Camelot V3 Router adapter interface +interface ICamelotV3Adapter is IAdapter, ICamelotV3AdapterTypes { /// @notice Emitted when new status is set for a pool event SetPoolStatus(address indexed token0, address indexed token1, bool allowed); -} -interface ICamelotV3AdapterExceptions { /// @notice Thrown when sanity checks on a swap path fail error InvalidPathException(); -} -/// @title Camelot V3 Router adapter interface -interface ICamelotV3Adapter is - IAdapter, - ICamelotV3AdapterTypes, - ICamelotV3AdapterEvents, - ICamelotV3AdapterExceptions -{ function exactInputSingle(ICamelotV3Router.ExactInputSingleParams calldata params) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); - function exactDiffInputSingle(ExactDiffInputSingleParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactDiffInputSingle(ExactDiffInputSingleParams calldata params) external returns (bool useSafePrices); function exactInputSingleSupportingFeeOnTransferTokens(ICamelotV3Router.ExactInputSingleParams calldata params) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function exactDiffInputSingleSupportingFeeOnTransferTokens(ExactDiffInputSingleParams calldata params) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); - function exactInput(ICamelotV3Router.ExactInputParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactInput(ICamelotV3Router.ExactInputParams calldata params) external returns (bool useSafePrices); - function exactDiffInput(ExactDiffInputParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactDiffInput(ExactDiffInputParams calldata params) external returns (bool useSafePrices); function exactOutputSingle(ICamelotV3Router.ExactOutputSingleParams calldata params) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); - function exactOutput(ICamelotV3Router.ExactOutputParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactOutput(ICamelotV3Router.ExactOutputParams calldata params) external returns (bool useSafePrices); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/compound/ICompoundV2_CTokenAdapter.sol b/contracts/interfaces/compound/ICompoundV2_CTokenAdapter.sol deleted file mode 100644 index 2f52d266..00000000 --- a/contracts/interfaces/compound/ICompoundV2_CTokenAdapter.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; - -interface ICompoundV2_Exceptions { - /// @notice Thrown when cToken operation produces an error - error CTokenError(uint256 errorCode); -} - -/// @title Compound V2 cToken adapter interface -interface ICompoundV2_CTokenAdapter is IAdapter, ICompoundV2_Exceptions { - function cToken() external view returns (address); - - function underlying() external view returns (address); - - function tokenMask() external view returns (uint256); - - function cTokenMask() external view returns (uint256); - - function mint(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function mintDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function redeem(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function redeemDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function redeemUnderlying(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); -} diff --git a/contracts/interfaces/convex/IConvexV1BaseRewardPoolAdapter.sol b/contracts/interfaces/convex/IConvexV1BaseRewardPoolAdapter.sol index 50bcb360..0c8c96ac 100644 --- a/contracts/interfaces/convex/IConvexV1BaseRewardPoolAdapter.sol +++ b/contracts/interfaces/convex/IConvexV1BaseRewardPoolAdapter.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IPhantomTokenAdapter} from "../IPhantomTokenAdapter.sol"; /// @title Convex V1 BaseRewardPool adapter interface -interface IConvexV1BaseRewardPoolAdapter is IAdapter { +interface IConvexV1BaseRewardPoolAdapter is IPhantomTokenAdapter { function curveLPtoken() external view returns (address); function stakingToken() external view returns (address); @@ -21,31 +21,17 @@ interface IConvexV1BaseRewardPoolAdapter is IAdapter { function extraReward4() external view returns (address); - function curveLPTokenMask() external view returns (uint256); + function stake(uint256) external returns (bool useSafePrices); - function stakingTokenMask() external view returns (uint256); + function stakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices); - function stakedTokenMask() external view returns (uint256); + function getReward() external returns (bool useSafePrices); - function rewardTokensMask() external view returns (uint256); + function withdraw(uint256, bool claim) external returns (bool useSafePrices); - function stake(uint256) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdrawDiff(uint256 leftoverAmount, bool claim) external returns (bool useSafePrices); - function stakeDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdrawAndUnwrap(uint256, bool claim) external returns (bool useSafePrices); - function getReward() external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdraw(uint256, bool claim) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawDiff(uint256 leftoverAmount, bool claim) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawAndUnwrap(uint256, bool claim) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdrawDiffAndUnwrap(uint256 leftoverAmount, bool claim) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdrawDiffAndUnwrap(uint256 leftoverAmount, bool claim) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/convex/IConvexV1BoosterAdapter.sol b/contracts/interfaces/convex/IConvexV1BoosterAdapter.sol index 3e13cc0e..0b24fedd 100644 --- a/contracts/interfaces/convex/IConvexV1BoosterAdapter.sol +++ b/contracts/interfaces/convex/IConvexV1BoosterAdapter.sol @@ -1,36 +1,33 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; - -interface IConvexV1BoosterAdapterEvents { - /// @notice Emitted when phantom staked token is set for the pool - event SetPidToPhantomToken(uint256 indexed pid, address indexed phantomToken); -} +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; /// @title Convex V1 Booster adapter interface -interface IConvexV1BoosterAdapter is IAdapter, IConvexV1BoosterAdapterEvents { - function deposit(uint256 _pid, uint256, bool _stake) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); +interface IConvexV1BoosterAdapter is IAdapter { + /// @notice Thrown when attempting to make a deposit into a pool with unknown pid + error UnsupportedPidException(); + + /// @notice Emitted when a new supported pid is added to booster adapter + event AddSupportedPid(uint256 indexed pid); + + function deposit(uint256 _pid, uint256, bool _stake) external returns (bool useSafePrices); - function depositDiff(uint256 leftoverAmount, uint256 _pid, bool _stake) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function depositDiff(uint256 leftoverAmount, uint256 _pid, bool _stake) external returns (bool useSafePrices); - function withdraw(uint256 _pid, uint256) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdraw(uint256 _pid, uint256) external returns (bool useSafePrices); - function withdrawDiff(uint256 leftoverAmount, uint256 _pid) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdrawDiff(uint256 leftoverAmount, uint256 _pid) external returns (bool useSafePrices); // ------------- // // CONFIGURATION // // ------------- // function pidToPhantomToken(uint256) external view returns (address); + function pidToCurveToken(uint256) external view returns (address); + function pidToConvexToken(uint256) external view returns (address); - function updateStakedPhantomTokensMap() external; + function updateSupportedPids() external; } diff --git a/contracts/interfaces/curve/ICurveV1Adapter.sol b/contracts/interfaces/curve/ICurveV1Adapter.sol index 3f564626..084da838 100644 --- a/contracts/interfaces/curve/ICurveV1Adapter.sol +++ b/contracts/interfaces/curve/ICurveV1Adapter.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; /// @title Curve V1 base adapter interface interface ICurveV1Adapter is IAdapter { @@ -11,8 +11,6 @@ interface ICurveV1Adapter is IAdapter { function lp_token() external view returns (address); - function lpTokenMask() external view returns (uint256); - function metapoolBase() external view returns (address); function nCoins() external view returns (uint256); @@ -24,48 +22,34 @@ interface ICurveV1Adapter is IAdapter { function token2() external view returns (address); function token3() external view returns (address); - function token0Mask() external view returns (uint256); - function token1Mask() external view returns (uint256); - function token2Mask() external view returns (uint256); - function token3Mask() external view returns (uint256); - function underlying0() external view returns (address); function underlying1() external view returns (address); function underlying2() external view returns (address); function underlying3() external view returns (address); - function underlying0Mask() external view returns (uint256); - function underlying1Mask() external view returns (uint256); - function underlying2Mask() external view returns (uint256); - function underlying3Mask() external view returns (uint256); - // -------- // // EXCHANGE // // -------- // - function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external returns (bool useSafePrices); - function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (bool useSafePrices); function exchange_diff(uint256 i, uint256 j, uint256 leftoverAmount, uint256 rateMinRAY) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function exchange_underlying(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function exchange_diff_underlying(uint256 i, uint256 j, uint256 leftoverAmount, uint256 rateMinRAY) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); // ------------- // // ADD LIQUIDITY // @@ -73,11 +57,11 @@ interface ICurveV1Adapter is IAdapter { function add_liquidity_one_coin(uint256 amount, uint256 i, uint256 minAmount) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function add_diff_liquidity_one_coin(uint256 leftoverAmount, uint256 i, uint256 rateMinRAY) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function calc_add_one_coin(uint256 amount, uint256 i) external view returns (uint256); @@ -87,13 +71,13 @@ interface ICurveV1Adapter is IAdapter { function remove_liquidity_one_coin(uint256 amount, uint256 i, uint256 minAmount) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function remove_liquidity_one_coin(uint256 amount, int128 i, uint256 minAmount) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function remove_diff_liquidity_one_coin(uint256 leftoverAmount, uint256 i, uint256 rateMinRAY) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); } diff --git a/contracts/interfaces/curve/ICurveV1_2AssetsAdapter.sol b/contracts/interfaces/curve/ICurveV1_2AssetsAdapter.sol index 0e02c73f..b04926ac 100644 --- a/contracts/interfaces/curve/ICurveV1_2AssetsAdapter.sol +++ b/contracts/interfaces/curve/ICurveV1_2AssetsAdapter.sol @@ -1,22 +1,18 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {N_COINS} from "../../integrations/curve/ICurvePool_2.sol"; import {ICurveV1Adapter} from "./ICurveV1Adapter.sol"; /// @title Curve V1 2 assets adapter interface interface ICurveV1_2AssetsAdapter is ICurveV1Adapter { - function add_liquidity(uint256[N_COINS] calldata amounts, uint256) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function add_liquidity(uint256[N_COINS] calldata amounts, uint256) external returns (bool useSafePrices); - function remove_liquidity(uint256, uint256[N_COINS] calldata) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function remove_liquidity(uint256, uint256[N_COINS] calldata) external returns (bool useSafePrices); function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); } diff --git a/contracts/interfaces/curve/ICurveV1_3AssetsAdapter.sol b/contracts/interfaces/curve/ICurveV1_3AssetsAdapter.sol index 646de95e..bc24c399 100644 --- a/contracts/interfaces/curve/ICurveV1_3AssetsAdapter.sol +++ b/contracts/interfaces/curve/ICurveV1_3AssetsAdapter.sol @@ -1,22 +1,18 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {N_COINS} from "../../integrations/curve/ICurvePool_3.sol"; import {ICurveV1Adapter} from "./ICurveV1Adapter.sol"; /// @title Curve V1 3 assets adapter interface interface ICurveV1_3AssetsAdapter is ICurveV1Adapter { - function add_liquidity(uint256[N_COINS] calldata amounts, uint256) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function add_liquidity(uint256[N_COINS] calldata amounts, uint256) external returns (bool useSafePrices); - function remove_liquidity(uint256, uint256[N_COINS] calldata) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function remove_liquidity(uint256, uint256[N_COINS] calldata) external returns (bool useSafePrices); function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); } diff --git a/contracts/interfaces/curve/ICurveV1_4AssetsAdapter.sol b/contracts/interfaces/curve/ICurveV1_4AssetsAdapter.sol index bb7574a5..796ace39 100644 --- a/contracts/interfaces/curve/ICurveV1_4AssetsAdapter.sol +++ b/contracts/interfaces/curve/ICurveV1_4AssetsAdapter.sol @@ -1,22 +1,18 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {N_COINS} from "../../integrations/curve/ICurvePool_4.sol"; import {ICurveV1Adapter} from "./ICurveV1Adapter.sol"; /// @title Curve V1 4 assets adapter interface interface ICurveV1_4AssetsAdapter is ICurveV1Adapter { - function add_liquidity(uint256[N_COINS] calldata amounts, uint256) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function add_liquidity(uint256[N_COINS] calldata amounts, uint256) external returns (bool useSafePrices); - function remove_liquidity(uint256, uint256[N_COINS] calldata) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function remove_liquidity(uint256, uint256[N_COINS] calldata) external returns (bool useSafePrices); function remove_liquidity_imbalance(uint256[N_COINS] calldata amounts, uint256) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); } diff --git a/contracts/interfaces/curve/ICurveV1_StableNGAdapter.sol b/contracts/interfaces/curve/ICurveV1_StableNGAdapter.sol index 57be02dd..e498675e 100644 --- a/contracts/interfaces/curve/ICurveV1_StableNGAdapter.sol +++ b/contracts/interfaces/curve/ICurveV1_StableNGAdapter.sol @@ -1,21 +1,15 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ICurveV1Adapter} from "./ICurveV1Adapter.sol"; /// @title Adapter for Curve stable pools with dynamic arrays interface ICurveV1_StableNGAdapter is ICurveV1Adapter { - function add_liquidity(uint256[] calldata amounts, uint256) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function add_liquidity(uint256[] calldata amounts, uint256) external returns (bool useSafePrices); - function remove_liquidity(uint256, uint256[] calldata) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function remove_liquidity(uint256, uint256[] calldata) external returns (bool useSafePrices); - function remove_liquidity_imbalance(uint256[] calldata amounts, uint256) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function remove_liquidity_imbalance(uint256[] calldata amounts, uint256) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/equalizer/IEqualizerRouterAdapter.sol b/contracts/interfaces/equalizer/IEqualizerRouterAdapter.sol index c79bcbab..91daf7d2 100644 --- a/contracts/interfaces/equalizer/IEqualizerRouterAdapter.sol +++ b/contracts/interfaces/equalizer/IEqualizerRouterAdapter.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {Route} from "../../integrations/equalizer/IEqualizerRouter.sol"; struct EqualizerPool { @@ -19,32 +19,28 @@ struct EqualizerPoolStatus { bool allowed; } -interface IEqualizerRouterAdapterEvents { +/// @title Equalizer Router adapter interface +interface IEqualizerRouterAdapter is IAdapter { /// @notice Emited when new status is set for a pair event SetPoolStatus(address indexed token0, address indexed token1, bool stable, bool allowed); -} -interface IEqualizerRouterAdapterExceptions { /// @notice Thrown when sanity checks on a swap path fail error InvalidPathException(); -} -/// @title Equalizer Router adapter interface -interface IEqualizerRouterAdapter is IAdapter, IEqualizerRouterAdapterEvents, IEqualizerRouterAdapterExceptions { function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapDiffTokensForTokens( uint256 leftoverAmount, uint256 rateMinRAY, Route[] calldata routes, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); // ------------- // // CONFIGURATION // @@ -53,6 +49,4 @@ interface IEqualizerRouterAdapter is IAdapter, IEqualizerRouterAdapterEvents, IE function isPoolAllowed(address token0, address token1, bool stable) external view returns (bool); function setPoolStatusBatch(EqualizerPoolStatus[] calldata pools) external; - - function supportedPools() external view returns (EqualizerPool[] memory pools); } diff --git a/contracts/interfaces/erc4626/IERC4626Adapter.sol b/contracts/interfaces/erc4626/IERC4626Adapter.sol index 38fa72b6..35a850f1 100644 --- a/contracts/interfaces/erc4626/IERC4626Adapter.sol +++ b/contracts/interfaces/erc4626/IERC4626Adapter.sol @@ -1,30 +1,24 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; interface IERC4626Adapter is IAdapter { function asset() external view returns (address); - function assetMask() external view returns (uint256); + function vault() external view returns (address); - function sharesMask() external view returns (uint256); + function deposit(uint256 assets, address) external returns (bool useSafePrices); - function deposit(uint256 assets, address) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function depositDiff(uint256 leftoverAmount) external returns (bool useSafePrices); - function depositDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function mint(uint256 shares, address) external returns (bool useSafePrices); - function mint(uint256 shares, address) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdraw(uint256 assets, address, address) external returns (bool useSafePrices); - function withdraw(uint256 assets, address, address) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function redeem(uint256 shares, address, address) external returns (bool useSafePrices); - function redeem(uint256 shares, address, address) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function redeemDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function redeemDiff(uint256 leftoverAmount) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/fluid/IFluidDexAdapter.sol b/contracts/interfaces/fluid/IFluidDexAdapter.sol new file mode 100644 index 00000000..153e000a --- /dev/null +++ b/contracts/interfaces/fluid/IFluidDexAdapter.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +/// @title FluidDex adapter interface +interface IFluidDexAdapter is IAdapter { + function token0() external view returns (address); + + function token1() external view returns (address); + + function swapIn(bool swap0to1, uint256 amountIn, uint256 amountOutMin, address to) external returns (bool); + + function swapInDiff(bool swap0to1, uint256 leftoverAmount, uint256 rateMinRAY) external returns (bool); +} diff --git a/contracts/interfaces/infinifi/IInfinifiGatewayAdapter.sol b/contracts/interfaces/infinifi/IInfinifiGatewayAdapter.sol new file mode 100644 index 00000000..5911781c --- /dev/null +++ b/contracts/interfaces/infinifi/IInfinifiGatewayAdapter.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +struct LockedTokenStatus { + address lockedToken; + uint32 unwindingEpochs; + bool allowed; +} + +interface IInfinifiGatewayEvents { + event SetLockedTokenStatus(address lockedToken, uint32 unwindingEpochs, bool allowed); +} + +interface IInfinifiGatewayExceptions { + /// @notice Thrown when the passed unwinding epochs for the locked token do not match actual unwinding epochs in Infinifi + error LockedTokenUnwindingEpochsMismatchException(); + + /// @notice Thrown when the locked token is not allowed + error LockedTokenNotAllowedException(); +} + +/// @title Infinifi Gateway adapter interface +interface IInfinifiGatewayAdapter is IAdapter, IInfinifiGatewayExceptions, IInfinifiGatewayEvents { + function usdc() external view returns (address); + + function iusd() external view returns (address); + + function siusd() external view returns (address); + + function lockedTokenToUnwindingEpoch(address lockedToken) external view returns (uint32); + + function mint(address to, uint256 amount) external returns (bool useSafePrices); + + function mintDiff(uint256 leftoverAmount) external returns (bool useSafePrices); + + function stake(address to, uint256 amount) external returns (bool useSafePrices); + + function stakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices); + + function unstake(address to, uint256 amount) external returns (bool useSafePrices); + + function unstakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices); + + function createPosition(uint256 amount, uint32 unwindingEpochs) external returns (bool useSafePrices); + + function createPositionDiff(uint256 leftoverAmount, uint32 unwindingEpochs) external returns (bool useSafePrices); + + function redeem(address to, uint256 amount, uint256 minAssetsOut) external returns (bool useSafePrices); + + function redeemDiff(uint256 leftoverAmount, uint256 minRateRAY) external returns (bool useSafePrices); + + function claimRedemption() external returns (bool useSafePrices); + + function getAllowedLockedTokens() external view returns (address[] memory); + + function setLockedTokenBatchStatus(LockedTokenStatus[] calldata lockedTokens) external; +} diff --git a/contracts/interfaces/infinifi/IInfinifiUnwindingGateway.sol b/contracts/interfaces/infinifi/IInfinifiUnwindingGateway.sol new file mode 100644 index 00000000..1dceac56 --- /dev/null +++ b/contracts/interfaces/infinifi/IInfinifiUnwindingGateway.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; + +struct UserUnwindingData { + uint256 shares; + uint32 unwindingEpochs; + uint256 unwindingTimestamp; + uint256 unclaimedAssets; + bool isWithdrawn; +} + +interface IInfinifiUnwindingGatewayExceptions { + /// @notice Thrown when a user attempts a second unwinding in the same block + error MoreThanOneUnwindingPerBlockException(); + + /// @notice Thrown when a user attempts to start unwinding while already unwinding + error UserAlreadyUnwindingException(); + + /// @notice Thrown when a user attempts to withdraw while not unwinding + error UserNotUnwindingException(); + + /// @notice Thrown when a user attempts to withdraw an unwinding that is not claimable + error UnwindingNotClaimableException(); + + /// @notice Thrown when a user attempts to withdraw an unwinding for more assets than are pending + error InsufficientPendingAssetsException(); +} + +interface IInfinifiUnwindingGateway is IVersion, IInfinifiUnwindingGatewayExceptions { + function iUSD() external view returns (address); + + function lockingController() external view returns (address); + + function unwindingModule() external view returns (address); + + function getUserUnwindingData(address user) external view returns (UserUnwindingData memory); + + function startUnwinding(uint256 shares, uint32 unwindingEpochs) external; + + function withdraw(uint256 unwindingTimestamp) external; + + function getPendingAssets(address user) external view returns (uint256); +} diff --git a/contracts/interfaces/infinifi/IInfinifiUnwindingGatewayAdapter.sol b/contracts/interfaces/infinifi/IInfinifiUnwindingGatewayAdapter.sol new file mode 100644 index 00000000..b5a46629 --- /dev/null +++ b/contracts/interfaces/infinifi/IInfinifiUnwindingGatewayAdapter.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IPhantomTokenAdapter} from "../IPhantomTokenAdapter.sol"; + +struct LockedTokenStatus { + address lockedToken; + uint32 unwindingEpochs; + bool allowed; +} + +interface IInfinifiGatewayEvents { + event SetLockedTokenStatus(address lockedToken, uint32 unwindingEpochs, bool allowed); +} + +interface IInfinifiGatewayExceptions { + /// @notice Thrown when the passed unwinding epochs for the locked token do not match actual unwinding epochs in Infinifi + error LockedTokenUnwindingEpochsMismatchException(); + + /// @notice Thrown when the locked token is not allowed + error LockedTokenNotAllowedException(); +} + +interface IInfinifiUnwindingGatewayAdapter is + IPhantomTokenAdapter, + IInfinifiGatewayExceptions, + IInfinifiGatewayEvents +{ + function lockedTokenToUnwindingEpoch(address lockedToken) external view returns (uint32); + + function startUnwinding(uint256 shares, uint32 unwindingEpochs) external returns (bool); + + function withdraw(uint256 amount) external returns (bool); + + function getAllowedLockedTokens() external view returns (address[] memory); + + function setLockedTokenBatchStatus(LockedTokenStatus[] calldata lockedTokens) external; +} diff --git a/contracts/interfaces/infrared/IInfraredVaultAdapter.sol b/contracts/interfaces/infrared/IInfraredVaultAdapter.sol new file mode 100644 index 00000000..a94acf3b --- /dev/null +++ b/contracts/interfaces/infrared/IInfraredVaultAdapter.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IPhantomTokenAdapter} from "../IPhantomTokenAdapter.sol"; + +/// @title InfraredVault Adapter Interface +interface IInfraredVaultAdapter is IPhantomTokenAdapter { + /// @notice Address of the staking token + function stakingToken() external view returns (address); + + /// @notice Address of the staked phantom token + function stakedPhantomToken() external view returns (address); + + /// @notice Stakes tokens in the InfraredVault + /// @param amount Amount of tokens to stake + function stake(uint256 amount) external returns (bool useSafePrices); + + /// @notice Stakes the entire balance of staking token, except the specified amount + /// @param leftoverAmount Amount of staking token to keep on the account + function stakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices); + + /// @notice Claims all rewards on the current position + function getReward() external returns (bool useSafePrices); + + /// @notice Withdraws staked tokens from the InfraredVault + /// @param amount Amount of tokens to withdraw + function withdraw(uint256 amount) external returns (bool useSafePrices); + + /// @notice Withdraws the entire balance of staked tokens, except the specified amount + /// @param leftoverAmount Amount of staked tokens to keep in the contract + function withdrawDiff(uint256 leftoverAmount) external returns (bool useSafePrices); + + /// @notice Exits the staking position by withdrawing all staked tokens and claiming rewards + function exit() external returns (bool useSafePrices); +} diff --git a/contracts/interfaces/kodiak/IKodiakIslandGateway.sol b/contracts/interfaces/kodiak/IKodiakIslandGateway.sol new file mode 100644 index 00000000..3031b264 --- /dev/null +++ b/contracts/interfaces/kodiak/IKodiakIslandGateway.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +struct Ratios { + uint256 priceRatio; + uint256 balance0; + uint256 balance1; + bool swapAll; + bool is0to1; +} + +interface IKodiakIslandGatewayErrors { + error InvalidTokenInException(); + error InsufficientAmountOutException(); +} + +interface IKodiakIslandGateway is IKodiakIslandGatewayErrors { + function swap(address island, address tokenIn, uint256 amountIn, uint256 amountOutMin) + external + returns (uint256 amountOut); + + function estimateSwap(address island, address tokenIn, uint256 amountIn) external returns (uint256 amountOut); + + function addLiquidityImbalanced( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver + ) external returns (uint256 lpAmount); + + function addLiquidityImbalancedAssisted( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver, + Ratios memory ratios + ) external returns (uint256 lpAmount); + + function estimateAddLiquidityImbalanced(address island, uint256 amount0, uint256 amount1) + external + returns (uint256 lpAmount, Ratios memory ratios); + + function removeLiquiditySingle( + address island, + uint256 lpAmount, + address tokenOut, + uint256 minAmountOut, + address receiver + ) external returns (uint256 amountOut); + + function estimateRemoveLiquiditySingle(address island, uint256 lpAmount, address tokenOut) + external + returns (uint256 amountOut); +} diff --git a/contracts/interfaces/kodiak/IKodiakIslandGatewayAdapter.sol b/contracts/interfaces/kodiak/IKodiakIslandGatewayAdapter.sol new file mode 100644 index 00000000..b1f25947 --- /dev/null +++ b/contracts/interfaces/kodiak/IKodiakIslandGatewayAdapter.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; +import {ExactInputSingleParams} from "../../integrations/kodiak/IKodiakSwapRouter.sol"; +import {Ratios} from "./IKodiakIslandGateway.sol"; + +enum IslandStatus { + NOT_ALLOWED, + ALLOWED, + SWAP_AND_EXIT_ONLY, + EXIT_ONLY +} + +struct KodiakIslandStatus { + address island; + IslandStatus status; +} + +interface IKodiakIslandGatewayEvents { + event SetIslandStatus(address indexed island, IslandStatus status); +} + +interface IKodiakIslandGatewayAdapterExceptions { + error IslandNotAllowedException(address island); +} + +interface IKodiakIslandGatewayAdapter is IAdapter, IKodiakIslandGatewayAdapterExceptions, IKodiakIslandGatewayEvents { + function swap(address island, address tokenIn, uint256 amountIn, uint256 amountOutMin) external returns (bool); + + function swapDiff(address island, address tokenIn, uint256 leftoverAmount, uint256 minRateRAY) + external + returns (bool); + + function addLiquidityImbalanced( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver + ) external returns (bool); + + function addLiquidityImbalancedAssisted( + address island, + uint256 amount0, + uint256 amount1, + uint256 minLPAmount, + address receiver, + Ratios memory ratios + ) external returns (bool); + + function addLiquidityImbalancedDiff( + address island, + uint256 leftoverAmount0, + uint256 leftoverAmount1, + uint256[2] memory minRatesRAY + ) external returns (bool); + + function addLiquidityImbalancedDiffAssisted( + address island, + uint256 leftoverAmount0, + uint256 leftoverAmount1, + uint256[2] memory minRatesRAY, + Ratios memory ratios + ) external returns (bool); + + function removeLiquiditySingle( + address island, + uint256 lpAmount, + address tokenOut, + uint256 minAmountOut, + address receiver + ) external returns (bool); + + function removeLiquiditySingleDiff(address island, uint256 leftoverAmount, address tokenOut, uint256 minRateRAY) + external + returns (bool); + + function allowedIslands() external view returns (KodiakIslandStatus[] memory); + + function setIslandStatusBatch(KodiakIslandStatus[] calldata islands) external; +} diff --git a/contracts/interfaces/lido/ILidoV1Adapter.sol b/contracts/interfaces/lido/ILidoV1Adapter.sol index d3ac1015..04ad64dc 100644 --- a/contracts/interfaces/lido/ILidoV1Adapter.sol +++ b/contracts/interfaces/lido/ILidoV1Adapter.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; /// @title Lido V1 adapter interface interface ILidoV1Adapter is IAdapter { @@ -11,13 +11,9 @@ interface ILidoV1Adapter is IAdapter { function stETH() external view returns (address); - function wethTokenMask() external view returns (uint256); - - function stETHTokenMask() external view returns (uint256); - function treasury() external view returns (address); - function submit(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function submit(uint256 amount) external returns (bool useSafePrices); - function submitDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function submitDiff(uint256 leftoverAmount) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/lido/IwstETHV1Adapter.sol b/contracts/interfaces/lido/IwstETHV1Adapter.sol index ac4b68f8..a45c81e6 100644 --- a/contracts/interfaces/lido/IwstETHV1Adapter.sol +++ b/contracts/interfaces/lido/IwstETHV1Adapter.sol @@ -1,23 +1,19 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; /// @title wstETH adapter interface interface IwstETHV1Adapter is IAdapter { function stETH() external view returns (address); - function stETHTokenMask() external view returns (uint256); + function wrap(uint256 amount) external returns (bool useSafePrices); - function wstETHTokenMask() external view returns (uint256); + function wrapDiff(uint256 leftoverAmount) external returns (bool useSafePrices); - function wrap(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function unwrap(uint256 amount) external returns (bool useSafePrices); - function wrapDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function unwrap(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function unwrapDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function unwrapDiff(uint256 leftoverAmount) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/mellow/IMellow4626VaultAdapter.sol b/contracts/interfaces/mellow/IMellow4626VaultAdapter.sol new file mode 100644 index 00000000..aceec474 --- /dev/null +++ b/contracts/interfaces/mellow/IMellow4626VaultAdapter.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC4626Adapter} from "../erc4626/IERC4626Adapter.sol"; + +/// @title Mellow ERC4626 Vault adapter interface +/// @notice Interface for the adapter to interact with Mellow's ERC4626 vaults +interface IMellow4626VaultAdapter is IERC4626Adapter { + /// @notice Thrown when the multivault in the staked phantom token does not match the one in the adapter + error InvalidMultiVaultException(); +} diff --git a/contracts/interfaces/mellow/IMellowClaimerAdapter.sol b/contracts/interfaces/mellow/IMellowClaimerAdapter.sol new file mode 100644 index 00000000..9d3c15ba --- /dev/null +++ b/contracts/interfaces/mellow/IMellowClaimerAdapter.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IPhantomTokenAdapter} from "../IPhantomTokenAdapter.sol"; + +struct MellowMultiVaultStatus { + address multiVault; + address stakedPhantomToken; + bool allowed; +} + +interface IMellowClaimerAdapterEvents { + event SetMultiVaultStatus(address indexed multiVault, bool allowed); +} + +interface IMellowClaimerAdapterExceptions { + /// @notice Error thrown when the actually claimed amount is less than the requested amount + error InsufficientClaimedException(); + + /// @notice Thrown when the staked phantom token field does not match the multivault + error InvalidMultiVaultException(); + + /// @notice Thrown when the staked phantom token added with the vault has incorrect parameters + error InvalidStakedPhantomTokenException(); + + /// @notice Thrown when the multivault is not allowed + error MultiVaultNotAllowedException(); +} + +/// @title Mellow ERC4626 Vault adapter interface +/// @notice Interface for the adapter to interact with Mellow's ERC4626 vaults +interface IMellowClaimerAdapter is + IPhantomTokenAdapter, + IMellowClaimerAdapterExceptions, + IMellowClaimerAdapterEvents +{ + function multiAccept(address multiVault, uint256[] calldata subvaultIndices, uint256[][] calldata indices) + external + returns (bool); + + function multiAcceptAndClaim( + address multiVault, + uint256[] calldata subvaultIndices, + uint256[][] calldata indices, + address, + uint256 maxAssets + ) external returns (bool); + + function getMultiVaultSubvaultIndices(address multiVault) + external + view + returns (uint256[] memory subvaultIndices, uint256[][] memory withdrawalIndices); + + function getUserSubvaultIndices(address multiVault, address user) + external + view + returns (uint256[] memory subvaultIndices, uint256[][] memory withdrawalIndices); + + function allowedMultiVaults() external view returns (address[] memory); + + function setMultiVaultStatusBatch(MellowMultiVaultStatus[] calldata multivaults) external; +} diff --git a/contracts/interfaces/mellow/IMellowVaultAdapter.sol b/contracts/interfaces/mellow/IMellowVaultAdapter.sol index 40ae77cf..36533022 100644 --- a/contracts/interfaces/mellow/IMellowVaultAdapter.sol +++ b/contracts/interfaces/mellow/IMellowVaultAdapter.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; struct MellowUnderlyingStatus { address underlying; @@ -35,7 +35,7 @@ interface IMellowVaultAdapter is IAdapter, IMellowVaultAdapterEvents, IMellowVau /// @notice `to` is ignored as the recipient is always the credit account function deposit(address, uint256[] memory amounts, uint256 minLpAmount, uint256 deadline) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); /// @notice Deposits a specififed amount of one underlying into the vault in exchange for LP tokens. /// @param asset The asset to deposit @@ -44,7 +44,7 @@ interface IMellowVaultAdapter is IAdapter, IMellowVaultAdapterEvents, IMellowVau /// @param deadline The time before which the operation must be completed. function depositOneAsset(address asset, uint256 amount, uint256 minLpAmount, uint256 deadline) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); /// @notice Deposits the entire balance of one underlying, except the specified amount, into the vault in exchange for LP tokens. /// @param asset The asset to deposit @@ -53,14 +53,14 @@ interface IMellowVaultAdapter is IAdapter, IMellowVaultAdapterEvents, IMellowVau /// @param deadline The time before which the operation must be completed. function depositOneAssetDiff(address asset, uint256 leftoverAmount, uint256 rateMinRAY, uint256 deadline) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); // ------------- // // CONFIGURATION // // ------------- // - /// @notice Whether the underlying token is allowed for deposits - function isUnderlyingAllowed(address token) external view returns (bool); + /// @notice Returns the list of allowed underlyings + function allowedUnderlyings() external view returns (address[] memory); /// @notice Changes the allowed status of several underlyings function setUnderlyingStatusBatch(MellowUnderlyingStatus[] calldata underlyings) external; diff --git a/contracts/interfaces/mellow/IMellowWrapperAdapter.sol b/contracts/interfaces/mellow/IMellowWrapperAdapter.sol new file mode 100644 index 00000000..d6090ff1 --- /dev/null +++ b/contracts/interfaces/mellow/IMellowWrapperAdapter.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +struct MellowVaultStatus { + address vault; + bool allowed; +} + +interface IMellowWrapperAdapterEvents { + /// @notice Emitted when the underlying is allowed / disallowed for deposit + event SetVaultStatus(address indexed token, bool newStatus); +} + +interface IMellowWrapperAdapterExceptions { + /// @notice Thrown when attempting to deposit into an unsupported vault + error VaultNotAllowedException(address asset); +} + +/// @title Mellow Vault adapter interface +interface IMellowWrapperAdapter is IAdapter, IMellowWrapperAdapterEvents, IMellowWrapperAdapterExceptions { + function deposit(address depositToken, uint256 amount, address vault, address receiver, address referral) + external + returns (bool); + + function depositDiff(uint256 leftoverAmount, address vault) external returns (bool); + + function allowedVaults() external view returns (address[] memory); + + function setVaultStatusBatch(MellowVaultStatus[] calldata vaults) external; +} diff --git a/contracts/interfaces/pendle/IPendleRouterAdapter.sol b/contracts/interfaces/pendle/IPendleRouterAdapter.sol index 20420df8..cc71f1a3 100644 --- a/contracts/interfaces/pendle/IPendleRouterAdapter.sol +++ b/contracts/interfaces/pendle/IPendleRouterAdapter.sol @@ -3,7 +3,7 @@ // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {ApproxParams, TokenInput, TokenOutput, LimitOrderData} from "../../integrations/pendle/IPendleRouter.sol"; @@ -53,14 +53,14 @@ interface IPendleRouterAdapter is IAdapter, IPendleRouterAdapterEvents, IPendleR ApproxParams calldata guessPtOut, TokenInput calldata input, LimitOrderData calldata limit - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapDiffTokenForPt( address market, uint256 minRateRAY, ApproxParams calldata guessPtOut, TokenDiffInput calldata diffInput - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapExactPtForToken( address receiver, @@ -68,19 +68,19 @@ interface IPendleRouterAdapter is IAdapter, IPendleRouterAdapterEvents, IPendleR uint256 exactPtIn, TokenOutput calldata output, LimitOrderData calldata limit - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapDiffPtForToken(address market, uint256 leftoverPt, TokenDiffOutput calldata diffOutput) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function redeemPyToToken(address receiver, address yt, uint256 netPyIn, TokenOutput calldata output) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); function redeemDiffPyToToken(address yt, uint256 leftoverPt, TokenDiffOutput calldata output) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/sky/IDaiUsdsAdapter.sol b/contracts/interfaces/sky/IDaiUsdsAdapter.sol index d4465fb2..abda86c6 100644 --- a/contracts/interfaces/sky/IDaiUsdsAdapter.sol +++ b/contracts/interfaces/sky/IDaiUsdsAdapter.sol @@ -1,40 +1,21 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; -/// @title DAI/USDS Adapter Interface -/// @notice Interface for the DAI/USDS adapter contract +/// @title DaiUsds adapter interface interface IDaiUsdsAdapter is IAdapter { - /// @notice DAI token address function dai() external view returns (address); - /// @notice USDS token address function usds() external view returns (address); - /// @notice Collateral token mask of DAI in the credit manager - function daiMask() external view returns (uint256); + function daiToUsds(address, uint256) external returns (bool); - /// @notice Collateral token mask of USDS in the credit manager - function usdsMask() external view returns (uint256); + function usdsToDai(address, uint256) external returns (bool); - /// @notice Swaps given amount of DAI to USDS - /// @param usr Recipient address (ignored, always Credit Account) - /// @param wad Amount of DAI to swap - function daiToUsds(address usr, uint256 wad) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function daiToUsdsDiff(uint256) external returns (bool); - /// @notice Swaps the entire balance of DAI to USDS, except the specified amount - /// @param leftoverAmount Amount of DAI to keep on the account - function daiToUsdsDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - /// @notice Swaps given amount of USDS to DAI - /// @param usr Recipient address (ignored, always Credit Account) - /// @param wad Amount of USDS to swap - function usdsToDai(address usr, uint256 wad) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - /// @notice Swaps the entire balance of USDS to DAI, except the specified amount - /// @param leftoverAmount Amount of USDS to keep on the account - function usdsToDaiDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function usdsToDaiDiff(uint256) external returns (bool); } diff --git a/contracts/interfaces/sky/IStakingRewardsAdapter.sol b/contracts/interfaces/sky/IStakingRewardsAdapter.sol index 434f36b3..5aa9d3be 100644 --- a/contracts/interfaces/sky/IStakingRewardsAdapter.sol +++ b/contracts/interfaces/sky/IStakingRewardsAdapter.sol @@ -1,47 +1,27 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IPhantomTokenAdapter} from "../IPhantomTokenAdapter.sol"; /// @title Staking Rewards Adapter Interface -/// @notice Interface for the Staking Rewards adapter contract -interface IStakingRewardsAdapter is IAdapter { - /// @notice Address of the staking token +interface IStakingRewardsAdapter is IPhantomTokenAdapter { function stakingToken() external view returns (address); - /// @notice Address of the rewards token function rewardsToken() external view returns (address); - /// @notice Address of a phantom token representing account's stake in the reward pool function stakedPhantomToken() external view returns (address); - /// @notice Collateral token mask of staking token in the credit manager - function stakingTokenMask() external view returns (uint256); + function referral() external view returns (uint16); - /// @notice Collateral token mask of rewards token in the credit manager - function rewardsTokenMask() external view returns (uint256); + function stake(uint256 amount) external returns (bool useSafePrices); - /// @notice Collateral token mask of staked phantom token in the credit manager - function stakedPhantomTokenMask() external view returns (uint256); + function stakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices); - /// @notice Stakes tokens in the StakingRewards contract - /// @param amount Amount of tokens to stake - function stake(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function getReward() external returns (bool useSafePrices); - /// @notice Stakes the entire balance of staking token, except the specified amount - /// @param leftoverAmount Amount of staking token to keep on the account - function stakeDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdraw(uint256 amount) external returns (bool useSafePrices); - /// @notice Claims rewards on the current position - function getReward() external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - /// @notice Withdraws staked tokens from the StakingRewards contract - /// @param amount Amount of tokens to withdraw - function withdraw(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - /// @notice Withdraws the entire balance of staked tokens, except the specified amount - /// @param leftoverAmount Amount of staked tokens to keep in the contract - function withdrawDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdrawDiff(uint256 leftoverAmount) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/traderjoe/ITraderJoeRouterAdapter.sol b/contracts/interfaces/traderjoe/ITraderJoeRouterAdapter.sol new file mode 100644 index 00000000..4f65cc2c --- /dev/null +++ b/contracts/interfaces/traderjoe/ITraderJoeRouterAdapter.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Path, Version} from "../../integrations/traderjoe/ITraderJoeRouter.sol"; + +/// @title TraderJoe Pool definition +struct TraderJoePool { + address token0; + address token1; + uint256 binStep; + Version poolVersion; +} + +/// @title TraderJoe Pool status for configuration +struct TraderJoePoolStatus { + address token0; + address token1; + uint256 binStep; + Version poolVersion; + bool allowed; +} + +/// @title TraderJoe Router Adapter Interface +interface ITraderJoeRouterAdapter is IAdapter { + /// @notice Emitted when new status is set for a pool + event SetPoolStatus( + address indexed token0, address indexed token1, uint256 binStep, Version poolVersion, bool allowed + ); + + /// @notice Thrown when sanity checks on a swap path fail + error InvalidPathException(); + + /// @notice Swap exact tokens for tokens through TraderJoe paths + /// @param amountIn Amount of input token to spend + /// @param amountOutMin Minimum amount of output token to receive + /// @param path Path struct defining the swap route + /// @param _to Address to receive the output tokens (ignored, must be credit account) + /// @param deadline Maximum timestamp until which the transaction is valid + function swapExactTokensForTokens( + uint256 amountIn, + uint256 amountOutMin, + Path calldata path, + address _to, + uint256 deadline + ) external returns (bool useSafePrices); + + /// @notice Swap tokens for tokens supporting fee-on-transfer tokens + /// @param amountIn Amount of input token to spend + /// @param amountOutMin Minimum amount of output token to receive + /// @param path Path struct defining the swap route + /// @param _to Address to receive the output tokens (ignored, must be credit account) + /// @param deadline Maximum timestamp until which the transaction is valid + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint256 amountIn, + uint256 amountOutMin, + Path calldata path, + address _to, + uint256 deadline + ) external returns (bool useSafePrices); + + /// @notice Swap all tokens except leftover amount for tokens + /// @param leftoverAmount Amount of tokenIn to keep on the account + /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 + /// @param path Path struct defining the swap route + /// @param deadline Maximum timestamp until which the transaction is valid + function swapDiffTokensForTokens(uint256 leftoverAmount, uint256 rateMinRAY, Path calldata path, uint256 deadline) + external + returns (bool useSafePrices); + + /// @notice Swap all tokens except leftover amount for tokens supporting fee-on-transfer tokens + /// @param leftoverAmount Amount of tokenIn to keep on the account + /// @param rateMinRAY Minimum exchange rate between input and output tokens, scaled by 1e27 + /// @param path Path struct defining the swap route + /// @param deadline Maximum timestamp until which the transaction is valid + function swapDiffTokensForTokensSupportingFeeOnTransferTokens( + uint256 leftoverAmount, + uint256 rateMinRAY, + Path calldata path, + uint256 deadline + ) external returns (bool useSafePrices); + + /// @notice Returns all supported pools + function supportedPools() external view returns (TraderJoePool[] memory pools); + + /// @notice Checks if a specific pool is allowed + /// @param token0 First token in the pair + /// @param token1 Second token in the pair + /// @param binStep Bin step for the pair + /// @param poolVersion Version of the pair + function isPoolAllowed(address token0, address token1, uint256 binStep, Version poolVersion) + external + view + returns (bool); + + /// @notice Sets status for a batch of pools + /// @param pools Array of pool status objects + function setPoolStatusBatch(TraderJoePoolStatus[] calldata pools) external; +} diff --git a/contracts/interfaces/uniswap/IUniswapV2Adapter.sol b/contracts/interfaces/uniswap/IUniswapV2Adapter.sol index 5c826ab7..047b5a4c 100644 --- a/contracts/interfaces/uniswap/IUniswapV2Adapter.sol +++ b/contracts/interfaces/uniswap/IUniswapV2Adapter.sol @@ -1,9 +1,14 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +struct UniswapV2Pair { + address token0; + address token1; +} struct UniswapV2PairStatus { address token0; @@ -11,25 +16,21 @@ struct UniswapV2PairStatus { bool allowed; } -interface IUniswapV2AdapterEvents { +/// @title Uniswap V2 Router adapter interface +interface IUniswapV2Adapter is IAdapter { /// @notice Emited when new status is set for a pair event SetPairStatus(address indexed token0, address indexed token1, bool allowed); -} -interface IUniswapV2AdapterExceptions { /// @notice Thrown when sanity checks on a swap path fail error InvalidPathException(); -} -/// @title Uniswap V2 Router adapter interface -interface IUniswapV2Adapter is IAdapter, IUniswapV2AdapterEvents, IUniswapV2AdapterExceptions { function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, address, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapExactTokensForTokens( uint256 amountIn, @@ -37,14 +38,14 @@ interface IUniswapV2Adapter is IAdapter, IUniswapV2AdapterEvents, IUniswapV2Adap address[] calldata path, address, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapDiffTokensForTokens( uint256 leftoverAmount, uint256 rateMinRAY, address[] calldata path, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/uniswap/IUniswapV3Adapter.sol b/contracts/interfaces/uniswap/IUniswapV3Adapter.sol index 1e441fdb..8a011757 100644 --- a/contracts/interfaces/uniswap/IUniswapV3Adapter.sol +++ b/contracts/interfaces/uniswap/IUniswapV3Adapter.sol @@ -1,12 +1,18 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {ISwapRouter} from "../../integrations/uniswap/IUniswapV3.sol"; +struct UniswapV3Pool { + address token0; + address token1; + uint24 fee; +} + struct UniswapV3PoolStatus { address token0; address token1; @@ -46,46 +52,29 @@ interface IUniswapV3AdapterTypes { } } -interface IUniswapV3AdapterEvents { +/// @title Uniswap V3 Router adapter interface +interface IUniswapV3Adapter is IAdapter, IUniswapV3AdapterTypes { /// @notice Emitted when new status is set for a pool event SetPoolStatus(address indexed token0, address indexed token1, uint24 indexed fee, bool allowed); -} -interface IUniswapV3AdapterExceptions { /// @notice Thrown when sanity checks on a swap path fail error InvalidPathException(); -} -/// @title Uniswap V3 Router adapter interface -interface IUniswapV3Adapter is - IAdapter, - IUniswapV3AdapterTypes, - IUniswapV3AdapterEvents, - IUniswapV3AdapterExceptions -{ function exactInputSingle(ISwapRouter.ExactInputSingleParams calldata params) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); - function exactDiffInputSingle(ExactDiffInputSingleParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactDiffInputSingle(ExactDiffInputSingleParams calldata params) external returns (bool useSafePrices); - function exactInput(ISwapRouter.ExactInputParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactInput(ISwapRouter.ExactInputParams calldata params) external returns (bool useSafePrices); - function exactDiffInput(ExactDiffInputParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactDiffInput(ExactDiffInputParams calldata params) external returns (bool useSafePrices); function exactOutputSingle(ISwapRouter.ExactOutputSingleParams calldata params) external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + returns (bool useSafePrices); - function exactOutput(ISwapRouter.ExactOutputParams calldata params) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function exactOutput(ISwapRouter.ExactOutputParams calldata params) external returns (bool useSafePrices); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/uniswap/IUniswapV4Adapter.sol b/contracts/interfaces/uniswap/IUniswapV4Adapter.sol new file mode 100644 index 00000000..a1d21f0c --- /dev/null +++ b/contracts/interfaces/uniswap/IUniswapV4Adapter.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +import {IUniswapV4Gateway, PoolKey} from "./IUniswapV4Gateway.sol"; + +struct UniswapV4PoolStatus { + PoolKey poolKey; + bool allowed; +} + +/// @title Uniswap V4 Router adapter interface +interface IUniswapV4Adapter is IAdapter { + event SetPoolKeyStatus( + address indexed token0, address indexed token1, uint24 fee, int24 tickSpacing, address hooks, bool allowed + ); + + error InvalidPoolKeyException(); + + function weth() external view returns (address); + + function swapExactInputSingle( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 amountIn, + uint128 amountOutMinimum, + bytes calldata hooks + ) external returns (bool); + + function swapExactInputSingleDiff( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 leftoverAmount, + uint128 rateMinRAY + ) external returns (bool); + + // ------------- // + // CONFIGURATION // + // ------------- // + + function supportedPoolKeys() external view returns (PoolKey[] memory poolKeys); + + function isPoolKeyAllowed(PoolKey calldata poolKey) external view returns (bool); + + function setPoolKeyStatusBatch(UniswapV4PoolStatus[] calldata poolKeys) external; +} diff --git a/contracts/interfaces/uniswap/IUniswapV4Gateway.sol b/contracts/interfaces/uniswap/IUniswapV4Gateway.sol new file mode 100644 index 00000000..59fdc4f4 --- /dev/null +++ b/contracts/interfaces/uniswap/IUniswapV4Gateway.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {PoolKey} from "../../integrations/uniswap/IUniswapUniversalRouter.sol"; + +interface IUniswapV4Gateway { + error UnexpectedETHTransferException(); + + function universalRouter() external view returns (address); + + function permit2() external view returns (address); + + function weth() external view returns (address); + + function swapExactInputSingle( + PoolKey calldata poolKey, + bool zeroForOne, + uint128 amountIn, + uint128 amountOutMinimum, + bytes calldata hookData + ) external returns (uint256 amount); +} diff --git a/contracts/interfaces/upshift/IUpshiftVaultAdapter.sol b/contracts/interfaces/upshift/IUpshiftVaultAdapter.sol new file mode 100644 index 00000000..89360f40 --- /dev/null +++ b/contracts/interfaces/upshift/IUpshiftVaultAdapter.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC4626Adapter} from "../erc4626/IERC4626Adapter.sol"; +import {IPhantomTokenAdapter} from "../IPhantomTokenAdapter.sol"; + +interface IUpshiftVaultAdapter is IERC4626Adapter, IPhantomTokenAdapter { + /// @notice Address of the staked phantom token + function stakedPhantomToken() external view returns (address); + + /// @notice Requests a redemption from the Upshift vault through the gateway + function requestRedeem(uint256 shares) external returns (bool); + + /// @notice Claims a redemption from the Upshift vault through the gateway + function claim(uint256 amount) external returns (bool); +} diff --git a/contracts/interfaces/upshift/IUpshiftVaultGateway.sol b/contracts/interfaces/upshift/IUpshiftVaultGateway.sol new file mode 100644 index 00000000..de2b01aa --- /dev/null +++ b/contracts/interfaces/upshift/IUpshiftVaultGateway.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; + +interface IUpshiftVaultGateway is IVersion { + function upshiftVault() external view returns (address); + function pendingAssetsOf(address account) external view returns (uint256); + function requestRedeem(uint256 shares) external; + function claim(uint256 amount) external; +} diff --git a/contracts/interfaces/velodrome/IVelodromeV2RouterAdapter.sol b/contracts/interfaces/velodrome/IVelodromeV2RouterAdapter.sol index 616de6d4..d87fb6c1 100644 --- a/contracts/interfaces/velodrome/IVelodromeV2RouterAdapter.sol +++ b/contracts/interfaces/velodrome/IVelodromeV2RouterAdapter.sol @@ -1,11 +1,18 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {Route} from "../../integrations/velodrome/IVelodromeV2Router.sol"; +struct VelodromeV2Pool { + address token0; + address token1; + bool stable; + address factory; +} + struct VelodromeV2PoolStatus { address token0; address token1; @@ -14,32 +21,28 @@ struct VelodromeV2PoolStatus { bool allowed; } -interface IVelodromeV2AdapterEvents { +/// @title Velodrome V2 Router adapter interface +interface IVelodromeV2RouterAdapter is IAdapter { /// @notice Emited when new status is set for a pair event SetPoolStatus(address indexed token0, address indexed token1, bool stable, address factory, bool allowed); -} -interface IVelodromeV2AdapterExceptions { /// @notice Thrown when sanity checks on a swap path fail error InvalidPathException(); -} -/// @title Velodrome V2 Router adapter interface -interface IVelodromeV2RouterAdapter is IAdapter, IVelodromeV2AdapterEvents, IVelodromeV2AdapterExceptions { function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); function swapDiffTokensForTokens( uint256 leftoverAmount, uint256 rateMinRAY, Route[] calldata routes, uint256 deadline - ) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + ) external returns (bool useSafePrices); // ------------- // // CONFIGURATION // diff --git a/contracts/interfaces/yearn/IYearnV2Adapter.sol b/contracts/interfaces/yearn/IYearnV2Adapter.sol index 8c24269a..5f3548d0 100644 --- a/contracts/interfaces/yearn/IYearnV2Adapter.sol +++ b/contracts/interfaces/yearn/IYearnV2Adapter.sol @@ -1,31 +1,25 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; /// @title Yearn V2 Vault adapter interface interface IYearnV2Adapter is IAdapter { function token() external view returns (address); - function tokenMask() external view returns (uint256); + function depositDiff(uint256 leftoverAmount) external returns (bool useSafePrices); - function yTokenMask() external view returns (uint256); + function deposit(uint256 amount) external returns (bool useSafePrices); - function depositDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function deposit(uint256 amount, address) external returns (bool useSafePrices); - function deposit(uint256 amount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdrawDiff(uint256 leftoverAmount) external returns (bool useSafePrices); - function deposit(uint256 amount, address) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdraw(uint256 maxShares) external returns (bool useSafePrices); - function withdrawDiff(uint256 leftoverAmount) external returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdraw(uint256 maxShares, address) external returns (bool useSafePrices); - function withdraw(uint256 maxShares) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdraw(uint256 maxShares, address) external returns (uint256 tokensToEnable, uint256 tokensToDisable); - - function withdraw(uint256 maxShares, address, uint256 maxLoss) - external - returns (uint256 tokensToEnable, uint256 tokensToDisable); + function withdraw(uint256 maxShares, address, uint256 maxLoss) external returns (bool useSafePrices); } diff --git a/contracts/interfaces/zappers/IERC20ZapperDeposits.sol b/contracts/interfaces/zappers/IERC20ZapperDeposits.sol index aa0eb004..fc8ef593 100644 --- a/contracts/interfaces/zappers/IERC20ZapperDeposits.sol +++ b/contracts/interfaces/zappers/IERC20ZapperDeposits.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; interface IERC20ZapperDeposits { function deposit(uint256 tokenInAmount, address receiver) external returns (uint256 tokenOutAmount); diff --git a/contracts/interfaces/zappers/IETHZapperDeposits.sol b/contracts/interfaces/zappers/IETHZapperDeposits.sol index 839fca2a..1eff1a4a 100644 --- a/contracts/interfaces/zappers/IETHZapperDeposits.sol +++ b/contracts/interfaces/zappers/IETHZapperDeposits.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; /// @dev Special address that denotes pure ETH address constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; diff --git a/contracts/interfaces/zappers/IZapper.sol b/contracts/interfaces/zappers/IZapper.sol index f8c2ecf9..8dd4e05c 100644 --- a/contracts/interfaces/zappers/IZapper.sol +++ b/contracts/interfaces/zappers/IZapper.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -interface IZapper { +import {IZapper as IZapperBase} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IZapper.sol"; + +interface IZapper is IZapperBase { function pool() external view returns (address); function underlying() external view returns (address); diff --git a/contracts/interfaces/zappers/IZapperRegister.sol b/contracts/interfaces/zappers/IZapperRegister.sol deleted file mode 100644 index fdb8b701..00000000 --- a/contracts/interfaces/zappers/IZapperRegister.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; - -interface IZapperRegisterEvents { - event AddZapper(address); - - event RemoveZapper(address); -} - -interface IZapperRegister is IVersion, IZapperRegisterEvents { - function zappers(address pool) external view returns (address[] memory); - - function addZapper(address zapper) external; - - function removeZapper(address zapper) external; -} diff --git a/contracts/test/config/TEST_DAI_Mainnet_config.sol b/contracts/test/config/TEST_DAI_Mainnet_config.sol deleted file mode 100644 index 5e1d9051..00000000 --- a/contracts/test/config/TEST_DAI_Mainnet_config.sol +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox. Generalized leverage protocol that allows to take leverage and then use it across other DeFi protocols and platforms in a composable way. -// (c) Gearbox Holdings, 2022 -pragma solidity ^0.8.17; - -import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; -import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import { - LinearIRMV3DeployParams, - PoolV3DeployParams, - CreditManagerV3DeployParams, - GaugeRate, - PoolQuotaLimit, - IPoolV3DeployConfig, - CollateralTokenHuman, - GenericSwapPair, - UniswapV3Pair, - BalancerPool, - VelodromeV2Pool, - PendlePair, - MellowUnderlyingConfig -} from "@gearbox-protocol/core-v3/contracts/test/interfaces/ICreditConfig.sol"; - -contract CONFIG_MAINNET_DAI_TEST_V3 is IPoolV3DeployConfig { - string public constant id = "mainnet-dai-test-v3"; - uint256 public constant chainId = 1; - uint256 public constant underlying = TOKEN_DAI; - bool public constant supportsQuotas = true; - uint256 public constant getAccountAmount = 100_000_000_000_000_000_000_000; - - // POOL - - string public constant symbol = "dDAI-test-V3"; - string public constant name = "Test DAI v3"; - - PoolV3DeployParams _poolParams = - PoolV3DeployParams({withdrawalFee: 0, totalDebtLimit: 100_000_000_000_000_000_000_000_000}); - - LinearIRMV3DeployParams _irm = LinearIRMV3DeployParams({ - U_1: 7_000, - U_2: 9_000, - R_base: 0, - R_slope1: 100, - R_slope2: 125, - R_slope3: 10_000, - _isBorrowingMoreU2Forbidden: true - }); - - GaugeRate[] _gaugeRates; - PoolQuotaLimit[] _quotaLimits; - - CreditManagerV3DeployParams[] _creditManagers; - - constructor() { - _gaugeRates.push(GaugeRate({token: TOKEN_USDS, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_stkUSDS, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_SKY, minRate: 4, maxRate: 1_500})); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_USDS, quotaIncreaseFee: 1, limit: 10_000_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_stkUSDS, quotaIncreaseFee: 1, limit: 10_000_000_000_000_000_000_000_000}) - ); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_SKY, quotaIncreaseFee: 1, limit: 0})); - - { - /// CREDIT_MANAGER_0 - CreditManagerV3DeployParams storage cp = _creditManagers.push(); - - cp.minDebt = 50_000_000_000_000_000_000_000; - cp.maxDebt = 1_000_000_000_000_000_000_000_000; - cp.feeInterest = 2500; - cp.feeLiquidation = 150; - cp.liquidationPremium = 400; - cp.feeLiquidationExpired = 100; - cp.liquidationPremiumExpired = 200; - cp.whitelisted = false; - cp.expirable = false; - cp.skipInit = false; - cp.poolLimit = 5_000_000_000_000_000_000_000_000; - cp.name = "Test Credit Manager"; - - CollateralTokenHuman[] storage cts = cp.collateralTokens; - cts.push(CollateralTokenHuman({token: TOKEN_USDS, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_stkUSDS, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_SKY, lt: 0})); - Contracts[] storage cs = cp.contracts; - cs.push(Contracts.DAI_USDS); - cs.push(Contracts.SKY_STAKING_REWARDS); - cs.push(Contracts.UNISWAP_V2_ROUTER); - { - GenericSwapPair[] storage gsp = cp.adapterConfig.genericSwapPairs; - gsp.push(GenericSwapPair({router: Contracts.UNISWAP_V2_ROUTER, token0: TOKEN_SKY, token1: TOKEN_USDS})); - } - } - } - - // GETTERS - - function poolParams() external view override returns (PoolV3DeployParams memory) { - return _poolParams; - } - - function irm() external view override returns (LinearIRMV3DeployParams memory) { - return _irm; - } - - function gaugeRates() external view override returns (GaugeRate[] memory) { - return _gaugeRates; - } - - function quotaLimits() external view override returns (PoolQuotaLimit[] memory) { - return _quotaLimits; - } - - function creditManagers() external view override returns (CreditManagerV3DeployParams[] memory) { - return _creditManagers; - } -} diff --git a/contracts/test/config/TEST_WETH_Mainnet_config.sol b/contracts/test/config/TEST_WETH_Mainnet_config.sol deleted file mode 100644 index 546d3b47..00000000 --- a/contracts/test/config/TEST_WETH_Mainnet_config.sol +++ /dev/null @@ -1,277 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox. Generalized leverage protocol that allows to take leverage and then use it across other DeFi protocols and platforms in a composable way. -// (c) Gearbox Holdings, 2022 -pragma solidity ^0.8.17; - -import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; -import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import { - LinearIRMV3DeployParams, - PoolV3DeployParams, - CreditManagerV3DeployParams, - GaugeRate, - PoolQuotaLimit, - IPoolV3DeployConfig, - CollateralTokenHuman, - GenericSwapPair, - UniswapV3Pair, - BalancerPool, - VelodromeV2Pool, - PendlePair, - MellowUnderlyingConfig -} from "@gearbox-protocol/core-v3/contracts/test/interfaces/ICreditConfig.sol"; - -contract CONFIG_MAINNET_WETH_TEST_V3 is IPoolV3DeployConfig { - string public constant id = "mainnet-weth-test-v3"; - uint256 public constant chainId = 1; - uint256 public constant underlying = TOKEN_WETH; - bool public constant supportsQuotas = true; - uint256 public constant getAccountAmount = 50_000_000_000_000_000_000; - - // POOL - - string public constant symbol = "dWETH-test-V3"; - string public constant name = "Test WETH v3"; - - PoolV3DeployParams _poolParams = - PoolV3DeployParams({withdrawalFee: 0, totalDebtLimit: 100_000_000_000_000_000_000_000}); - - LinearIRMV3DeployParams _irm = LinearIRMV3DeployParams({ - U_1: 7_000, - U_2: 9_000, - R_base: 0, - R_slope1: 100, - R_slope2: 125, - R_slope3: 10_000, - _isBorrowingMoreU2Forbidden: true - }); - - GaugeRate[] _gaugeRates; - PoolQuotaLimit[] _quotaLimits; - - CreditManagerV3DeployParams[] _creditManagers; - - constructor() { - _gaugeRates.push(GaugeRate({token: TOKEN_LDO, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_CRV, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_CVX, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_steCRV, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_cvxsteCRV, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_rsETH_WETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_trenSTETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_Re7LRT, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_rstETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_amphrETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_STETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_stkcvxsteCRV, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_wstETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_steakLRT, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_rsETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_PT_rsETH_26SEP2024, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_USDC, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_WBTC, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_pufETHwstE, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_pufETH, minRate: 4, maxRate: 1_500})); - _gaugeRates.push(GaugeRate({token: TOKEN_zpufETH, minRate: 4, maxRate: 1_500})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_LDO, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_CRV, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_CVX, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_steCRV, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_cvxsteCRV, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_rsETH_WETH, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_trenSTETH, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_Re7LRT, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_rstETH, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_amphrETH, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_STETH, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_stkcvxsteCRV, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_wstETH, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_steakLRT, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_rsETH, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_PT_rsETH_26SEP2024, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_USDC, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_WBTC, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push(PoolQuotaLimit({token: TOKEN_pufETHwstE, quotaIncreaseFee: 0, limit: 0})); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_pufETH, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - _quotaLimits.push( - PoolQuotaLimit({token: TOKEN_zpufETH, quotaIncreaseFee: 0, limit: 4_000_000_000_000_000_000_000}) - ); - - { - /// CREDIT_MANAGER_0 - CreditManagerV3DeployParams storage cp = _creditManagers.push(); - - cp.minDebt = 20_000_000_000_000_000_000; - cp.maxDebt = 400_000_000_000_000_000_000; - cp.feeInterest = 2500; - cp.feeLiquidation = 150; - cp.liquidationPremium = 400; - cp.feeLiquidationExpired = 100; - cp.liquidationPremiumExpired = 200; - cp.whitelisted = false; - cp.expirable = false; - cp.skipInit = false; - cp.poolLimit = 5_000_000_000_000_000_000_000; - cp.name = "Test Credit Manager"; - - CollateralTokenHuman[] storage cts = cp.collateralTokens; - cts.push(CollateralTokenHuman({token: TOKEN_USDC, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_WBTC, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_STETH, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_wstETH, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_steakLRT, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_rsETH, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_PT_rsETH_26SEP2024, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_stkcvxsteCRV, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_pufETH, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_zpufETH, lt: 9_000})); - - cts.push(CollateralTokenHuman({token: TOKEN_steCRV, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_cvxsteCRV, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_rsETH_WETH, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_trenSTETH, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_Re7LRT, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_rstETH, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_amphrETH, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_LDO, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_CRV, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_CVX, lt: 0})); - - cts.push(CollateralTokenHuman({token: TOKEN_pufETHwstE, lt: 0})); - Contracts[] storage cs = cp.contracts; - cs.push(Contracts.UNISWAP_V3_ROUTER); - { - UniswapV3Pair[] storage uv3p = cp.adapterConfig.uniswapV3Pairs; - uv3p.push( - UniswapV3Pair({ - router: Contracts.UNISWAP_V3_ROUTER, - token0: TOKEN_WETH, - token1: TOKEN_WBTC, - fee: 3000 - }) - ); - uv3p.push( - UniswapV3Pair({ - router: Contracts.UNISWAP_V3_ROUTER, - token0: TOKEN_WETH, - token1: TOKEN_USDC, - fee: 500 - }) - ); - uv3p.push( - UniswapV3Pair({ - router: Contracts.UNISWAP_V3_ROUTER, - token0: TOKEN_WETH, - token1: TOKEN_CRV, - fee: 3000 - }) - ); - uv3p.push( - UniswapV3Pair({ - router: Contracts.UNISWAP_V3_ROUTER, - token0: TOKEN_WETH, - token1: TOKEN_CRV, - fee: 10000 - }) - ); - uv3p.push( - UniswapV3Pair({ - router: Contracts.UNISWAP_V3_ROUTER, - token0: TOKEN_WETH, - token1: TOKEN_CVX, - fee: 10000 - }) - ); - } - cs.push(Contracts.PENDLE_ROUTER); - PendlePair[] storage pendp = cp.adapterConfig.pendlePairs; - pendp.push( - PendlePair({ - market: 0x6b4740722e46048874d84306B2877600ABCea3Ae, - inputToken: TOKEN_rsETH, - pendleToken: TOKEN_PT_rsETH_26SEP2024, - status: 1 - }) - ); - cs.push(Contracts.BALANCER_VAULT); - BalancerPool[] storage bp = cp.adapterConfig.balancerPools; - - bp.push( - BalancerPool({poolId: 0x58aadfb1afac0ad7fca1148f3cde6aedf5236b6d00000000000000000000067f, status: 2}) - ); - - bp.push( - BalancerPool({poolId: 0x4216d5900a6109bba48418b5e2ab6cc4e61cf4770000000000000000000006a1, status: 2}) - ); - cs.push(Contracts.MELLOW_STEAKHOUSE_VAULT); - { - MellowUnderlyingConfig[] storage mu = cp.adapterConfig.mellowUnderlyings; - mu.push(MellowUnderlyingConfig({vault: Contracts.MELLOW_STEAKHOUSE_VAULT, underlying: TOKEN_wstETH})); - } - cs.push(Contracts.LIDO_WSTETH); - cs.push(Contracts.CURVE_STETH_GATEWAY); - cs.push(Contracts.CURVE_PUFETH_WSTETH_POOL); - cs.push(Contracts.CONVEX_BOOSTER); - cs.push(Contracts.CONVEX_STECRV_POOL); - cs.push(Contracts.ZIRCUIT_POOL); - } - } - - // GETTERS - - function poolParams() external view override returns (PoolV3DeployParams memory) { - return _poolParams; - } - - function irm() external view override returns (LinearIRMV3DeployParams memory) { - return _irm; - } - - function gaugeRates() external view override returns (GaugeRate[] memory) { - return _gaugeRates; - } - - function quotaLimits() external view override returns (PoolQuotaLimit[] memory) { - return _quotaLimits; - } - - function creditManagers() external view override returns (CreditManagerV3DeployParams[] memory) { - return _creditManagers; - } -} diff --git a/contracts/test/helpers/BalanceComparator.sol b/contracts/test/helpers/BalanceComparator.sol index aca50d76..4ee055a4 100644 --- a/contracts/test/helpers/BalanceComparator.sol +++ b/contracts/test/helpers/BalanceComparator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox. Generalized leverage protocol that allows to take leverage and then use it across other DeFi protocols and platforms in a composable way. -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; diff --git a/contracts/test/helpers/BalanceHelper.sol b/contracts/test/helpers/BalanceHelper.sol index 3d42d33b..d620e218 100644 --- a/contracts/test/helpers/BalanceHelper.sol +++ b/contracts/test/helpers/BalanceHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; import {TokensTestSuite} from "@gearbox-protocol/core-v3/contracts/test/suites/TokensTestSuite.sol"; diff --git a/contracts/test/helpers/CreditFacadeTestHelper.sol b/contracts/test/helpers/CreditFacadeTestHelper.sol index 6df903d1..d6ae8ab5 100644 --- a/contracts/test/helpers/CreditFacadeTestHelper.sol +++ b/contracts/test/helpers/CreditFacadeTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {TokensTestSuite} from "@gearbox-protocol/core-v3/contracts/test/suites/TokensTestSuite.sol"; @@ -26,6 +26,6 @@ contract CreditFacadeTestHelper is IntegrationTestHelper { address priceFeed = address(new PriceFeedMock(int256(price), 8)); vm.prank(CONFIGURATOR); - priceOracle.setPriceFeed(token, priceFeed, 48 hours, false); + priceOracle.setPriceFeed(token, priceFeed, 48 hours); } } diff --git a/contracts/test/lib/constants.sol b/contracts/test/lib/constants.sol index 0ad6687e..4bda1c61 100644 --- a/contracts/test/lib/constants.sol +++ b/contracts/test/lib/constants.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; diff --git a/contracts/test/live/Env.sol b/contracts/test/live/Env.sol index 73404f17..6b027459 100644 --- a/contracts/test/live/Env.sol +++ b/contracts/test/live/Env.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {LiveTestHelper} from "../suites/LiveTestHelper.sol"; diff --git a/contracts/test/live/adapters/aave/Live_AaveV2LendingPoolEquivalenceTest.sol b/contracts/test/live/adapters/aave/Live_AaveV2LendingPoolEquivalenceTest.sol deleted file mode 100644 index e9dccc26..00000000 --- a/contracts/test/live/adapters/aave/Live_AaveV2LendingPoolEquivalenceTest.sol +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; -import { - CollateralDebtData, CollateralCalcTask -} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; -import {IAaveV2_LendingPoolAdapter} from "../../../../interfaces/aave/IAaveV2_LendingPoolAdapter.sol"; -import {ILendingPool} from "../../../../integrations/aave/ILendingPool.sol"; -import {IAToken} from "../../../../integrations/aave/IAToken.sol"; - -import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; -import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; - -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; -import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; - -import {TokenType} from "@gearbox-protocol/sdk-gov/contracts/TokensData.sol"; - -import { - AaveV2_LendingPoolCalls, AaveV2_LendingPoolMulticaller -} from "../../../multicall/aave/AaveV2_LendingPoolCalls.sol"; -// TEST -import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; - -// SUITES - -import {LiveTestHelper} from "../../../suites/LiveTestHelper.sol"; -import {BalanceComparator, BalanceBackup} from "../../../helpers/BalanceComparator.sol"; - -contract Live_AaveV2LendingPoolEquivalenceTest is LiveTestHelper { - using AaveV2_LendingPoolCalls for AaveV2_LendingPoolMulticaller; - - BalanceComparator comparator; - - function prepareComparator(address aToken, address underlying) internal { - uint256[2] memory tokensToTrack = [tokenTestSuite.tokenIndexes(underlying), tokenTestSuite.tokenIndexes(aToken)]; - - // STAGES - string[4] memory stages = ["after_deposit", "after_depositDiff", "after_withdraw", "after_withdrawDiff"]; - - /// @notice Sets comparator for this equivalence test - - uint256 len = stages.length; - string[] memory _stages = new string[](len); - unchecked { - for (uint256 i; i < len; ++i) { - _stages[i] = stages[i]; - } - } - - len = tokensToTrack.length; - uint256[] memory _tokensToTrack = new uint256[](len); - unchecked { - for (uint256 i; i < len; ++i) { - _tokensToTrack[i] = tokensToTrack[i]; - } - } - - comparator = new BalanceComparator(_stages, _tokensToTrack, tokenTestSuite); - } - - function compareBehavior( - address creditAccount, - address lendingPoolAddr, - address aToken, - address underlying, - bool isAdapter - ) internal { - if (isAdapter) { - AaveV2_LendingPoolMulticaller lendingPool = AaveV2_LendingPoolMulticaller(lendingPoolAddr); - - vm.startPrank(USER); - - creditFacade.multicall( - creditAccount, MultiCallBuilder.build(lendingPool.deposit(underlying, WAD, creditAccount, 0)) - ); - comparator.takeSnapshot("after_deposit", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(lendingPool.depositDiff(underlying, 20 * WAD))); - comparator.takeSnapshot("after_depositDiff", creditAccount); - - creditFacade.multicall( - creditAccount, MultiCallBuilder.build(lendingPool.withdraw(underlying, WAD, creditAccount)) - ); - comparator.takeSnapshot("after_withdraw", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(lendingPool.withdrawDiff(underlying, WAD))); - comparator.takeSnapshot("after_withdrawDiff", creditAccount); - - vm.stopPrank(); - } else { - ILendingPool lendingPool = ILendingPool(lendingPoolAddr); - - vm.startPrank(creditAccount); - - lendingPool.deposit(underlying, WAD, creditAccount, 0); - comparator.takeSnapshot("after_deposit", creditAccount); - - uint256 balanceToSwap = tokenTestSuite.balanceOf(underlying, creditAccount) - 20 * WAD; - lendingPool.deposit(underlying, balanceToSwap, creditAccount, 0); - comparator.takeSnapshot("after_depositDiff", creditAccount); - - lendingPool.withdraw(underlying, WAD, creditAccount); - comparator.takeSnapshot("after_withdraw", creditAccount); - - balanceToSwap = tokenTestSuite.balanceOf(aToken, creditAccount) - WAD; - lendingPool.withdraw(underlying, balanceToSwap, creditAccount); - comparator.takeSnapshot("after_withdrawDiff", creditAccount); - - vm.stopPrank(); - } - } - - function openCreditAccountWithUnderlying(address token, uint256 amount) internal returns (address creditAccount) { - vm.prank(USER); - creditAccount = creditFacade.openCreditAccount(USER, MultiCallBuilder.build(), 0); - tokenTestSuite.mint(token, creditAccount, amount); - } - - /// @dev [L-AV2ET-1]: AaveV2 adapter and normal account works identically - function test_live_AV2ET_01_AaveV2_adapter_and_normal_account_works_identically() public attachOrLiveTest { - uint256 collateralTokensCount = creditManager.collateralTokensCount(); - - for (uint256 i = 0; i < collateralTokensCount; ++i) { - address token = creditManager.getTokenByMask(1 << i); - - if (tokenTestSuite.tokenTypes(tokenTestSuite.tokenIndexes(token)) != TokenType.AAVE_V2_A_TOKEN) continue; - - address underlying = IAToken(token).UNDERLYING_ASSET_ADDRESS(); - - prepareComparator(token, underlying); - - address creditAccount = - openCreditAccountWithUnderlying(underlying, 100 * 10 ** IERC20Metadata(underlying).decimals()); - - address lendingPoolAdapter = getAdapter(address(creditManager), Contracts.AAVE_V2_LENDING_POOL); - - tokenTestSuite.approve( - underlying, creditAccount, supportedContracts.addressOf(Contracts.AAVE_V2_LENDING_POOL) - ); - - tokenTestSuite.approve(token, creditAccount, supportedContracts.addressOf(Contracts.AAVE_V2_LENDING_POOL)); - - uint256 snapshot = vm.snapshot(); - - compareBehavior( - creditAccount, supportedContracts.addressOf(Contracts.AAVE_V2_LENDING_POOL), token, underlying, false - ); - - /// Stores save balances in memory, because all state data would be reverted afer snapshot - BalanceBackup[] memory savedBalanceSnapshots = comparator.exportSnapshots(creditAccount); - - vm.revertTo(snapshot); - - compareBehavior(creditAccount, lendingPoolAdapter, token, underlying, true); - - comparator.compareAllSnapshots(creditAccount, savedBalanceSnapshots); - } - } - - function test_diag_profits() public attachOrLiveTest { - uint256 cmProfit = 0; - - address[] memory creditAccounts = creditManager.creditAccounts(); - - for (uint256 j = 0; j < creditAccounts.length; ++j) { - CollateralDebtData memory cdd = - creditManager.calcDebtAndCollateral(creditAccounts[j], CollateralCalcTask.DEBT_ONLY); - - cmProfit += cdd.accruedFees; - } - - emit log_address(address(creditManager)); - emit log_uint(cmProfit); - } - - function test_diag_pf() public attachOrLiveTest { - emit log_uint(priceOracle.getPrice(tokenTestSuite.addressOf(TOKEN_ezETH))); - } -} diff --git a/contracts/test/live/adapters/aave/Live_AaveV2WrappedATokenEquivalenceTest.sol b/contracts/test/live/adapters/aave/Live_AaveV2WrappedATokenEquivalenceTest.sol deleted file mode 100644 index 720b81ce..00000000 --- a/contracts/test/live/adapters/aave/Live_AaveV2WrappedATokenEquivalenceTest.sol +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; -import {IAaveV2_WrappedATokenAdapter} from "../../../../interfaces/aave/IAaveV2_WrappedATokenAdapter.sol"; -import {WrappedAToken} from "../../../../helpers/aave/AaveV2_WrappedAToken.sol"; -import {IAToken} from "../../../../integrations/aave/IAToken.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; - -import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; -import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; - -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; -import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; - -import {TokenType} from "@gearbox-protocol/sdk-gov/contracts/TokensData.sol"; - -import { - AaveV2_WrappedATokenCalls, - AaveV2_WrappedATokenMulticaller -} from "../../../multicall/aave/AaveV2_WrappedATokenCalls.sol"; -// TEST -import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; - -// SUITES - -import {LiveTestHelper} from "../../../suites/LiveTestHelper.sol"; -import {BalanceComparator, BalanceBackup} from "../../../helpers/BalanceComparator.sol"; - -contract Live_AaveV2WrappedATokenEquivalenceTest is LiveTestHelper { - using AaveV2_WrappedATokenCalls for AaveV2_WrappedATokenMulticaller; - - BalanceComparator comparator; - - function prepareComparator(address waToken) internal { - address aToken = WrappedAToken(waToken).aToken(); - address underlying = WrappedAToken(waToken).underlying(); - - uint256[3] memory tokensToTrack = [ - tokenTestSuite.tokenIndexes(waToken), - tokenTestSuite.tokenIndexes(underlying), - tokenTestSuite.tokenIndexes(aToken) - ]; - - // STAGES - string[8] memory stages = [ - "after_deposit", - "after_depositDiff", - "after_depositUnderlying", - "after_depositDiffUnderlying", - "after_withdraw", - "after_withdrawDiff", - "after_withdrawUnderlying", - "after_withdrawDiffUnderlying" - ]; - - uint256 len = stages.length; - string[] memory _stages = new string[](len); - unchecked { - for (uint256 i; i < len; ++i) { - _stages[i] = stages[i]; - } - } - - len = tokensToTrack.length; - uint256[] memory _tokensToTrack = new uint256[](len); - unchecked { - for (uint256 i; i < len; ++i) { - _tokensToTrack[i] = tokensToTrack[i]; - } - } - - comparator = new BalanceComparator(_stages, _tokensToTrack, tokenTestSuite); - } - - function compareBehavior( - address creditAccount, - address waTokenAddr, - address aToken, - address underlying, - uint256 baseUnit, - bool isAdapter - ) internal { - if (isAdapter) { - AaveV2_WrappedATokenMulticaller waToken = AaveV2_WrappedATokenMulticaller(waTokenAddr); - - vm.startPrank(USER); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.deposit(baseUnit))); - comparator.takeSnapshot("after_deposit", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.depositDiff(20 * baseUnit))); - comparator.takeSnapshot("after_depositDiff", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.depositUnderlying(baseUnit))); - comparator.takeSnapshot("after_depositUnderlying", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.depositDiffUnderlying(20 * baseUnit))); - comparator.takeSnapshot("after_depositDiffUnderlying", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.withdraw(baseUnit))); - comparator.takeSnapshot("after_withdraw", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.withdrawDiff(10 * baseUnit))); - comparator.takeSnapshot("after_withdrawDiff", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.withdrawUnderlying(baseUnit))); - comparator.takeSnapshot("after_withdrawUnderlying", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(waToken.withdrawDiffUnderlying(baseUnit))); - comparator.takeSnapshot("after_withdrawDiffUnderlying", creditAccount); - - vm.stopPrank(); - } else { - WrappedAToken waToken = WrappedAToken(waTokenAddr); - - vm.startPrank(creditAccount); - - waToken.deposit(baseUnit); - comparator.takeSnapshot("after_deposit", creditAccount); - - uint256 balanceToSwap = IERC20(aToken).balanceOf(creditAccount) - 20 * baseUnit; - waToken.deposit(balanceToSwap); - comparator.takeSnapshot("after_depositDiff", creditAccount); - - waToken.depositUnderlying(baseUnit); - comparator.takeSnapshot("after_depositUnderlying", creditAccount); - - balanceToSwap = IERC20(underlying).balanceOf(creditAccount) - 20 * baseUnit; - waToken.depositUnderlying(balanceToSwap); - comparator.takeSnapshot("after_depositDiffUnderlying", creditAccount); - - waToken.withdraw(baseUnit); - comparator.takeSnapshot("after_withdraw", creditAccount); - - balanceToSwap = IERC20(waToken).balanceOf(creditAccount) - 10 * baseUnit; - waToken.withdraw(balanceToSwap); - comparator.takeSnapshot("after_withdrawDiff", creditAccount); - - waToken.withdrawUnderlying(baseUnit); - comparator.takeSnapshot("after_withdrawUnderlying", creditAccount); - - balanceToSwap = IERC20(waToken).balanceOf(creditAccount) - baseUnit; - waToken.withdrawUnderlying(balanceToSwap); - comparator.takeSnapshot("after_withdrawDiffUnderlying", creditAccount); - - vm.stopPrank(); - } - } - - function openCreditAccountWithUnderlying(address token, uint256 amount) internal returns (address creditAccount) { - vm.prank(USER); - creditAccount = creditFacade.openCreditAccount(USER, MultiCallBuilder.build(), 0); - tokenTestSuite.mint(token, creditAccount, amount); - } - - /// @dev [L-WAV2ET-1]: Wrapped AToken adapters and original contracts work identically - function test_live_WAV2ET_01_waToken_adapters_and_original_contracts_are_equivalent() public attachOrLiveTest { - address[] memory adapters = creditConfigurator.allowedAdapters(); - - for (uint256 i = 0; i < adapters.length; ++i) { - if (IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.AAVE_V2_WRAPPED_ATOKEN) continue; - - uint256 snapshot0 = vm.snapshot(); - - address waToken = IAaveV2_WrappedATokenAdapter(adapters[i]).targetContract(); - address aToken = IAaveV2_WrappedATokenAdapter(adapters[i]).aToken(); - address underlying = IAaveV2_WrappedATokenAdapter(adapters[i]).underlying(); - - address creditAccount = - openCreditAccountWithUnderlying(underlying, 3000 * 10 ** IERC20Metadata(underlying).decimals()); - - tokenTestSuite.approve(underlying, creditAccount, waToken); - tokenTestSuite.approve(aToken, creditAccount, waToken); - - uint256 snapshot1 = vm.snapshot(); - - prepareComparator(waToken); - - compareBehavior( - creditAccount, waToken, aToken, underlying, 10 ** IERC20Metadata(underlying).decimals(), false - ); - - BalanceBackup[] memory savedBalanceSnapshots = comparator.exportSnapshots(creditAccount); - - vm.revertTo(snapshot1); - - prepareComparator(waToken); - - compareBehavior( - creditAccount, adapters[i], aToken, underlying, 10 ** IERC20Metadata(underlying).decimals(), true - ); - - comparator.compareAllSnapshots(creditAccount, savedBalanceSnapshots, 0); - - vm.revertTo(snapshot0); - } - } -} diff --git a/contracts/test/live/adapters/balancer/Live_BalancerV2EquivalenceTest.sol b/contracts/test/live/adapters/balancer/Live_BalancerV2EquivalenceTest.sol index 91364b52..5372a98c 100644 --- a/contracts/test/live/adapters/balancer/Live_BalancerV2EquivalenceTest.sol +++ b/contracts/test/live/adapters/balancer/Live_BalancerV2EquivalenceTest.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import { IBalancerV2Vault, SingleSwap, @@ -33,7 +33,7 @@ import {BalancerV2_Calls, BalancerV2_Multicaller} from "../../../multicall/balan import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; // TEST @@ -55,6 +55,7 @@ struct BalancerPoolParams { contract Live_BalancerV2EquivalenceTest is LiveTestHelper { using BalancerV2_Calls for BalancerV2_Multicaller; using AddressList for address[]; + using Address for address; BalanceComparator comparator; @@ -75,16 +76,15 @@ contract Live_BalancerV2EquivalenceTest is LiveTestHelper { function setUp() public { uint256 len = stages.length; _stages = new string[](len); - unchecked { - for (uint256 i; i < len; ++i) { - _stages[i] = stages[i]; - } + + for (uint256 i; i < len; ++i) { + _stages[i] = stages[i]; } } /// HELPER - function _getDefaultFundManagement(address creditAccount) internal returns (FundManagement memory) { + function _getDefaultFundManagement(address creditAccount) internal pure returns (FundManagement memory) { return FundManagement({ sender: creditAccount, fromInternalBalance: false, @@ -207,13 +207,11 @@ contract Live_BalancerV2EquivalenceTest is LiveTestHelper { } if (isAdapter) { - BalancerV2_Multicaller vault = BalancerV2_Multicaller(balancerVaultAddress); - creditFacade.multicall( creditAccount, MultiCallBuilder.build(MultiCall({target: balancerVaultAddress, callData: callData})) ); } else { - address(balancerVaultAddress).call(callData); + address(balancerVaultAddress).functionCall(callData); } comparator.takeSnapshot("after_batchSwap", creditAccount); @@ -602,9 +600,6 @@ contract Live_BalancerV2EquivalenceTest is LiveTestHelper { uint256 snapshot0 = vm.snapshot(); - (IERC20[] memory tokens,,) = - IBalancerV2Vault(IAdapter(balancerVaultAdapter).targetContract()).getPoolTokens(poolId); - BalancerPoolParams memory params = BalancerPoolParams({ poolToken: pool, poolId: poolId, diff --git a/contracts/test/live/adapters/camelot/Live_CamelotV3EquivalenceTest.sol b/contracts/test/live/adapters/camelot/Live_CamelotV3EquivalenceTest.sol index 84be1109..fbebd7ee 100644 --- a/contracts/test/live/adapters/camelot/Live_CamelotV3EquivalenceTest.sol +++ b/contracts/test/live/adapters/camelot/Live_CamelotV3EquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; @@ -11,7 +11,7 @@ import {ICamelotV3Adapter, ICamelotV3AdapterTypes} from "../../../../interfaces/ import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {CamelotV3_Calls, CamelotV3_Multicaller} from "../../../multicall/camelot/CamelotV3_Calls.sol"; diff --git a/contracts/test/live/adapters/compound/Live_CompoundV2EquivalenceTest.sol b/contracts/test/live/adapters/compound/Live_CompoundV2EquivalenceTest.sol deleted file mode 100644 index 2f5cd220..00000000 --- a/contracts/test/live/adapters/compound/Live_CompoundV2EquivalenceTest.sol +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; -import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; - -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; -import {ICErc20, ICErc20Actions} from "../../../../integrations/compound/ICErc20.sol"; -import {ICompoundV2_CTokenAdapter} from "../../../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; -import {CompoundV2_Calls, CompoundV2_Multicaller} from "../../../multicall/compound/CompoundV2_Calls.sol"; - -import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; -import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; - -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; -import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; -import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; -// TEST -import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; - -// SUITES -import {LiveTestHelper} from "../../../suites/LiveTestHelper.sol"; -import {BalanceComparator, BalanceBackup} from "../../../helpers/BalanceComparator.sol"; - -contract Live_CompoundV2EquivalenceTest is LiveTestHelper { - using CompoundV2_Calls for CompoundV2_Multicaller; - using AddressList for address[]; - - string[5] stages = ["after_mint", "after_mintDiff", "after_redeem", "after_redeemDiff", "after_redeemUnderlying"]; - - string[] _stages; - - function setUp() public { - uint256 len = stages.length; - _stages = new string[](len); - unchecked { - for (uint256 i; i < len; ++i) { - _stages[i] = stages[i]; - } - } - } - - /// HELPER - - function compareBehavior( - address creditAccount, - address cTokenAddress, - address underlyingToken, - bool isAdapter, - BalanceComparator comparator - ) internal { - address cTokenShare = isAdapter ? ICompoundV2_CTokenAdapter(cTokenAddress).targetContract() : cTokenAddress; - uint256 baseUnit = IERC20Metadata(underlyingToken).decimals(); - - if (isAdapter) { - CompoundV2_Multicaller cToken = CompoundV2_Multicaller(cTokenAddress); - - vm.startPrank(USER); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(cToken.mint(10 * baseUnit))); - comparator.takeSnapshot("after_mint", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(cToken.mintDiff(10 * baseUnit))); - comparator.takeSnapshot("after_mintDiff", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(cToken.redeem(5 * baseUnit))); - comparator.takeSnapshot("after_redeem", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(cToken.redeemDiff(5 * baseUnit))); - comparator.takeSnapshot("after_redeemDiff", creditAccount); - - creditFacade.multicall(creditAccount, MultiCallBuilder.build(cToken.redeemUnderlying(2 * baseUnit))); - comparator.takeSnapshot("after_redeemUnderlying", creditAccount); - - vm.stopPrank(); - } else { - ICErc20Actions cToken = ICErc20Actions(cTokenAddress); - - vm.startPrank(creditAccount); - - cToken.mint(10 * baseUnit); - comparator.takeSnapshot("after_mint", creditAccount); - - uint256 amountToSwap = IERC20(underlyingToken).balanceOf(creditAccount) - 10 * baseUnit; - cToken.mint(amountToSwap); - comparator.takeSnapshot("after_mintDiff", creditAccount); - - cToken.redeem(5 * baseUnit); - comparator.takeSnapshot("after_redeem", creditAccount); - - amountToSwap = IERC20(cTokenShare).balanceOf(creditAccount) - 5 * baseUnit; - cToken.redeem(amountToSwap); - comparator.takeSnapshot("after_redeemDiff", creditAccount); - - cToken.redeemUnderlying(2 * baseUnit); - comparator.takeSnapshot("after_redeemUnderlying", creditAccount); - - vm.stopPrank(); - } - } - - function openCreditAccountWithUnderlying(address token, uint256 amount) internal returns (address creditAccount) { - vm.prank(USER); - creditAccount = creditFacade.openCreditAccount(USER, MultiCallBuilder.build(), 0); - - tokenTestSuite.mint(token, creditAccount, amount); - } - - function prepareComparator(address cTokenAdapter, address underlying) - internal - returns (BalanceComparator comparator) - { - address[] memory tokensToTrack = new address[](2); - - tokensToTrack[0] = underlying; - tokensToTrack[1] = ICompoundV2_CTokenAdapter(cTokenAdapter).targetContract(); - - uint256[] memory _tokensToTrack = new uint256[](tokensToTrack.length); - - for (uint256 j = 0; j < tokensToTrack.length; ++j) { - _tokensToTrack[j] = tokenTestSuite.tokenIndexes(tokensToTrack[j]); - } - - comparator = new BalanceComparator(_stages, _tokensToTrack, tokenTestSuite); - } - - /// @dev [L-COMPV2ET-1]: CompoundV2 adapters and original contracts work identically - function test_live_COMPV2ET_01_Compound_V2_adapters_and_original_contracts_are_equivalent() - public - attachOrLiveTest - { - address[] memory adapters = creditConfigurator.allowedAdapters(); - - for (uint256 i = 0; i < adapters.length; ++i) { - if ( - IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.COMPOUND_V2_CERC20 - && IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.COMPOUND_V2_CETHER - ) continue; - - uint256 snapshot0 = vm.snapshot(); - - address underlying = ICompoundV2_CTokenAdapter(adapters[i])._gearboxAdapterType() - == AdapterType.COMPOUND_V2_CETHER ? tokenTestSuite.addressOf(TOKEN_WETH) : ICErc20(adapters[i]).underlying(); - - address creditAccount = - openCreditAccountWithUnderlying(underlying, 3000 * 10 ** IERC20Metadata(underlying).decimals()); - - tokenTestSuite.approve(underlying, creditAccount, IAdapter(adapters[i]).targetContract()); - - uint256 snapshot1 = vm.snapshot(); - - BalanceComparator comparator = prepareComparator(adapters[i], underlying); - - compareBehavior(creditAccount, IAdapter(adapters[i]).targetContract(), underlying, false, comparator); - - BalanceBackup[] memory savedBalanceSnapshots = comparator.exportSnapshots(creditAccount); - - vm.revertTo(snapshot1); - - comparator = prepareComparator(adapters[i], underlying); - - compareBehavior(creditAccount, adapters[i], underlying, true, comparator); - - comparator.compareAllSnapshots(creditAccount, savedBalanceSnapshots, 0); - - vm.revertTo(snapshot0); - } - } -} diff --git a/contracts/test/live/adapters/convex/Live_ConvexEquivalenceTest.t.sol b/contracts/test/live/adapters/convex/Live_ConvexEquivalenceTest.t.sol index 8f2fd039..b5e1917e 100644 --- a/contracts/test/live/adapters/convex/Live_ConvexEquivalenceTest.t.sol +++ b/contracts/test/live/adapters/convex/Live_ConvexEquivalenceTest.t.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; @@ -10,19 +11,26 @@ import {IBaseRewardPool} from "../../../../integrations/convex/IBaseRewardPool.s import {IRewards} from "../../../../integrations/convex/IRewards.sol"; import {IBooster} from "../../../../integrations/convex/IBooster.sol"; import {IConvexV1BaseRewardPoolAdapter} from "../../../../interfaces/convex/IConvexV1BaseRewardPoolAdapter.sol"; +import {ConvexStakedPositionToken} from "../../../../helpers/convex/ConvexV1_StakedPositionToken.sol"; +import { + IPhantomToken, + IPhantomTokenWithdrawer +} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; +import {PriceFeedParams} from "@gearbox-protocol/core-v3/contracts/interfaces/IPriceOracleV3.sol"; +import {IPriceFeed} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPriceFeed.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; import { ConvexV1_BaseRewardPoolCalls, ConvexV1_BaseRewardPoolMulticaller } from "../../../multicall/convex/ConvexV1_BaseRewardPoolCalls.sol"; import {ConvexV1_BoosterCalls, ConvexV1_BoosterMulticaller} from "../../../multicall/convex/ConvexV1_BoosterCalls.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; @@ -246,7 +254,7 @@ contract Live_ConvexEquivalenceTest is LiveTestHelper { address[] memory adapters = creditConfigurator.allowedAdapters(); for (uint256 i = 0; i < adapters.length; ++i) { - if (IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.CONVEX_V1_BASE_REWARD_POOL) continue; + if (IAdapter(adapters[i]).contractType() != "ADAPTER::CVX_V1_BASE_REWARD_POOL") continue; uint256 snapshot0 = vm.snapshot(); @@ -282,4 +290,60 @@ contract Live_ConvexEquivalenceTest is LiveTestHelper { vm.revertTo(snapshot0); } } + + /// @dev [L-CVXET-2]: Withdrawals for Convex phantom tokens work correctly + function test_live_CVXET_02_Convex_phantom_token_withdrawals_work_correctly() public attachOrLiveTest { + uint256 collateralTokensCount = creditManager.collateralTokensCount(); + + for (uint256 i = 0; i < collateralTokensCount; ++i) { + uint256 snapshot = vm.snapshot(); + + address token = creditManager.getTokenByMask(1 << i); + + try IPhantomToken(token).getPhantomTokenInfo() returns (address target, address) { + address adapter = creditManager.contractToAdapter(target); + if (IAdapter(adapter).contractType() != "ADAPTER::CVX_V1_BASE_REWARD_POOL") continue; + } catch { + continue; + } + + address boosterAdapter = creditManager.contractToAdapter(ConvexStakedPositionToken(token).booster()); + address pool = ConvexStakedPositionToken(token).pool(); + + uint256 pid = IBaseRewardPool(pool).pid(); + + if (priceOracle.reservePriceFeeds(token) == address(0)) { + PriceFeedParams memory pfParams = priceOracle.priceFeedParams(token); + vm.prank(Ownable(address(acl)).owner()); + priceOracle.setReservePriceFeed(token, pfParams.priceFeed, pfParams.stalenessPeriod); + } + + address curveToken = ConvexStakedPositionToken(token).curveToken(); + + address creditAccount = openCreditAccountWithUnderlying(curveToken, 100 * WAD); + + vm.prank(USER); + creditFacade.multicall( + creditAccount, + MultiCallBuilder.build(ConvexV1_BoosterMulticaller(boosterAdapter).deposit(pid, WAD, true)) + ); + + address poolAdapter = creditManager.contractToAdapter(pool); + + vm.expectCall(poolAdapter, abi.encodeCall(IPhantomTokenWithdrawer.withdrawPhantomToken, (token, WAD))); + vm.prank(USER); + MultiCall memory call = MultiCall({ + target: address(creditFacade), + callData: abi.encodeCall(ICreditFacadeV3Multicall.withdrawCollateral, (token, WAD, USER)) + }); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(call)); + + address convexToken = ConvexStakedPositionToken(token).underlying(); + + assertEq(IERC20(convexToken).balanceOf(USER), WAD); + + vm.revertTo(snapshot); + } + } } diff --git a/contracts/test/live/adapters/curve/Live_CurveEquivalenceTest.sol b/contracts/test/live/adapters/curve/Live_CurveEquivalenceTest.sol index 98e738e6..05055646 100644 --- a/contracts/test/live/adapters/curve/Live_CurveEquivalenceTest.sol +++ b/contracts/test/live/adapters/curve/Live_CurveEquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; @@ -16,14 +16,13 @@ import {ICurveV1_2AssetsAdapter} from "../../../../interfaces/curve/ICurveV1_2As import {ICurveV1_3AssetsAdapter} from "../../../../interfaces/curve/ICurveV1_3AssetsAdapter.sol"; import {ICurveV1_4AssetsAdapter} from "../../../../interfaces/curve/ICurveV1_4AssetsAdapter.sol"; import {ICurveV1_StableNGAdapter} from "../../../../interfaces/curve/ICurveV1_StableNGAdapter.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {CurveV1Calls, CurveV1Multicaller} from "../../../multicall/curve/CurveV1_Calls.sol"; @@ -611,10 +610,9 @@ contract Live_CurveEquivalenceTest is LiveTestHelper { } } - function isCurveAdapter(AdapterType aType) internal pure returns (bool) { - return aType == AdapterType.CURVE_V1_2ASSETS || aType == AdapterType.CURVE_V1_3ASSETS - || aType == AdapterType.CURVE_V1_4ASSETS || aType == AdapterType.CURVE_V1_STECRV_POOL - || aType == AdapterType.CURVE_STABLE_NG; + function isCurveAdapter(bytes32 aType) internal pure returns (bool) { + return aType == "AD_CURVE_V1_2ASSETS" || aType == "AD_CURVE_V1_3ASSETS" || aType == "AD_CURVE_V1_4ASSETS" + || aType == "AD_CURVE_V1_STECRV_POOL" || aType == "AD_CURVE_STABLE_NG"; } /// @dev [L-CRVET-1]: Curve adapter and normal account works identically @@ -622,7 +620,7 @@ contract Live_CurveEquivalenceTest is LiveTestHelper { address[] memory adapters = creditConfigurator.allowedAdapters(); for (uint256 i = 0; i < adapters.length; ++i) { - if (!isCurveAdapter(IAdapter(adapters[i])._gearboxAdapterType())) continue; + if (!isCurveAdapter(IAdapter(adapters[i]).contractType())) continue; uint256 snapshot0 = vm.snapshot(); @@ -636,7 +634,7 @@ contract Live_CurveEquivalenceTest is LiveTestHelper { CurvePoolParams memory cpp = CurvePoolParams({ use256: ICurveV1Adapter(adapters[i]).use256(), hasUnderlying: ICurveV1Adapter(adapters[i]).underlying0() != address(0), - isNGPool: IAdapter(adapters[i])._gearboxAdapterType() == AdapterType.CURVE_STABLE_NG, + isNGPool: IAdapter(adapters[i]).contractType() == "ADAPTER::CURVE_STABLE_NG", nCoins: ICurveV1Adapter(adapters[i]).nCoins(), lpToken: ICurveV1Adapter(adapters[i]).token(), lpSupported: creditManager.liquidationThresholds(ICurveV1Adapter(adapters[i]).token()) != 0, diff --git a/contracts/test/live/adapters/erc4626/Live_ERC4626EquivalenceTest.sol b/contracts/test/live/adapters/erc4626/Live_ERC4626EquivalenceTest.sol index 7d017f4b..63a74296 100644 --- a/contracts/test/live/adapters/erc4626/Live_ERC4626EquivalenceTest.sol +++ b/contracts/test/live/adapters/erc4626/Live_ERC4626EquivalenceTest.sol @@ -1,15 +1,14 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {IERC4626Adapter} from "../../../../interfaces/erc4626/IERC4626Adapter.sol"; import {ERC4626_Calls, ERC4626_Multicaller} from "../../../multicall/erc4626/ERC4626_Calls.sol"; @@ -17,7 +16,7 @@ import {ERC4626_Calls, ERC4626_Multicaller} from "../../../multicall/erc4626/ERC import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; // TEST @@ -157,7 +156,7 @@ contract Live_ERC4626EquivalenceTest is LiveTestHelper { address[] memory adapters = creditConfigurator.allowedAdapters(); for (uint256 i = 0; i < adapters.length; ++i) { - if (IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.ERC4626_VAULT) continue; + if (IAdapter(adapters[i]).contractType() != "ADAPTER::ERC4626_VAULT") continue; uint256 snapshot0 = vm.snapshot(); diff --git a/contracts/test/live/adapters/lido/Live_LidoEquivalenceTest.sol b/contracts/test/live/adapters/lido/Live_LidoEquivalenceTest.sol index 82ec013f..2c8714e6 100644 --- a/contracts/test/live/adapters/lido/Live_LidoEquivalenceTest.sol +++ b/contracts/test/live/adapters/lido/Live_LidoEquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; @@ -14,7 +14,7 @@ import {LidoV1_Calls, LidoV1_Multicaller} from "../../../multicall/lido/LidoV1_C import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; // TEST import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; diff --git a/contracts/test/live/adapters/lido/Live_WstETHV1Adapter.t.sol b/contracts/test/live/adapters/lido/Live_WstETHV1Adapter.t.sol index 15f921e0..9e0c69c3 100644 --- a/contracts/test/live/adapters/lido/Live_WstETHV1Adapter.t.sol +++ b/contracts/test/live/adapters/lido/Live_WstETHV1Adapter.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -14,7 +14,7 @@ import {WstETHV1_Calls, WstETHV1_Multicaller} from "../../../multicall/lido/WstE import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; // TEST import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; diff --git a/contracts/test/live/adapters/mellow/Live_MellowVaultEquivalenceTest.t.sol b/contracts/test/live/adapters/mellow/Live_MellowVaultEquivalenceTest.t.sol index ca5f204c..a88ea1b7 100644 --- a/contracts/test/live/adapters/mellow/Live_MellowVaultEquivalenceTest.t.sol +++ b/contracts/test/live/adapters/mellow/Live_MellowVaultEquivalenceTest.t.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; import {IMellowVault} from "../../../../integrations/mellow/IMellowVault.sol"; import {IMellowVaultAdapter} from "../../../../interfaces/mellow/IMellowVaultAdapter.sol"; @@ -15,7 +15,7 @@ import {MellowVault_Calls, MellowVault_Multicaller} from "../../../multicall/mel import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; @@ -133,7 +133,7 @@ contract Live_MellowVaultAdapterTest is LiveTestHelper { address[] memory adapters = creditConfigurator.allowedAdapters(); for (uint256 i = 0; i < adapters.length; ++i) { - if (IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.MELLOW_LRT_VAULT) continue; + if (IAdapter(adapters[i]).contractType() != "ADAPTER::MELLOW_LRT_VAULT") continue; uint256 snapshot0 = vm.snapshot(); diff --git a/contracts/test/live/adapters/pendle/Live_PendleRouterEquivalenceTest.t.sol b/contracts/test/live/adapters/pendle/Live_PendleRouterEquivalenceTest.t.sol index 75c92b5c..2dc42802 100644 --- a/contracts/test/live/adapters/pendle/Live_PendleRouterEquivalenceTest.t.sol +++ b/contracts/test/live/adapters/pendle/Live_PendleRouterEquivalenceTest.t.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import { IPendleRouter, IPendleMarket, @@ -32,7 +31,7 @@ import {PendleRouter_Calls, PendleRouter_Multicaller} from "../../../multicall/p import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; diff --git a/contracts/test/live/adapters/sky/Live_DaiUsdsEquivalenceTest.sol b/contracts/test/live/adapters/sky/Live_DaiUsdsEquivalenceTest.sol new file mode 100644 index 00000000..e761500b --- /dev/null +++ b/contracts/test/live/adapters/sky/Live_DaiUsdsEquivalenceTest.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; + +import {IDaiUsds} from "../../../../integrations/sky/IDaiUsds.sol"; +import {IDaiUsdsAdapter} from "../../../../interfaces/sky/IDaiUsdsAdapter.sol"; +import {DaiUsds_Calls, DaiUsds_Multicaller} from "../../../multicall/sky/DaiUsds_Calls.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; +import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; + +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; +import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; +// TEST +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + +// SUITES +import {LiveTestHelper} from "../../../suites/LiveTestHelper.sol"; +import {BalanceComparator, BalanceBackup} from "../../../helpers/BalanceComparator.sol"; + +contract Live_DaiUsdsEquivalenceTest is LiveTestHelper { + using DaiUsds_Calls for DaiUsds_Multicaller; + using AddressList for address[]; + + string[4] stages = ["after_daiToUsds", "after_daiToUsdsDiff", "after_usdsToDai", "after_usdsToDaiDiff"]; + + string[] _stages; + + function setUp() public { + _setUp(); + + /// @notice Sets comparator for this equivalence test + + uint256 len = stages.length; + _stages = new string[](len); + unchecked { + for (uint256 i; i < len; ++i) { + _stages[i] = stages[i]; + } + } + } + + /// HELPER + + function compareBehavior( + address creditAccount, + address daiUsdsAddress, + uint256 baseUnit, + bool isAdapter, + BalanceComparator comparator + ) internal { + address dai = IDaiUsdsAdapter(daiUsdsAddress).dai(); + address usds = IDaiUsdsAdapter(daiUsdsAddress).usds(); + + if (isAdapter) { + DaiUsds_Multicaller daiUsds = DaiUsds_Multicaller(daiUsdsAddress); + + vm.startPrank(USER); + + creditFacade.multicall( + creditAccount, MultiCallBuilder.build(daiUsds.daiToUsds(creditAccount, 100 * baseUnit)) + ); + comparator.takeSnapshot("after_daiToUsds", creditAccount); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(daiUsds.daiToUsdsDiff(100 * baseUnit))); + comparator.takeSnapshot("after_daiToUsdsDiff", creditAccount); + + creditFacade.multicall( + creditAccount, MultiCallBuilder.build(daiUsds.usdsToDai(creditAccount, 50 * baseUnit)) + ); + comparator.takeSnapshot("after_usdsToDai", creditAccount); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(daiUsds.usdsToDaiDiff(10 * baseUnit))); + comparator.takeSnapshot("after_usdsToDaiDiff", creditAccount); + + vm.stopPrank(); + } else { + IDaiUsds daiUsds = IDaiUsds(daiUsdsAddress); + + vm.startPrank(creditAccount); + + daiUsds.daiToUsds(creditAccount, 100 * baseUnit); + comparator.takeSnapshot("after_daiToUsds", creditAccount); + + uint256 remainingDaiBalance = IERC20(dai).balanceOf(creditAccount); + daiUsds.daiToUsds(creditAccount, remainingDaiBalance - 100 * baseUnit); + comparator.takeSnapshot("after_daiToUsdsDiff", creditAccount); + + daiUsds.usdsToDai(creditAccount, 50 * baseUnit); + comparator.takeSnapshot("after_usdsToDai", creditAccount); + + uint256 remainingUsdsBalance = IERC20(usds).balanceOf(creditAccount); + daiUsds.usdsToDai(creditAccount, remainingUsdsBalance - 10 * baseUnit); + comparator.takeSnapshot("after_usdsToDaiDiff", creditAccount); + + vm.stopPrank(); + } + } + + function openCreditAccountWithDai(address daiUsdsAdapter, uint256 amount) + internal + returns (address creditAccount) + { + vm.prank(USER); + creditAccount = creditFacade.openCreditAccount(USER, MultiCallBuilder.build(), 0); + + address dai = IDaiUsdsAdapter(daiUsdsAdapter).dai(); + tokenTestSuite.mint(dai, creditAccount, amount); + } + + function prepareComparator(address daiUsdsAdapter) internal returns (BalanceComparator comparator) { + address[] memory tokensToTrack = new address[](2); + + tokensToTrack[0] = IDaiUsdsAdapter(daiUsdsAdapter).dai(); + tokensToTrack[1] = IDaiUsdsAdapter(daiUsdsAdapter).usds(); + + uint256[] memory _tokensToTrack = new uint256[](tokensToTrack.length); + + for (uint256 j = 0; j < tokensToTrack.length; ++j) { + _tokensToTrack[j] = tokenTestSuite.tokenIndexes(tokensToTrack[j]); + } + + comparator = new BalanceComparator(_stages, _tokensToTrack, tokenTestSuite); + } + + /// @dev [L-DUSDS-1]: DaiUsds adapters and original contracts work identically + function test_live_DUSDS_01_DaiUsds_adapters_and_original_contracts_are_equivalent() public attachOrLiveTest { + address[] memory adapters = creditConfigurator.allowedAdapters(); + + for (uint256 i = 0; i < adapters.length; ++i) { + if (IAdapter(adapters[i]).contractType() != "ADAPTER::DAI_USDS_EXCHANGE") continue; + + uint256 snapshot0 = vm.snapshot(); + + address dai = IDaiUsdsAdapter(adapters[i]).dai(); + address usds = IDaiUsdsAdapter(adapters[i]).usds(); + + address creditAccount = openCreditAccountWithDai(adapters[i], 3000 * 10 ** IERC20Metadata(dai).decimals()); + + tokenTestSuite.approve(dai, creditAccount, IAdapter(adapters[i]).targetContract()); + tokenTestSuite.approve(usds, creditAccount, IAdapter(adapters[i]).targetContract()); + + uint256 snapshot1 = vm.snapshot(); + + BalanceComparator comparator = prepareComparator(adapters[i]); + + compareBehavior( + creditAccount, + IAdapter(adapters[i]).targetContract(), + 10 ** IERC20Metadata(dai).decimals(), + false, + comparator + ); + + BalanceBackup[] memory savedBalanceSnapshots = comparator.exportSnapshots(creditAccount); + + vm.revertTo(snapshot1); + + comparator = prepareComparator(adapters[i]); + + compareBehavior(creditAccount, adapters[i], 10 ** IERC20Metadata(dai).decimals(), true, comparator); + + comparator.compareAllSnapshots(creditAccount, savedBalanceSnapshots, 0); + + vm.revertTo(snapshot0); + } + } +} diff --git a/contracts/test/live/adapters/sky/Live_StakingRewardsEquivalenceTest.sol b/contracts/test/live/adapters/sky/Live_StakingRewardsEquivalenceTest.sol new file mode 100644 index 00000000..ff42bf4e --- /dev/null +++ b/contracts/test/live/adapters/sky/Live_StakingRewardsEquivalenceTest.sol @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3Multicall.sol"; +import {IStakingRewards} from "../../../../integrations/sky/IStakingRewards.sol"; +import {IStakingRewardsAdapter} from "../../../../interfaces/sky/IStakingRewardsAdapter.sol"; +import { + IPhantomToken, + IPhantomTokenWithdrawer +} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol"; +import {PriceFeedParams} from "@gearbox-protocol/core-v3/contracts/interfaces/IPriceOracleV3.sol"; +import {IPriceFeed} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPriceFeed.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; + +import {StakingRewards_Calls, StakingRewards_Multicaller} from "../../../multicall/sky/StakingRewards_Calls.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; + +import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; +import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; + +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; +import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; + +import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; +// TEST +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + +// SUITES +import {LiveTestHelper} from "../../../suites/LiveTestHelper.sol"; +import {BalanceComparator, BalanceBackup} from "../../../helpers/BalanceComparator.sol"; + +contract Live_StakingRewardsEquivalenceTest is LiveTestHelper { + using AddressList for address[]; + using StakingRewards_Calls for StakingRewards_Multicaller; + + string[5] stages = ["after_stake", "after_stakeDiff", "after_getReward", "after_withdraw", "after_withdrawDiff"]; + + string[] _stages; + + function setUp() public { + _setUp(); + + /// @notice Sets comparator for this equivalence test + uint256 len = stages.length; + _stages = new string[](len); + unchecked { + for (uint256 i; i < len; ++i) { + _stages[i] = stages[i]; + } + } + } + + /// HELPER + + function compareBehavior( + address creditAccount, + address stakingRewardsAddress, + address stakedPhantomToken, + bool isAdapter, + BalanceComparator comparator + ) internal { + if (isAdapter) { + StakingRewards_Multicaller stakingRewards = StakingRewards_Multicaller(stakingRewardsAddress); + + vm.startPrank(USER); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(stakingRewards.stake(WAD))); + comparator.takeSnapshot("after_stake", creditAccount); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(stakingRewards.stakeDiff(WAD))); + comparator.takeSnapshot("after_stakeDiff", creditAccount); + + vm.warp(block.timestamp + 24 * 60 * 60); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(stakingRewards.getReward())); + comparator.takeSnapshot("after_getReward", creditAccount); + + vm.warp(block.timestamp + 24 * 60 * 60); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(stakingRewards.withdraw(WAD))); + comparator.takeSnapshot("after_withdraw", creditAccount); + + vm.warp(block.timestamp + 24 * 60 * 60); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(stakingRewards.withdrawDiff(WAD))); + comparator.takeSnapshot("after_withdrawDiff", creditAccount); + + vm.stopPrank(); + } else { + IStakingRewards stakingRewards = IStakingRewards(stakingRewardsAddress); + + vm.startPrank(creditAccount); + + stakingRewards.stake(WAD); + comparator.takeSnapshot("after_stake", creditAccount); + + uint256 remainingBalance = IERC20(stakingRewards.stakingToken()).balanceOf(creditAccount); + stakingRewards.stake(remainingBalance - WAD); + comparator.takeSnapshot("after_stakeDiff", creditAccount); + + vm.warp(block.timestamp + 24 * 60 * 60); + + stakingRewards.getReward(); + comparator.takeSnapshot("after_getReward", creditAccount); + + vm.warp(block.timestamp + 24 * 60 * 60); + + stakingRewards.withdraw(WAD); + comparator.takeSnapshot("after_withdraw", creditAccount); + + vm.warp(block.timestamp + 24 * 60 * 60); + + remainingBalance = IERC20(stakedPhantomToken).balanceOf(creditAccount); + stakingRewards.withdraw(remainingBalance - WAD); + comparator.takeSnapshot("after_withdrawDiff", creditAccount); + + vm.stopPrank(); + } + } + + function openCreditAccountWithUnderlying(address token, uint256 amount) internal returns (address creditAccount) { + vm.prank(USER); + creditAccount = creditFacade.openCreditAccount(USER, MultiCallBuilder.build(), 0); + + tokenTestSuite.mint(token, creditAccount, amount); + } + + function prepareComparator(address stakingRewardsAdapter) internal returns (BalanceComparator comparator) { + address[] memory tokensToTrack = new address[](3); + + tokensToTrack[0] = IStakingRewardsAdapter(stakingRewardsAdapter).stakingToken(); + tokensToTrack[1] = IStakingRewardsAdapter(stakingRewardsAdapter).rewardsToken(); + tokensToTrack[2] = IStakingRewardsAdapter(stakingRewardsAdapter).stakedPhantomToken(); + + tokensToTrack = tokensToTrack.trim(); + + uint256[] memory _tokensToTrack = new uint256[](tokensToTrack.length); + + for (uint256 j = 0; j < tokensToTrack.length; ++j) { + _tokensToTrack[j] = tokenTestSuite.tokenIndexes(tokensToTrack[j]); + } + + comparator = new BalanceComparator(_stages, _tokensToTrack, tokenTestSuite); + } + + /// @dev [L-STRET-1]: StakingRewards adapters and original contracts work identically + function test_live_STRET_01_StakingRewards_adapters_and_original_contracts_are_equivalent() + public + attachOrLiveTest + { + address[] memory adapters = creditConfigurator.allowedAdapters(); + + for (uint256 i = 0; i < adapters.length; ++i) { + if (IAdapter(adapters[i]).contractType() != "ADAPTER::STAKING_REWARDS") continue; + + uint256 snapshot0 = vm.snapshot(); + + address creditAccount = + openCreditAccountWithUnderlying(IStakingRewardsAdapter(adapters[i]).stakingToken(), 3000 * WAD); + + tokenTestSuite.approve( + IStakingRewardsAdapter(adapters[i]).stakingToken(), + creditAccount, + IAdapter(adapters[i]).targetContract() + ); + + uint256 snapshot1 = vm.snapshot(); + + BalanceComparator comparator = prepareComparator(adapters[i]); + + compareBehavior( + creditAccount, + IAdapter(adapters[i]).targetContract(), + IStakingRewardsAdapter(adapters[i]).stakedPhantomToken(), + false, + comparator + ); + + BalanceBackup[] memory savedBalanceSnapshots = comparator.exportSnapshots(creditAccount); + + vm.revertTo(snapshot1); + + comparator = prepareComparator(adapters[i]); + + compareBehavior( + creditAccount, adapters[i], IStakingRewardsAdapter(adapters[i]).stakedPhantomToken(), true, comparator + ); + + comparator.compareAllSnapshots(creditAccount, savedBalanceSnapshots); + + vm.revertTo(snapshot0); + } + } + + /// @dev [L-STRET-2]: Withdrawals for StakingRewards phantom tokens work correctly + function test_live_STRET_02_StakingRewards_phantom_token_withdrawals_work_correctly() public attachOrLiveTest { + uint256 collateralTokensCount = creditManager.collateralTokensCount(); + + for (uint256 i = 0; i < collateralTokensCount; ++i) { + uint256 snapshot = vm.snapshot(); + + address token = creditManager.getTokenByMask(1 << i); + address adapter; + + try IPhantomToken(token).getPhantomTokenInfo() returns (address target, address) { + adapter = creditManager.contractToAdapter(target); + if (IAdapter(adapter).contractType() != "ADAPTER::STAKING_REWARDS") continue; + } catch { + continue; + } + + if (priceOracle.reservePriceFeeds(token) == address(0)) { + PriceFeedParams memory pfParams = priceOracle.priceFeedParams(token); + vm.prank(Ownable(address(acl)).owner()); + priceOracle.setReservePriceFeed(token, pfParams.priceFeed, pfParams.stalenessPeriod); + } + + address stakingToken = IStakingRewardsAdapter(adapter).stakingToken(); + + address creditAccount = openCreditAccountWithUnderlying(stakingToken, 100 * WAD); + + vm.prank(USER); + creditFacade.multicall( + creditAccount, MultiCallBuilder.build(StakingRewards_Multicaller(adapter).stake(WAD)) + ); + + vm.expectCall(adapter, abi.encodeCall(IPhantomTokenWithdrawer.withdrawPhantomToken, (token, WAD))); + vm.prank(USER); + MultiCall memory call = MultiCall({ + target: address(creditFacade), + callData: abi.encodeCall(ICreditFacadeV3Multicall.withdrawCollateral, (token, WAD, USER)) + }); + + creditFacade.multicall(creditAccount, MultiCallBuilder.build(call)); + + assertEq(IERC20(stakingToken).balanceOf(USER), WAD); + + vm.revertTo(snapshot); + } + } +} diff --git a/contracts/test/live/adapters/uniswap/Live_UniswapV2EquivalenceTest.sol b/contracts/test/live/adapters/uniswap/Live_UniswapV2EquivalenceTest.sol index 4dc9080f..a0329f44 100644 --- a/contracts/test/live/adapters/uniswap/Live_UniswapV2EquivalenceTest.sol +++ b/contracts/test/live/adapters/uniswap/Live_UniswapV2EquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; @@ -11,7 +11,7 @@ import {IUniswapV2Adapter} from "../../../../interfaces/uniswap/IUniswapV2Adapte import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {UniswapV2_Calls, UniswapV2_Multicaller} from "../../../multicall/uniswap/UniswapV2_Calls.sol"; diff --git a/contracts/test/live/adapters/uniswap/Live_UniswapV3EquivalenceTest.sol b/contracts/test/live/adapters/uniswap/Live_UniswapV3EquivalenceTest.sol index eca78d90..e17b03d0 100644 --- a/contracts/test/live/adapters/uniswap/Live_UniswapV3EquivalenceTest.sol +++ b/contracts/test/live/adapters/uniswap/Live_UniswapV3EquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; @@ -11,7 +11,7 @@ import {IUniswapV3Adapter, IUniswapV3AdapterTypes} from "../../../../interfaces/ import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {UniswapV3_Calls, UniswapV3_Multicaller} from "../../../multicall/uniswap/UniswapV3_Calls.sol"; diff --git a/contracts/test/live/adapters/velodrome/Live_VelodromeV2EquivalenceTest.sol b/contracts/test/live/adapters/velodrome/Live_VelodromeV2EquivalenceTest.sol index 645b4d46..f38e96d2 100644 --- a/contracts/test/live/adapters/velodrome/Live_VelodromeV2EquivalenceTest.sol +++ b/contracts/test/live/adapters/velodrome/Live_VelodromeV2EquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; @@ -11,7 +11,7 @@ import {IVelodromeV2RouterAdapter} from "../../../../interfaces/velodrome/IVelod import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import { diff --git a/contracts/test/live/adapters/yearn/Live_YearnEquivalenceTest.sol b/contracts/test/live/adapters/yearn/Live_YearnEquivalenceTest.sol index 24f29dc4..403faf15 100644 --- a/contracts/test/live/adapters/yearn/Live_YearnEquivalenceTest.sol +++ b/contracts/test/live/adapters/yearn/Live_YearnEquivalenceTest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; @@ -11,13 +11,12 @@ import {ICreditFacadeV3Multicall} from "@gearbox-protocol/core-v3/contracts/inte import {IYVault} from "../../../../integrations/yearn/IYVault.sol"; import {IYearnV2Adapter} from "../../../../interfaces/yearn/IYearnV2Adapter.sol"; import {YearnV2_Calls, YearnV2_Multicaller} from "../../../multicall/yearn/YearnV2_Calls.sol"; -import {IAdapter} from "@gearbox-protocol/core-v2/contracts/interfaces/IAdapter.sol"; -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol"; import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {MultiCallBuilder} from "@gearbox-protocol/core-v3/contracts/test/lib/MultiCallBuilder.sol"; import {AddressList} from "@gearbox-protocol/core-v3/contracts/test/lib/AddressList.sol"; // TEST @@ -157,7 +156,7 @@ contract Live_YearnEquivalenceTest is LiveTestHelper { address[] memory adapters = creditConfigurator.allowedAdapters(); for (uint256 i = 0; i < adapters.length; ++i) { - if (IAdapter(adapters[i])._gearboxAdapterType() != AdapterType.YEARN_V2) continue; + if (IAdapter(adapters[i]).contractType() != "ADAPTER::YEARN_V2") continue; uint256 snapshot0 = vm.snapshot(); diff --git a/contracts/test/live/zappers/AllZappers.live.t.sol b/contracts/test/live/zappers/AllZappers.live.t.sol index 774b2761..9e13d1fa 100644 --- a/contracts/test/live/zappers/AllZappers.live.t.sol +++ b/contracts/test/live/zappers/AllZappers.live.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/contracts/test/mocks/credit/CreditManagerLiveMock.sol b/contracts/test/mocks/credit/CreditManagerLiveMock.sol index 20912998..d41b82a5 100644 --- a/contracts/test/mocks/credit/CreditManagerLiveMock.sol +++ b/contracts/test/mocks/credit/CreditManagerLiveMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; // contract CreditManagerLiveMock is CreditManagerV3 { // constructor(address _pool) CreditManagerV3(_pool) {} diff --git a/contracts/test/mocks/credit/CreditManagerMockFactory.sol b/contracts/test/mocks/credit/CreditManagerMockFactory.sol deleted file mode 100644 index cbb14931..00000000 --- a/contracts/test/mocks/credit/CreditManagerMockFactory.sol +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import { - CreditConfiguratorV3, - CreditManagerOpts -} from "@gearbox-protocol/core-v3/contracts/credit/CreditConfiguratorV3.sol"; - -// import {CreditManagerLiveMock} from "./CreditManagerLiveMock.sol"; - -/// @title CreditManagerV3Mock factory -/// @notice Same as `CreditManagerV3Factory` but configures mock credit manager -contract CreditManagerV3MockFactory { -// CreditManagerLiveMock public CreditManagerV3; -// CreditFacadeV3 public creditFacade; -// CreditConfiguratorV3 public CreditConfiguratorV3; -// PoolService public immutable pool; - -// address[] public adapters; - -// constructor(address _pool, CreditManagerOpts memory opts, uint256 salt) -// ContractUpgrader(address(PoolService(_pool).addressProvider())) -// { -// pool = PoolService(_pool); - -// CreditManagerV3 = new CreditManagerLiveMock(_pool); -// creditFacade = new CreditFacadeV3( -// address(creditManager), -// opts.degenNFT, -// opts.blacklistHelper, -// opts.expirable -// ); - -// bytes memory configuratorByteCode = -// abi.encodePacked(type(CreditConfiguratorV3).creationCode, abi.encode(CreditManagerV3, creditFacade, opts)); - -// address CreditConfiguratorV3Addr = getAddress(configuratorByteCode, salt); - -// creditManager.setConfigurator(CreditConfiguratorV3Addr); - -// deploy(configuratorByteCode, salt); - -// CreditConfiguratorV3 = CreditConfiguratorV3(CreditConfiguratorV3Addr); - -// require(address(creditConfigurator.CreditManagerV3()) == address(creditManager), "Incorrect CM"); -// } - -// function getAddress(bytes memory bytecode, uint256 _salt) public view returns (address) { -// bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode))); - -// // NOTE: cast last 20 bytes of hash to address -// return address(uint160(uint256(hash))); -// } - -// function deploy(bytes memory bytecode, uint256 _salt) public payable { -// address addr; - -// /* -// NOTE: How to call create2 - -// create2(v, p, n, s) -// create new contract with code at memory p to p + n -// and send v wei -// and return the new address -// where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n))) -// s = big-endian 256-bit value -// */ -// assembly { -// addr := -// create2( -// callvalue(), // wei sent with current call -// // Actual code starts after skipping the first 32 bytes -// add(bytecode, 0x20), -// mload(bytecode), // Load the size of code contained in the first 32 bytes -// _salt // Salt from function arguments -// ) - -// if iszero(extcodesize(addr)) { revert(0, 0) } -// } -// } - -// /// @dev adds adapters to public array to provide ability for DAO to -// /// check the list before running configure command -// function addAdapters(Adapter[] memory _adapters) external onlyOwner { -// uint256 len = _adapters.length; -// for (uint256 i = 0; i < len;) { -// adapters.push(_adapters[i]); -// unchecked { -// ++i; -// } -// } -// } - -// function _configure() internal override { -// ContractsRegister cr = ContractsRegister(addressProvider.getContractsRegister()); - -// uint256 len = adapters.length; -// for (uint256 i = 0; i < len;) { -// creditConfigurator.allowAdapter(adapters[i].targetContract, adapters[i].adapter); -// unchecked { -// ++i; -// } -// } - -// cr.addCreditManagerV3(address(creditManager)); - -// pool.connectCreditManagerV3(address(creditManager)); - -// _postInstall(); -// } - -// function _postInstall() internal virtual {} -} diff --git a/contracts/test/mocks/credit/CreditManagerV3Mock.sol b/contracts/test/mocks/credit/CreditManagerV3Mock.sol index e7b981cf..985d3d16 100644 --- a/contracts/test/mocks/credit/CreditManagerV3Mock.sol +++ b/contracts/test/mocks/credit/CreditManagerV3Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; interface CreditManagerV3MockEvents { event Approve(address token, uint256 amount); @@ -9,7 +9,7 @@ interface CreditManagerV3MockEvents { } contract CreditManagerV3Mock is CreditManagerV3MockEvents { - address public addressProvider; + address public pool; address public creditFacade; address public creditConfigurator; @@ -18,8 +18,8 @@ contract CreditManagerV3Mock is CreditManagerV3MockEvents { bytes _result; - constructor(address _addressProvider, address _creditFacade, address _creditConfigurator) { - addressProvider = _addressProvider; + constructor(address _pool, address _creditFacade, address _creditConfigurator) { + pool = _pool; creditFacade = _creditFacade; creditConfigurator = _creditConfigurator; } diff --git a/contracts/test/mocks/integrations/aave/ATokenMock.sol b/contracts/test/mocks/integrations/aave/ATokenMock.sol index eeb8b526..2ec6251d 100644 --- a/contracts/test/mocks/integrations/aave/ATokenMock.sol +++ b/contracts/test/mocks/integrations/aave/ATokenMock.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {IAToken} from "../../../../integrations/aave/IAToken.sol"; import {ILendingPool} from "../../../../integrations/aave/ILendingPool.sol"; diff --git a/contracts/test/mocks/integrations/aave/LendingPoolMock.sol b/contracts/test/mocks/integrations/aave/LendingPoolMock.sol index 1cd88f38..13cdf109 100644 --- a/contracts/test/mocks/integrations/aave/LendingPoolMock.sol +++ b/contracts/test/mocks/integrations/aave/LendingPoolMock.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {IAToken} from "../../../../integrations/aave/IAToken.sol"; import {DataTypes} from "../../../../integrations/aave/DataTypes.sol"; diff --git a/contracts/test/mocks/integrations/balancer/VaultMock.sol b/contracts/test/mocks/integrations/balancer/VaultMock.sol index 7c532738..4242423f 100644 --- a/contracts/test/mocks/integrations/balancer/VaultMock.sol +++ b/contracts/test/mocks/integrations/balancer/VaultMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IAsset, PoolSpecialization} from "../../../../integrations/balancer/IBalancerV2Vault.sol"; diff --git a/contracts/test/mocks/integrations/compound/CErc20Mock.sol b/contracts/test/mocks/integrations/compound/CErc20Mock.sol index 3cc34ff6..701a8dab 100644 --- a/contracts/test/mocks/integrations/compound/CErc20Mock.sol +++ b/contracts/test/mocks/integrations/compound/CErc20Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/contracts/test/mocks/integrations/compound/CEtherMock.sol b/contracts/test/mocks/integrations/compound/CEtherMock.sol index 84a06f49..9e3c9683 100644 --- a/contracts/test/mocks/integrations/compound/CEtherMock.sol +++ b/contracts/test/mocks/integrations/compound/CEtherMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; diff --git a/contracts/test/mocks/integrations/compound/CTokenMockBase.sol b/contracts/test/mocks/integrations/compound/CTokenMockBase.sol index 56342620..e9768829 100644 --- a/contracts/test/mocks/integrations/compound/CTokenMockBase.sol +++ b/contracts/test/mocks/integrations/compound/CTokenMockBase.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {WAD} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; +import {WAD} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; import {ICToken} from "../../../../integrations/compound/ICToken.sol"; diff --git a/contracts/test/mocks/integrations/convex/BaseRewardPoolMock.sol b/contracts/test/mocks/integrations/convex/BaseRewardPoolMock.sol index 760ee2fd..c9c359b8 100644 --- a/contracts/test/mocks/integrations/convex/BaseRewardPoolMock.sol +++ b/contracts/test/mocks/integrations/convex/BaseRewardPoolMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; contract BaseRewardPoolMock { uint256 public pid; diff --git a/contracts/test/mocks/integrations/convex/BoosterMock.sol b/contracts/test/mocks/integrations/convex/BoosterMock.sol index 1ee37044..34e1dc62 100644 --- a/contracts/test/mocks/integrations/convex/BoosterMock.sol +++ b/contracts/test/mocks/integrations/convex/BoosterMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IBooster} from "../../../../integrations/convex/IBooster.sol"; diff --git a/contracts/test/mocks/integrations/convex/ExtraRewardWrapperMock.sol b/contracts/test/mocks/integrations/convex/ExtraRewardWrapperMock.sol index 187b9d9d..acc4e51a 100644 --- a/contracts/test/mocks/integrations/convex/ExtraRewardWrapperMock.sol +++ b/contracts/test/mocks/integrations/convex/ExtraRewardWrapperMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; contract ExtraRewardWrapperMock { address public token; diff --git a/contracts/test/mocks/integrations/convex/RewardsMock.sol b/contracts/test/mocks/integrations/convex/RewardsMock.sol index a6829a48..f9617022 100644 --- a/contracts/test/mocks/integrations/convex/RewardsMock.sol +++ b/contracts/test/mocks/integrations/convex/RewardsMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; contract RewardsMock { address public rewardToken; diff --git a/contracts/test/mocks/integrations/curve/PoolMock.sol b/contracts/test/mocks/integrations/curve/PoolMock.sol index 13969588..6bc911a3 100644 --- a/contracts/test/mocks/integrations/curve/PoolMock.sol +++ b/contracts/test/mocks/integrations/curve/PoolMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; enum PoolType { Stable, diff --git a/contracts/test/mocks/pool/PoolV3Mock.sol b/contracts/test/mocks/pool/PoolV3Mock.sol index ea2d0d42..df8ed6e0 100644 --- a/contracts/test/mocks/pool/PoolV3Mock.sol +++ b/contracts/test/mocks/pool/PoolV3Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; contract PoolV3Mock { event Deposit(uint256 assets, uint256 shares, address receiver); diff --git a/contracts/test/mocks/token/cERC20Mock.sol b/contracts/test/mocks/token/cERC20Mock.sol index 61f39487..9b9c128e 100644 --- a/contracts/test/mocks/token/cERC20Mock.sol +++ b/contracts/test/mocks/token/cERC20Mock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/contracts/test/multicall/aave/AaveV2_LendingPoolCalls.sol b/contracts/test/multicall/aave/AaveV2_LendingPoolCalls.sol deleted file mode 100644 index 4f1d8b1e..00000000 --- a/contracts/test/multicall/aave/AaveV2_LendingPoolCalls.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; - -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; - -import {IAaveV2_LendingPoolAdapter} from "../../../interfaces/aave/IAaveV2_LendingPoolAdapter.sol"; - -interface AaveV2_LendingPoolMulticaller {} - -library AaveV2_LendingPoolCalls { - function deposit(AaveV2_LendingPoolMulticaller c, address asset, uint256 amount, address, uint16) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_LendingPoolAdapter.deposit, (asset, amount, address(0), 0)) - }); - } - - function depositDiff(AaveV2_LendingPoolMulticaller c, address asset, uint256 leftoverAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_LendingPoolAdapter.depositDiff, (asset, leftoverAmount)) - }); - } - - function withdraw(AaveV2_LendingPoolMulticaller c, address asset, uint256 amount, address) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_LendingPoolAdapter.withdraw, (asset, amount, address(0))) - }); - } - - function withdrawDiff(AaveV2_LendingPoolMulticaller c, address asset, uint256 leftoverAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_LendingPoolAdapter.withdrawDiff, (asset, leftoverAmount)) - }); - } -} diff --git a/contracts/test/multicall/aave/AaveV2_WrappedATokenCalls.sol b/contracts/test/multicall/aave/AaveV2_WrappedATokenCalls.sol deleted file mode 100644 index 0e8aacce..00000000 --- a/contracts/test/multicall/aave/AaveV2_WrappedATokenCalls.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; - -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; - -import {IAaveV2_WrappedATokenAdapter} from "../../../interfaces/aave/IAaveV2_WrappedATokenAdapter.sol"; - -interface AaveV2_WrappedATokenMulticaller {} - -library AaveV2_WrappedATokenCalls { - function deposit(AaveV2_WrappedATokenMulticaller c, uint256 assets) internal pure returns (MultiCall memory) { - return MultiCall({target: address(c), callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.deposit, (assets))}); - } - - function depositDiff(AaveV2_WrappedATokenMulticaller c, uint256 leftoverAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.depositDiff, (leftoverAmount)) - }); - } - - function depositUnderlying(AaveV2_WrappedATokenMulticaller c, uint256 assets) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.depositUnderlying, (assets)) - }); - } - - function depositDiffUnderlying(AaveV2_WrappedATokenMulticaller c, uint256 leftoverAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.depositDiffUnderlying, (leftoverAmount)) - }); - } - - function withdraw(AaveV2_WrappedATokenMulticaller c, uint256 shares) internal pure returns (MultiCall memory) { - return - MultiCall({target: address(c), callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.withdraw, (shares))}); - } - - function withdrawDiff(AaveV2_WrappedATokenMulticaller c, uint256 leftoverAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.withdrawDiff, (leftoverAmount)) - }); - } - - function withdrawUnderlying(AaveV2_WrappedATokenMulticaller c, uint256 shares) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.withdrawUnderlying, (shares)) - }); - } - - function withdrawDiffUnderlying(AaveV2_WrappedATokenMulticaller c, uint256 leftoverAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(IAaveV2_WrappedATokenAdapter.withdrawDiffUnderlying, (leftoverAmount)) - }); - } -} diff --git a/contracts/test/multicall/balancer/BalancerV2_Calls.sol b/contracts/test/multicall/balancer/BalancerV2_Calls.sol index 7772e96c..f8c72ffd 100644 --- a/contracts/test/multicall/balancer/BalancerV2_Calls.sol +++ b/contracts/test/multicall/balancer/BalancerV2_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import { IAsset, @@ -97,7 +97,7 @@ library BalancerV2_Calls { target: address(c), callData: abi.encodeCall( IBalancerV2VaultAdapter.joinPoolSingleAssetDiff, (poolId, assetIn, leftoverAmount, minRateRAY) - ) + ) }); } @@ -125,7 +125,7 @@ library BalancerV2_Calls { target: address(c), callData: abi.encodeCall( IBalancerV2VaultAdapter.exitPoolSingleAsset, (poolId, assetOut, amountIn, minAmountOut) - ) + ) }); } @@ -140,7 +140,7 @@ library BalancerV2_Calls { target: address(c), callData: abi.encodeCall( IBalancerV2VaultAdapter.exitPoolSingleAssetDiff, (poolId, assetOut, leftoverAmount, minRateRAY) - ) + ) }); } } diff --git a/contracts/test/multicall/balancer/BalancerV3Router_Calls.sol b/contracts/test/multicall/balancer/BalancerV3Router_Calls.sol index b81016e9..960bb744 100644 --- a/contracts/test/multicall/balancer/BalancerV3Router_Calls.sol +++ b/contracts/test/multicall/balancer/BalancerV3Router_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024 -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IBalancerV3RouterAdapter} from "../../../interfaces/balancer/IBalancerV3RouterAdapter.sol"; diff --git a/contracts/test/multicall/camelot/CamelotV3_Calls.sol b/contracts/test/multicall/camelot/CamelotV3_Calls.sol index 08771d01..f1c6174d 100644 --- a/contracts/test/multicall/camelot/CamelotV3_Calls.sol +++ b/contracts/test/multicall/camelot/CamelotV3_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICamelotV3Router} from "../../../integrations/camelot/ICamelotV3Router.sol"; import {ICamelotV3Adapter} from "../../../interfaces/camelot/ICamelotV3Adapter.sol"; diff --git a/contracts/test/multicall/compound/CompoundV2_Calls.sol b/contracts/test/multicall/compound/CompoundV2_Calls.sol deleted file mode 100644 index 0aa1aec7..00000000 --- a/contracts/test/multicall/compound/CompoundV2_Calls.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: MIT -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; - -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; - -import {ICompoundV2_CTokenAdapter} from "../../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; - -interface CompoundV2_Multicaller {} - -library CompoundV2_Calls { - function mint(CompoundV2_Multicaller c, uint256 mintAmount) internal pure returns (MultiCall memory) { - return MultiCall({target: address(c), callData: abi.encodeCall(ICompoundV2_CTokenAdapter.mint, (mintAmount))}); - } - - function mintDiff(CompoundV2_Multicaller c, uint256 leftoverAmount) internal pure returns (MultiCall memory) { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(ICompoundV2_CTokenAdapter.mintDiff, (leftoverAmount)) - }); - } - - function redeem(CompoundV2_Multicaller c, uint256 redeemTokens) internal pure returns (MultiCall memory) { - return - MultiCall({target: address(c), callData: abi.encodeCall(ICompoundV2_CTokenAdapter.redeem, (redeemTokens))}); - } - - function redeemDiff(CompoundV2_Multicaller c, uint256 leftoverAmount) internal pure returns (MultiCall memory) { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(ICompoundV2_CTokenAdapter.redeemDiff, (leftoverAmount)) - }); - } - - function redeemUnderlying(CompoundV2_Multicaller c, uint256 redeemAmount) - internal - pure - returns (MultiCall memory) - { - return MultiCall({ - target: address(c), - callData: abi.encodeCall(ICompoundV2_CTokenAdapter.redeemUnderlying, (redeemAmount)) - }); - } -} diff --git a/contracts/test/multicall/convex/ConvexV1_BaseRewardPoolCalls.sol b/contracts/test/multicall/convex/ConvexV1_BaseRewardPoolCalls.sol index 7e1019bb..35b0f649 100644 --- a/contracts/test/multicall/convex/ConvexV1_BaseRewardPoolCalls.sol +++ b/contracts/test/multicall/convex/ConvexV1_BaseRewardPoolCalls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IConvexV1BaseRewardPoolAdapter} from "../../../interfaces/convex/IConvexV1BaseRewardPoolAdapter.sol"; diff --git a/contracts/test/multicall/convex/ConvexV1_BoosterCalls.sol b/contracts/test/multicall/convex/ConvexV1_BoosterCalls.sol index ce2da574..49f2d3b6 100644 --- a/contracts/test/multicall/convex/ConvexV1_BoosterCalls.sol +++ b/contracts/test/multicall/convex/ConvexV1_BoosterCalls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IConvexV1BoosterAdapter} from "../../../interfaces/convex/IConvexV1BoosterAdapter.sol"; diff --git a/contracts/test/multicall/curve/CurveV1_Calls.sol b/contracts/test/multicall/curve/CurveV1_Calls.sol index f90788dc..39e876dd 100644 --- a/contracts/test/multicall/curve/CurveV1_Calls.sol +++ b/contracts/test/multicall/curve/CurveV1_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ICurveV1Adapter} from "../../../interfaces/curve/ICurveV1Adapter.sol"; import {ICurveV1_2AssetsAdapter} from "../../../interfaces/curve/ICurveV1_2AssetsAdapter.sol"; @@ -45,7 +45,7 @@ library CurveV1Calls { target: address(c), callData: abi.encodeWithSignature( "exchange_diff(uint256,uint256,uint256,uint256)", i, j, leftoverAmount, rateMinRAY - ) + ) }); } @@ -82,7 +82,7 @@ library CurveV1Calls { target: address(c), callData: abi.encodeWithSignature( "exchange_diff_underlying(uint256,uint256,uint256,uint256)", i, j, leftoverAmount, rateMinRAY - ) + ) }); } @@ -150,7 +150,7 @@ library CurveV1Calls { target: address(c), callData: abi.encodeWithSignature( "add_diff_liquidity_one_coin(uint256,uint256,uint256)", leftoverAmount, i, rateMinRAY - ) + ) }); } @@ -207,7 +207,7 @@ library CurveV1Calls { target: address(c), callData: abi.encodeWithSignature( "remove_liquidity_one_coin(uint256,int128,uint256)", token_amount, i, min_amount - ) + ) }); } @@ -220,7 +220,7 @@ library CurveV1Calls { target: address(c), callData: abi.encodeWithSignature( "remove_liquidity_one_coin(uint256,uint256,uint256)", token_amount, i, min_amount - ) + ) }); } @@ -233,7 +233,7 @@ library CurveV1Calls { target: address(c), callData: abi.encodeWithSignature( "remove_diff_liquidity_one_coin(uint256,uint256,uint256)", leftoverAmount, i, rateMinRAY - ) + ) }); } diff --git a/contracts/test/multicall/erc4626/ERC4626_Calls.sol b/contracts/test/multicall/erc4626/ERC4626_Calls.sol index 908264b9..76b01561 100644 --- a/contracts/test/multicall/erc4626/ERC4626_Calls.sol +++ b/contracts/test/multicall/erc4626/ERC4626_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IERC4626Adapter} from "../../../interfaces/erc4626/IERC4626Adapter.sol"; diff --git a/contracts/test/multicall/lido/LidoV1_Calls.sol b/contracts/test/multicall/lido/LidoV1_Calls.sol index 5c738ef9..6d2671e3 100644 --- a/contracts/test/multicall/lido/LidoV1_Calls.sol +++ b/contracts/test/multicall/lido/LidoV1_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ILidoV1Adapter} from "../../../interfaces/lido/ILidoV1Adapter.sol"; diff --git a/contracts/test/multicall/lido/WstETHV1_Calls.sol b/contracts/test/multicall/lido/WstETHV1_Calls.sol index 2744b8dc..1dbca723 100644 --- a/contracts/test/multicall/lido/WstETHV1_Calls.sol +++ b/contracts/test/multicall/lido/WstETHV1_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IwstETHV1Adapter} from "../../../interfaces/lido/IwstETHV1Adapter.sol"; diff --git a/contracts/test/multicall/mellow/MellowVault_Calls.sol b/contracts/test/multicall/mellow/MellowVault_Calls.sol index afcd4be1..25fe413a 100644 --- a/contracts/test/multicall/mellow/MellowVault_Calls.sol +++ b/contracts/test/multicall/mellow/MellowVault_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IMellowVaultAdapter} from "../../../interfaces/mellow/IMellowVaultAdapter.sol"; diff --git a/contracts/test/multicall/pendle/PendleRouter_Calls.sol b/contracts/test/multicall/pendle/PendleRouter_Calls.sol index 1a608edb..6cfe7f7d 100644 --- a/contracts/test/multicall/pendle/PendleRouter_Calls.sol +++ b/contracts/test/multicall/pendle/PendleRouter_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import { IPendleRouterAdapter, TokenDiffInput, TokenDiffOutput diff --git a/contracts/test/multicall/sky/DaiUsds_Calls.sol b/contracts/test/multicall/sky/DaiUsds_Calls.sol index 75c81e5d..9302e388 100644 --- a/contracts/test/multicall/sky/DaiUsds_Calls.sol +++ b/contracts/test/multicall/sky/DaiUsds_Calls.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024 -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IDaiUsdsAdapter} from "../../../interfaces/sky/IDaiUsdsAdapter.sol"; diff --git a/contracts/test/multicall/sky/StakingRewards_Calls.sol b/contracts/test/multicall/sky/StakingRewards_Calls.sol index 53923f7f..956a9dad 100644 --- a/contracts/test/multicall/sky/StakingRewards_Calls.sol +++ b/contracts/test/multicall/sky/StakingRewards_Calls.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024 -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IStakingRewardsAdapter} from "../../../interfaces/sky/IStakingRewardsAdapter.sol"; diff --git a/contracts/test/multicall/uniswap/UniswapV2_Calls.sol b/contracts/test/multicall/uniswap/UniswapV2_Calls.sol index 806c4680..98ad0e93 100644 --- a/contracts/test/multicall/uniswap/UniswapV2_Calls.sol +++ b/contracts/test/multicall/uniswap/UniswapV2_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IUniswapV2Adapter} from "../../../interfaces/uniswap/IUniswapV2Adapter.sol"; interface UniswapV2_Multicaller {} @@ -21,7 +21,7 @@ library UniswapV2_Calls { target: address(c), callData: abi.encodeCall( IUniswapV2Adapter.swapTokensForExactTokens, (amountOut, amountInMax, path, address(0), deadline) - ) + ) }); } @@ -37,7 +37,7 @@ library UniswapV2_Calls { target: address(c), callData: abi.encodeCall( IUniswapV2Adapter.swapExactTokensForTokens, (amountIn, amountOutMin, path, address(0), deadline) - ) + ) }); } @@ -52,7 +52,7 @@ library UniswapV2_Calls { target: address(c), callData: abi.encodeCall( IUniswapV2Adapter.swapDiffTokensForTokens, (leftoverAmount, rateMinRAY, path, deadline) - ) + ) }); } } diff --git a/contracts/test/multicall/uniswap/UniswapV3_Calls.sol b/contracts/test/multicall/uniswap/UniswapV3_Calls.sol index 1f08544b..8894285b 100644 --- a/contracts/test/multicall/uniswap/UniswapV3_Calls.sol +++ b/contracts/test/multicall/uniswap/UniswapV3_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {ISwapRouter} from "../../../integrations/uniswap/IUniswapV3.sol"; import {IUniswapV3Adapter} from "../../../interfaces/uniswap/IUniswapV3Adapter.sol"; diff --git a/contracts/test/multicall/velodrome/VelodromeV2Router_Calls.sol b/contracts/test/multicall/velodrome/VelodromeV2Router_Calls.sol index 901094b5..03ca18ee 100644 --- a/contracts/test/multicall/velodrome/VelodromeV2Router_Calls.sol +++ b/contracts/test/multicall/velodrome/VelodromeV2Router_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; import {IVelodromeV2RouterAdapter} from "../../../interfaces/velodrome/IVelodromeV2RouterAdapter.sol"; import {Route} from "../../../integrations/velodrome/IVelodromeV2Router.sol"; @@ -22,7 +22,7 @@ library VelodromeV2Router_Calls { target: address(c), callData: abi.encodeCall( IVelodromeV2RouterAdapter.swapExactTokensForTokens, (amountIn, amountOutMin, routes, address(0), deadline) - ) + ) }); } @@ -37,7 +37,7 @@ library VelodromeV2Router_Calls { target: address(c), callData: abi.encodeCall( IVelodromeV2RouterAdapter.swapDiffTokensForTokens, (leftoverAmount, rateMinRAY, routes, deadline) - ) + ) }); } } diff --git a/contracts/test/multicall/yearn/YearnV2_Calls.sol b/contracts/test/multicall/yearn/YearnV2_Calls.sol index 5a2a0c26..3003952e 100644 --- a/contracts/test/multicall/yearn/YearnV2_Calls.sol +++ b/contracts/test/multicall/yearn/YearnV2_Calls.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023 -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024 +pragma solidity ^0.8.23; -import {MultiCall} from "@gearbox-protocol/core-v2/contracts/libraries/MultiCall.sol"; +import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; interface YearnV2_Multicaller {} diff --git a/contracts/test/suites/AdapterDeployer.sol b/contracts/test/suites/AdapterDeployer.sol index 89427403..145cce7c 100644 --- a/contracts/test/suites/AdapterDeployer.sol +++ b/contracts/test/suites/AdapterDeployer.sol @@ -13,6 +13,7 @@ import {AdapterData} from "@gearbox-protocol/sdk-gov/contracts/AdapterData.sol"; import {SupportedContracts, Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +import {ICurvePool} from "../../integrations/curve/ICurvePool.sol"; // SIMPLE ADAPTERS import {UniswapV2Adapter} from "../../adapters/uniswap/UniswapV2.sol"; @@ -32,12 +33,6 @@ import {CurveV1AdapterDeposit} from "../../adapters/curve/CurveV1_DepositZap.sol import {ConvexV1BaseRewardPoolAdapter} from "../../adapters/convex/ConvexV1_BaseRewardPool.sol"; -import {CompoundV2_CErc20Adapter} from "../../adapters/compound/CompoundV2_CErc20Adapter.sol"; -import {CompoundV2_CEtherAdapter} from "../../adapters/compound/CompoundV2_CEtherAdapter.sol"; - -import {AaveV2_LendingPoolAdapter} from "../../adapters/aave/AaveV2_LendingPoolAdapter.sol"; -import {AaveV2_WrappedATokenAdapter} from "../../adapters/aave/AaveV2_WrappedATokenAdapter.sol"; - import {ERC4626Adapter} from "../../adapters/erc4626/ERC4626Adapter.sol"; import {BalancerV2VaultAdapter} from "../../adapters/balancer/BalancerV2VaultAdapter.sol"; @@ -128,16 +123,8 @@ contract AdapterDeployer is AdapterData, Test { } else if (at == AdapterType.LIDO_WSTETH_V1) { adapter = address(new WstETHV1Adapter(address(creditManager), tokenTestSuite.addressOf(TOKEN_wstETH))); - } else if (at == AdapterType.COMPOUND_V2_CERC20) { - adapter = address(new CompoundV2_CErc20Adapter(address(creditManager), targetContract)); - } else if (at == AdapterType.COMPOUND_V2_CETHER) { - adapter = address(new CompoundV2_CEtherAdapter(address(creditManager), targetContract)); - } else if (at == AdapterType.AAVE_V2_LENDING_POOL) { - adapter = address(new AaveV2_LendingPoolAdapter(address(creditManager), targetContract)); - } else if (at == AdapterType.AAVE_V2_WRAPPED_ATOKEN) { - adapter = address(new AaveV2_WrappedATokenAdapter(address(creditManager), targetContract)); } else if (at == AdapterType.ERC4626_VAULT) { - adapter = address(new ERC4626Adapter(address(creditManager), targetContract)); + adapter = address(new ERC4626Adapter(address(creditManager), targetContract, address(0))); } else if (at == AdapterType.BALANCER_VAULT) { adapter = address(new BalancerV2VaultAdapter(address(creditManager), targetContract)); } else if (at == AdapterType.VELODROME_V2_ROUTER) { @@ -161,6 +148,13 @@ contract AdapterDeployer is AdapterData, Test { if (cnt == curveAdapters[i].targetContract) { AdapterType at = curveAdapters[i].adapterType; targetContract = supportedContracts.addressOf(cnt); + bool use256; + + try ICurvePool(targetContract).mid_fee() returns (uint256) { + use256 = true; + } catch { + use256 = false; + } if (at == AdapterType.CURVE_V1_2ASSETS) { adapter = address( @@ -168,7 +162,8 @@ contract AdapterDeployer is AdapterData, Test { address(creditManager), targetContract, tokenTestSuite.addressOf(curveAdapters[i].lpToken), - supportedContracts.addressOf(curveAdapters[i].basePool) + supportedContracts.addressOf(curveAdapters[i].basePool), + use256 ) ); } else if (at == AdapterType.CURVE_V1_3ASSETS) { @@ -177,7 +172,8 @@ contract AdapterDeployer is AdapterData, Test { address(creditManager), targetContract, tokenTestSuite.addressOf(curveAdapters[i].lpToken), - address(0) + address(0), + use256 ) ); } else if (at == AdapterType.CURVE_V1_4ASSETS) { @@ -186,7 +182,8 @@ contract AdapterDeployer is AdapterData, Test { address(creditManager), targetContract, tokenTestSuite.addressOf(curveAdapters[i].lpToken), - address(0) + address(0), + use256 ) ); } else if (at == AdapterType.CURVE_STABLE_NG) { @@ -195,7 +192,8 @@ contract AdapterDeployer is AdapterData, Test { address(creditManager), targetContract, tokenTestSuite.addressOf(curveAdapters[i].lpToken), - address(0) + address(0), + use256 ) ); } @@ -257,7 +255,8 @@ contract AdapterDeployer is AdapterData, Test { new StakingRewardsAdapter( address(creditManager), targetContract, - tokenTestSuite.addressOf(stakingRewardsAdapters[i].stakedToken) + tokenTestSuite.addressOf(stakingRewardsAdapters[i].stakedToken), + 0 ) ); return adapter; diff --git a/contracts/test/suites/LiveTestHelper.sol b/contracts/test/suites/LiveTestHelper.sol index bb56fa78..bd120fbe 100644 --- a/contracts/test/suites/LiveTestHelper.sol +++ b/contracts/test/suites/LiveTestHelper.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. +// (c) Gearbox Foundation, 2024. pragma solidity ^0.8.10; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol"; -import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol"; -import {DegenNFTV2} from "@gearbox-protocol/core-v2/contracts/tokens/DegenNFTV2.sol"; +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {DegenNFTMock} from "@gearbox-protocol/core-v3/contracts/test/mocks/token/DegenNFTMock.sol"; import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {SupportedContracts, Contracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; @@ -19,17 +19,14 @@ import { UniswapV3Pair, GenericSwapPair, VelodromeV2Pool, - PendlePair, - MellowUnderlyingConfig + MellowUnderlyingConfig, + PendlePair } from "@gearbox-protocol/core-v3/contracts/test/interfaces/ICreditConfig.sol"; import {PriceFeedDeployer} from "@gearbox-protocol/oracles-v3/contracts/test/suites/PriceFeedDeployer.sol"; import {IntegrationTestHelper} from "@gearbox-protocol/core-v3/contracts/test/helpers/IntegrationTestHelper.sol"; import {AdapterDeployer} from "./AdapterDeployer.sol"; -import {CONFIG_MAINNET_DAI_TEST_V3} from "../config/TEST_DAI_Mainnet_config.sol"; -import {CONFIG_MAINNET_WETH_TEST_V3} from "../config/TEST_WETH_Mainnet_config.sol"; - import {IConvexV1BoosterAdapter} from "../../interfaces/convex/IConvexV1BoosterAdapter.sol"; import {BalancerV2VaultAdapter} from "../../adapters/balancer/BalancerV2VaultAdapter.sol"; import {UniswapV2Adapter} from "../../adapters/uniswap/UniswapV2.sol"; @@ -38,6 +35,7 @@ import {VelodromeV2RouterAdapter} from "../../adapters/velodrome/VelodromeV2Rout import {CamelotV3Adapter} from "../../adapters/camelot/CamelotV3Adapter.sol"; import {PendleRouterAdapter} from "../../adapters/pendle/PendleRouterAdapter.sol"; import {MellowVaultAdapter} from "../../adapters/mellow/MellowVaultAdapter.sol"; + import {PoolStatus} from "../../interfaces/balancer/IBalancerV2VaultAdapter.sol"; import {UniswapV2PairStatus} from "../../interfaces/uniswap/IUniswapV2Adapter.sol"; import {UniswapV3PoolStatus} from "../../interfaces/uniswap/IUniswapV3Adapter.sol"; @@ -51,10 +49,7 @@ import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; import "forge-std/console.sol"; contract LiveTestHelper is IntegrationTestHelper { - constructor() { - addDeployConfig(new CONFIG_MAINNET_WETH_TEST_V3()); - addDeployConfig(new CONFIG_MAINNET_DAI_TEST_V3()); - } + constructor() {} SupportedContracts public supportedContracts; @@ -73,16 +68,7 @@ contract LiveTestHelper is IntegrationTestHelper { modifier attachOrLiveTest() { if (chainId != 1337 && chainId != 31337) { - try vm.envAddress("ATTACH_ADDRESS_PROVIDER") returns (address) { - _attachCore(); - supportedContracts = new SupportedContracts(chainId); - - address creditManagerToAttach; - - try vm.envAddress("ATTACH_CREDIT_MANAGER") returns (address val) { - creditManagerToAttach = val; - } catch {} - + try vm.envAddress("ATTACH_CREDIT_MANAGER") returns (address creditManagerToAttach) { if (creditManagerToAttach != address(0)) { if (_checkFunctionalSuite(creditManagerToAttach)) { _attachCreditManager(creditManagerToAttach); @@ -91,8 +77,13 @@ contract LiveTestHelper is IntegrationTestHelper { } else { console.log("Pool or facade for attached CM paused, skipping: %s", creditManagerToAttach); } - } else { - address[] memory cms = cr.getCreditManagers(); + } + } catch { + try vm.envAddress("ATTACH_POOL") returns (address poolToAttach) { + _attachPool(poolToAttach); + supportedContracts = new SupportedContracts(chainId); + + address[] memory cms = pool.creditManagers(); uint256 len = cms.length; for (uint256 i = 0; i < len; ++i) { if (IVersion(cms[i]).version() >= 3_00) { @@ -107,20 +98,25 @@ contract LiveTestHelper is IntegrationTestHelper { vm.revertTo(snapshot); } } - } - } catch { - try vm.envString("LIVE_TEST_CONFIG") returns (string memory id) { - _setupLiveCreditTest(id); + console.log("Successfully ran tests on attached pool: %s", poolToAttach); + } catch { + try vm.envString("LIVE_TEST_CONFIG") returns (string memory id) { + _setupLiveCreditTest(id); - vm.prank(address(gauge)); - poolQuotaKeeper.updateRates(); + vm.prank(address(gauge)); + poolQuotaKeeper.updateRates(); - for (uint256 i = 0; i < creditManagers.length; ++i) { - _attachCreditManager(address(creditManagers[i])); - _; + for (uint256 i = 0; i < creditManagers.length; ++i) { + uint256 s = vm.snapshot(); + _attachCreditManager(address(creditManagers[i])); + _; + vm.revertTo(s); + } + } catch { + revert( + "Live/attach tests require the attached pool/CM address or live test config. Please set one of the env variables: ATTACH_POOL or ATTACH_CREDIT_MANAGER or LIVE_TEST_CONFIG" + ); } - } catch { - revert("Neither attach AP nor live test config was defined."); } } } @@ -131,7 +127,7 @@ contract LiveTestHelper is IntegrationTestHelper { supportedContracts = new SupportedContracts(chainId); PriceFeedDeployer priceFeedDeployer = - new PriceFeedDeployer(chainId, address(addressProvider), tokenTestSuite, supportedContracts); + new PriceFeedDeployer(chainId, address(acl), tokenTestSuite, supportedContracts); priceFeedDeployer.addPriceFeeds(address(priceOracle)); @@ -151,10 +147,10 @@ contract LiveTestHelper is IntegrationTestHelper { address degenNFT = ICreditFacadeV3(ICreditManagerV3(creditManagers[i]).creditFacade()).degenNFT(); if (degenNFT != address(0)) { - address minter = DegenNFTV2(degenNFT).minter(); + address minter = DegenNFTMock(degenNFT).minter(); vm.prank(minter); - DegenNFTV2(degenNFT).mint(USER, 1000); + DegenNFTMock(degenNFT).mint(USER, 1000); } } } @@ -167,14 +163,14 @@ contract LiveTestHelper is IntegrationTestHelper { if (boosterAdapter != address(0)) { vm.prank(CONFIGURATOR); - IConvexV1BoosterAdapter(boosterAdapter).updateStakedPhantomTokensMap(); + IConvexV1BoosterAdapter(boosterAdapter).updateSupportedPids(); } boosterAdapter = getAdapter(creditManager, Contracts.AURA_BOOSTER); if (boosterAdapter != address(0)) { vm.prank(CONFIGURATOR); - IConvexV1BoosterAdapter(boosterAdapter).updateStakedPhantomTokensMap(); + IConvexV1BoosterAdapter(boosterAdapter).updateSupportedPids(); } // BALANCER VAULT diff --git a/contracts/test/suites/ZapperLiveTestHelper.sol b/contracts/test/suites/ZapperLiveTestHelper.sol index 944838fc..f3535179 100644 --- a/contracts/test/suites/ZapperLiveTestHelper.sol +++ b/contracts/test/suites/ZapperLiveTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; @@ -9,22 +9,19 @@ import {PoolV3} from "@gearbox-protocol/core-v3/contracts/pool/PoolV3.sol"; import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; import {IZapper} from "../../interfaces/zappers/IZapper.sol"; -import {IZapperRegister} from "../../interfaces/zappers/IZapperRegister.sol"; -import {DTokenDepositZapper} from "../../zappers/DTokenDepositZapper.sol"; -import {DTokenFarmingZapper} from "../../zappers/DTokenFarmingZapper.sol"; import {UnderlyingDepositZapper} from "../../zappers/UnderlyingDepositZapper.sol"; import {UnderlyingFarmingZapper} from "../../zappers/UnderlyingFarmingZapper.sol"; import {WETHDepositZapper} from "../../zappers/WETHDepositZapper.sol"; import {WETHFarmingZapper} from "../../zappers/WETHFarmingZapper.sol"; import {WstETHDepositZapper} from "../../zappers/WstETHDepositZapper.sol"; import {WstETHFarmingZapper} from "../../zappers/WstETHFarmingZapper.sol"; -import {ZapperRegister} from "../../zappers/ZapperRegister.sol"; +import {ZapperRegister} from "./ZapperRegister.sol"; import {LiveTestHelper} from "./LiveTestHelper.sol"; contract ZapperLiveTestHelper is LiveTestHelper { - IZapperRegister zapperRegister; + ZapperRegister zapperRegister; mapping(address => address) farmingPools; mapping(address => address) legacyPools; @@ -34,45 +31,33 @@ contract ZapperLiveTestHelper is LiveTestHelper { // If it fails, the value stays equal to the passed one, and the test can be skipped. if (chainId == 1337 || chainId == 31337) return; - // Either `ATTACH_ADDRESS_PROVIDER` or `LIVE_TEST_CONFIG` must be specified. - // The former allows to test zappers on existing pools, while the latter allows to create an arbitrary one. - address attachedAddressProvider = vm.envOr("ATTACH_ADDRESS_PROVIDER", address(0)); - if (attachedAddressProvider != address(0)) { - _attachCore(); + // Either `ATTACH_ZAPPER_REGISTER` or `LIVE_TEST_CONFIG` must be specified. + // The former allows to test existing deployed zappers, while the latter allows to create a new pool and test a zappers for it. + // If `ATTACH_ZAPPER_REGISTER` is specified, then `ATTACH_POOL` must also be specified + address attachedZapperRegister = vm.envOr("ATTACH_ZAPPER_REGISTER", address(0)); + if (attachedZapperRegister != address(0)) { + address acl = ZapperRegister(attachedZapperRegister).acl(); + address contractsRegister = ZapperRegister(attachedZapperRegister).contractsRegister(); + _attachState(); // By default, attach tests are run for already deployed zappers. // To test the ones that are not deployed yet, set `REDEPLOY_ZAPPERS` to `true`. bool redeployZappers = vm.envOr("REDEPLOY_ZAPPERS", false); if (redeployZappers) { - zapperRegister = new ZapperRegister(address(addressProvider)); + zapperRegister = new ZapperRegister(acl, contractsRegister); } else { - uint256 version = vm.envOr("ATTACH_ZAPPER_REGISTER_VERSION", uint256(300)); - zapperRegister = IZapperRegister(addressProvider.getAddressOrRevert("ZAPPER_REGISTER", version)); + zapperRegister = ZapperRegister(attachedZapperRegister); } - // If `ATTACH_POOL` is specified, the tests are executed only for this pool's zappers. - // Otherwise, they are run for all v3 pools. - address attachedPool = vm.envOr("ATTACH_POOL", address(0)); - if (attachedPool != address(0)) { - _attachPool(attachedPool); - if (redeployZappers) _deployZappers(address(pool)); - _; - } else { - address[] memory pools = cr.getPools(); - for (uint256 i; i < pools.length; ++i) { - if (PoolV3(pools[i]).version() >= 3_00 && !PoolV3(pools[i]).paused()) { - _attachPool(pools[i]); - if (redeployZappers) _deployZappers(pools[i]); - _; - } - } - } + _attachPool(vm.envAddress("ATTACH_POOL")); + if (redeployZappers) _deployZappers(address(pool)); + _; } else { // Deploy the system from scratch using given config. _setupCore(); _attachState(); - zapperRegister = new ZapperRegister(address(addressProvider)); + zapperRegister = new ZapperRegister(address(acl), address(cr)); _deployPool(getDeployConfig(vm.envString("LIVE_TEST_CONFIG"))); _deployZappers(address(pool)); _; @@ -102,15 +87,6 @@ contract ZapperLiveTestHelper is LiveTestHelper { zapperRegister.addZapper(address(new UnderlyingFarmingZapper(pool, farmingPool))); } - // dToken zapper - address legacyPool = legacyPools[underlying]; - if (legacyPool != address(0)) { - zapperRegister.addZapper(address(new DTokenDepositZapper(pool, legacyPool))); - if (farmingPool != address(0)) { - zapperRegister.addZapper(address(new DTokenFarmingZapper(pool, legacyPool, farmingPool))); - } - } - // WETH zapper if (underlying == tokenTestSuite.addressOf(TOKEN_WETH)) { zapperRegister.addZapper(address(new WETHDepositZapper(pool))); diff --git a/contracts/test/suites/ZapperRegister.sol b/contracts/test/suites/ZapperRegister.sol new file mode 100644 index 00000000..9070d98c --- /dev/null +++ b/contracts/test/suites/ZapperRegister.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol"; +import {ACLTrait} from "@gearbox-protocol/core-v3/contracts/traits/ACLTrait.sol"; +import {ContractsRegisterTrait} from "@gearbox-protocol/core-v3/contracts/traits/ContractsRegisterTrait.sol"; +import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol"; + +import {IZapper} from "../../interfaces/zappers/IZapper.sol"; + +contract ZapperRegister is IVersion, ACLTrait, ContractsRegisterTrait, SanityCheckTrait { + using EnumerableSet for EnumerableSet.AddressSet; + + event AddZapper(address indexed zapper); + event RemoveZapper(address indexed zapper); + + uint256 public constant version = 3_10; + bytes32 public constant contractType = "ZR"; + + mapping(address => EnumerableSet.AddressSet) internal _zappersMap; + + constructor(address acl_, address contractsRegister_) ACLTrait(acl_) ContractsRegisterTrait(contractsRegister_) {} + + function zappers(address pool) external view returns (address[] memory) { + return _zappersMap[pool].values(); + } + + function addZapper(address zapper) external nonZeroAddress(zapper) configuratorOnly { + address pool = IZapper(zapper).pool(); + _ensureRegisteredPool(pool); + + EnumerableSet.AddressSet storage zapperSet = _zappersMap[pool]; + if (!zapperSet.contains(zapper)) { + zapperSet.add(zapper); + emit AddZapper(zapper); + } + } + + function removeZapper(address zapper) external nonZeroAddress(zapper) configuratorOnly { + EnumerableSet.AddressSet storage zapperSet = _zappersMap[IZapper(zapper).pool()]; + if (zapperSet.contains(zapper)) { + zapperSet.remove(zapper); + emit RemoveZapper(zapper); + } + } +} diff --git a/contracts/test/unit/adapters/AdapterUnitTestHelper.sol b/contracts/test/unit/adapters/AdapterUnitTestHelper.sol index 5fe65be8..b89adf9d 100644 --- a/contracts/test/unit/adapters/AdapterUnitTestHelper.sol +++ b/contracts/test/unit/adapters/AdapterUnitTestHelper.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {Test} from "forge-std/Test.sol"; import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol"; import { CallerNotConfiguratorException, - CallerNotCreditFacadeException + CallerNotCreditFacadeException, + TokenNotAllowedException } from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; import {AddressProviderV3ACLMock} from "@gearbox-protocol/core-v3/contracts/test/mocks/core/AddressProviderV3ACLMock.sol"; @@ -21,8 +22,9 @@ contract AdapterUnitTestHelper is Test, CreditManagerV3MockEvents { address creditFacade; address creditAccount; address creditConfigurator; + address pool; + address acl; CreditManagerV3Mock creditManager; - AddressProviderV3ACLMock addressProvider; address[10] tokens; @@ -36,11 +38,14 @@ contract AdapterUnitTestHelper is Test, CreditManagerV3MockEvents { creditFacade = makeAddr("CREDIT_FACADE"); creditAccount = makeAddr("CREDIT_ACCOUNT"); creditConfigurator = makeAddr("CREDIT_CONFIGURATOR"); + pool = makeAddr("POOL"); vm.prank(configurator); - addressProvider = new AddressProviderV3ACLMock(); + acl = address(new AddressProviderV3ACLMock()); - creditManager = new CreditManagerV3Mock(address(addressProvider), creditFacade, creditConfigurator); + vm.mockCall(pool, abi.encodeWithSignature("acl()"), abi.encode(acl)); + + creditManager = new CreditManagerV3Mock(pool, creditFacade, creditConfigurator); for (uint256 i; i < tokens.length; ++i) { string memory name = string.concat("Test Token ", vm.toString(i)); @@ -76,6 +81,11 @@ contract AdapterUnitTestHelper is Test, CreditManagerV3MockEvents { vm.expectRevert(CallerNotCreditFacadeException.selector); } + function _revertsOnUnknownToken() internal { + //vm.expectRevert(TokenNotAllowedException.selector); + vm.expectRevert("Token not recognized"); + } + function _readsTokenMask(address token) internal { vm.expectCall(address(creditManager), abi.encodeCall(ICreditManagerV3.getTokenMaskOrRevert, (token))); } @@ -84,21 +94,7 @@ contract AdapterUnitTestHelper is Test, CreditManagerV3MockEvents { vm.expectCall(address(creditManager), abi.encodeCall(ICreditManagerV3.getActiveCreditAccountOrRevert, ())); } - function _executesSwap( - address tokenIn, - address tokenOut, - bytes memory callData, - bool requiresApproval, - bool validatesTokens - ) internal { - if (validatesTokens) { - vm.expectCall(address(creditManager), abi.encodeCall(ICreditManagerV3.getTokenMaskOrRevert, (tokenOut))); - - if (!requiresApproval) { - vm.expectCall(address(creditManager), abi.encodeCall(ICreditManagerV3.getTokenMaskOrRevert, (tokenIn))); - } - } - + function _executesSwap(address tokenIn, bytes memory callData, bool requiresApproval) internal { if (requiresApproval) { vm.expectCall( address(creditManager), @@ -120,15 +116,7 @@ contract AdapterUnitTestHelper is Test, CreditManagerV3MockEvents { } } - function _executesCall(address[] memory tokensToApprove, address[] memory tokensToValidate, bytes memory callData) - internal - { - for (uint256 i; i < tokensToValidate.length; ++i) { - vm.expectCall( - address(creditManager), abi.encodeCall(ICreditManagerV3.getTokenMaskOrRevert, (tokensToValidate[i])) - ); - } - + function _executesCall(address[] memory tokensToApprove, bytes memory callData) internal { for (uint256 i; i < tokensToApprove.length; ++i) { vm.expectCall( address(creditManager), diff --git a/contracts/test/unit/adapters/aave/AaveV2_LendingPoolAdapter.unit.t.sol b/contracts/test/unit/adapters/aave/AaveV2_LendingPoolAdapter.unit.t.sol deleted file mode 100644 index 25205a21..00000000 --- a/contracts/test/unit/adapters/aave/AaveV2_LendingPoolAdapter.unit.t.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AaveV2_LendingPoolAdapter} from "../../../../adapters/aave/AaveV2_LendingPoolAdapter.sol"; -import {ILendingPool, DataTypes} from "../../../../integrations/aave/ILendingPool.sol"; -import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; - -/// @title Aave v2 lending pool adapter unit test -/// @notice U:[AAVE2]: Unit tests for Aave v2 lending pool adapter -contract AaveV2_LendingPoolAdapterUnitTest is AdapterUnitTestHelper { - AaveV2_LendingPoolAdapter adapter; - - address lendingPool; - - function setUp() public { - _setUp(); - - lendingPool = makeAddr("LENDING_POOL"); - - DataTypes.ReserveData memory data; - data.aTokenAddress = tokens[1]; - vm.mockCall(lendingPool, abi.encodeCall(ILendingPool.getReserveData, (tokens[0])), abi.encode(data)); - - adapter = new AaveV2_LendingPoolAdapter(address(creditManager), lendingPool); - } - - /// @notice U:[AAVE2-1]: Constructor works as expected - function test_U_AAVE2_01_constructor_works_as_expected() public { - assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); - assertEq(adapter.targetContract(), lendingPool, "Incorrect targetContract"); - } - - /// @notice U:[AAVE2-2]: Wrapper functions revert on wrong caller - function test_U_AAVE2_02_wrapper_functions_revert_on_wrong_caller() public { - _revertsOnNonFacadeCaller(); - adapter.deposit(address(0), 0, address(0), 0); - - _revertsOnNonFacadeCaller(); - adapter.depositDiff(address(0), 0); - - _revertsOnNonFacadeCaller(); - adapter.withdraw(address(0), 0, address(0)); - - _revertsOnNonFacadeCaller(); - adapter.withdrawDiff(address(0), 0); - } - - /// @notice U:[AAVE2-3]: `deposit` works as expected - function test_U_AAVE2_03_deposit_works_as_expected() public { - _readsActiveAccount(); - _executesSwap({ - tokenIn: tokens[0], - tokenOut: tokens[1], - callData: abi.encodeCall(ILendingPool.deposit, (tokens[0], 123, creditAccount, 0)), - requiresApproval: true, - validatesTokens: true - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(tokens[0], 123, address(0), 0); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2-4]: `depositDiff` works as expected - function test_U_AAVE2_04_depositDiff_works_as_expected() public diffTestCases { - deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: tokens[0], - tokenOut: tokens[1], - callData: abi.encodeCall(ILendingPool.deposit, (tokens[0], diffInputAmount, creditAccount, 0)), - requiresApproval: true, - validatesTokens: true - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositDiff(tokens[0], diffLeftoverAmount); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2-5A]: `withdraw` works as expected - function test_U_AAVE2_05A_withdraw_works_as_expected() public { - _readsActiveAccount(); - _executesSwap({ - tokenIn: tokens[1], - tokenOut: tokens[0], - callData: abi.encodeCall(ILendingPool.withdraw, (tokens[0], 123, creditAccount)), - requiresApproval: false, - validatesTokens: true - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(tokens[0], 123, address(0)); - - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2-5B]: `withdraw` works as expected with amx amount - function test_U_AAVE2_05B_withdraw_works_as_expected_with_max_amount() public { - deal({token: tokens[1], to: creditAccount, give: 1001}); - _readsActiveAccount(); - _executesSwap({ - tokenIn: tokens[1], - tokenOut: tokens[0], - callData: abi.encodeCall(ILendingPool.withdraw, (tokens[0], 1000, creditAccount)), - requiresApproval: false, - validatesTokens: true - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(tokens[0], type(uint256).max, address(0)); - - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 2, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2-6]: `withdrawDiff` works as expected - function test_U_AAVE2_06_withdrawDiff_works_as_expected() public diffTestCases { - deal({token: tokens[1], to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: tokens[1], - tokenOut: tokens[0], - callData: abi.encodeCall(ILendingPool.withdraw, (tokens[0], diffInputAmount, creditAccount)), - requiresApproval: false, - validatesTokens: true - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiff(tokens[0], diffLeftoverAmount); - - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 2 : 0, "Incorrect tokensToDisable"); - } -} diff --git a/contracts/test/unit/adapters/aave/AaveV2_WrappedATokenAdapter.unit.t.sol b/contracts/test/unit/adapters/aave/AaveV2_WrappedATokenAdapter.unit.t.sol deleted file mode 100644 index a475e114..00000000 --- a/contracts/test/unit/adapters/aave/AaveV2_WrappedATokenAdapter.unit.t.sol +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AaveV2_WrappedATokenAdapter} from "../../../../adapters/aave/AaveV2_WrappedATokenAdapter.sol"; -import {WrappedAToken} from "../../../../helpers/aave/AaveV2_WrappedAToken.sol"; - -import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; - -/// @title Aave v2 wrapped aToken adapter unit test -/// @notice U:[AAVE2W]: Unit tests for Aave v2 waToken adapter -contract AaveV2_WrappedATokenAdapterUnitTest is AdapterUnitTestHelper { - AaveV2_WrappedATokenAdapter adapter; - - address token; - address aToken; - address waToken; - - uint256 tokenMask; - uint256 aTokenMask; - uint256 waTokenMask; - - function setUp() public { - _setUp(); - - (token, tokenMask) = (tokens[0], 1); - (aToken, aTokenMask) = (tokens[1], 2); - (waToken, waTokenMask) = (tokens[2], 4); - - vm.mockCall(waToken, abi.encodeWithSignature("aToken()"), abi.encode(aToken)); - vm.mockCall(waToken, abi.encodeWithSignature("underlying()"), abi.encode(token)); - - adapter = new AaveV2_WrappedATokenAdapter(address(creditManager), waToken); - } - - /// @notice U:[AAVE2W-1]: Constructor works as expected - function test_U_AAVE2W_01_constructor_works_as_expected() public { - _readsTokenMask(token); - _readsTokenMask(aToken); - _readsTokenMask(waToken); - adapter = new AaveV2_WrappedATokenAdapter(address(creditManager), waToken); - - assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); - assertEq(adapter.targetContract(), waToken, "Incorrect targetContract"); - assertEq(adapter.underlying(), token, "Incorrect underlying"); - assertEq(adapter.aToken(), aToken, "Incorrect aToken"); - assertEq(adapter.tokenMask(), tokenMask, "Incorrect tokenMask"); - assertEq(adapter.aTokenMask(), aTokenMask, "Incorrect aTokenMask"); - assertEq(adapter.waTokenMask(), waTokenMask, "Incorrect waTokenMask"); - } - - /// @notice U:[AAVE2W-2]: Wrapper functions revert on wrong caller - function test_U_AAVE2W_02_wrapper_functions_revert_on_wrong_caller() public { - _revertsOnNonFacadeCaller(); - adapter.deposit(0); - - _revertsOnNonFacadeCaller(); - adapter.depositDiff(0); - - _revertsOnNonFacadeCaller(); - adapter.depositUnderlying(0); - - _revertsOnNonFacadeCaller(); - adapter.depositDiffUnderlying(0); - - _revertsOnNonFacadeCaller(); - adapter.withdraw(0); - - _revertsOnNonFacadeCaller(); - adapter.withdrawDiff(0); - - _revertsOnNonFacadeCaller(); - adapter.withdrawUnderlying(0); - - _revertsOnNonFacadeCaller(); - adapter.withdrawDiffUnderlying(0); - } - - /// @notice U:[AAVE2W-3]: `deposit` works as expected - function test_U_AAVE2W_03_deposit_works_as_expected() public { - _executesSwap({ - tokenIn: aToken, - tokenOut: waToken, - callData: abi.encodeCall(WrappedAToken.deposit, (123)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(123); - - assertEq(tokensToEnable, waTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-4]: `depositDiff` works as expected - function test_U_AAVE2W_04_depositDiff_works_as_expected() public diffTestCases { - deal({token: aToken, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: aToken, - tokenOut: waToken, - callData: abi.encodeCall(WrappedAToken.deposit, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, waTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? aTokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-5]: `depositUnderlying` works as expected - function test_U_AAVE2W_05_depositUnderlying_works_as_expected() public { - _executesSwap({ - tokenIn: token, - tokenOut: waToken, - callData: abi.encodeCall(WrappedAToken.depositUnderlying, (123)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositUnderlying(123); - - assertEq(tokensToEnable, waTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-6]: `depositDiffUnderlying` works as expected - function test_U_AAVE2W_06_depositDiffUnderlying_works_as_expected() public diffTestCases { - deal({token: token, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: token, - tokenOut: waToken, - callData: abi.encodeCall(WrappedAToken.depositUnderlying, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositDiffUnderlying(diffLeftoverAmount); - - assertEq(tokensToEnable, waTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? tokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-7]: `withdraw` works as expected - function test_U_AAVE2W_07_withdraw_works_as_expected() public { - _executesSwap({ - tokenIn: waToken, - tokenOut: aToken, - callData: abi.encodeCall(WrappedAToken.withdraw, (123)), - requiresApproval: false, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(123); - - assertEq(tokensToEnable, aTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-8]: `withdrawDiff` works as expected - function test_U_AAVE2W_08_withdrawDiff_works_as_expected() public diffTestCases { - deal({token: waToken, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: waToken, - tokenOut: aToken, - callData: abi.encodeCall(WrappedAToken.withdraw, (diffInputAmount)), - requiresApproval: false, - validatesTokens: false - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, aTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? waTokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-9]: `withdrawUnderlying` works as expected - function test_U_AAVE2W_09_withdrawUnderlying_works_as_expected() public { - _executesSwap({ - tokenIn: waToken, - tokenOut: token, - callData: abi.encodeCall(WrappedAToken.withdrawUnderlying, (123)), - requiresApproval: false, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawUnderlying(123); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[AAVE2W-10]: `withdrawDiffUnderlying` works as expected - function test_U_AAVE2W_10_withdrawDiffUnderlying_works_as_expected() public diffTestCases { - deal({token: waToken, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: waToken, - tokenOut: token, - callData: abi.encodeCall(WrappedAToken.withdrawUnderlying, (diffInputAmount)), - requiresApproval: false, - validatesTokens: false - }); - - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiffUnderlying(diffLeftoverAmount); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? waTokenMask : 0, "Incorrect tokensToDisable"); - } -} diff --git a/contracts/test/unit/adapters/balancer/BalancerV2VaultAdapter.unit.t.sol b/contracts/test/unit/adapters/balancer/BalancerV2VaultAdapter.unit.t.sol index 6dbb499b..15f8e116 100644 --- a/contracts/test/unit/adapters/balancer/BalancerV2VaultAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/balancer/BalancerV2VaultAdapter.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {BalancerV2VaultAdapter} from "../../../../adapters/balancer/BalancerV2VaultAdapter.sol"; import { @@ -15,8 +15,7 @@ import { ExitPoolRequest } from "../../../../integrations/balancer/IBalancerV2Vault.sol"; import { - IBalancerV2VaultAdapterEvents, - IBalancerV2VaultAdapterExceptions, + IBalancerV2VaultAdapter, PoolStatus, SingleSwapDiff } from "../../../../interfaces/balancer/IBalancerV2VaultAdapter.sol"; @@ -25,13 +24,11 @@ import {VaultMock} from "../../../mocks/integrations/balancer/VaultMock.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + /// @title Balancer v2 vault adapter unit test /// @notice U:[BAL2]: Unit tests for Balancer v2 vault adapter -contract BalancerV2VaultAdapterUnitTest is - AdapterUnitTestHelper, - IBalancerV2VaultAdapterEvents, - IBalancerV2VaultAdapterExceptions -{ +contract BalancerV2VaultAdapterUnitTest is AdapterUnitTestHelper { BalancerV2VaultAdapter adapter; VaultMock vault; @@ -50,9 +47,8 @@ contract BalancerV2VaultAdapterUnitTest is } /// @notice U:[BAL2-1]: Constructor works as expected - function test_U_BAL2_01_constructor_works_as_expected() public { + function test_U_BAL2_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), address(vault), "Incorrect targetContract"); } @@ -112,7 +108,7 @@ contract BalancerV2VaultAdapterUnitTest is userData: "DUMMY DATA" }); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.swap(singleSwap, _getFundManagement(address(0)), 0, 0); @@ -122,17 +118,12 @@ contract BalancerV2VaultAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[1], - tokenOut: tokens[2], callData: abi.encodeCall(IBalancerV2Vault.swap, (singleSwap, _getFundManagement(creditAccount), 500, 456)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swap(singleSwap, _getFundManagement(address(0)), 500, 456); - - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swap(singleSwap, _getFundManagement(address(0)), 500, 456); + assertTrue(useSafePrices); } /// @notice U:[BAL2-4]: `swapDiff` works as expected @@ -156,7 +147,7 @@ contract BalancerV2VaultAdapterUnitTest is userData: "DUMMY DATA" }); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.swapDiff(singleSwapDiff, 0, 0); @@ -166,18 +157,14 @@ contract BalancerV2VaultAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[1], - tokenOut: tokens[2], callData: abi.encodeCall( IBalancerV2Vault.swap, (singleSwap, _getFundManagement(creditAccount), diffInputAmount / 2, 456) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.swapDiff(singleSwapDiff, 0.5e27, 456); - - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 2 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapDiff(singleSwapDiff, 0.5e27, 456); + assertTrue(useSafePrices); } /// @notice U:[BAL2-5]: `batchSwap` works as expected @@ -197,7 +184,7 @@ contract BalancerV2VaultAdapterUnitTest is creditManager.setExecuteResult(abi.encode(limits)); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.batchSwap(SwapKind.GIVEN_IN, swaps, assets, _getFundManagement(address(0)), limits, 456); @@ -212,18 +199,16 @@ contract BalancerV2VaultAdapterUnitTest is _readsActiveAccount(); _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: new address[](0), callData: abi.encodeCall( IBalancerV2Vault.batchSwap, (SwapKind.GIVEN_IN, swaps, assets, _getFundManagement(creditAccount), limits, 456) - ) + ) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = + bool useSafePrices = adapter.batchSwap(SwapKind.GIVEN_IN, swaps, assets, _getFundManagement(address(0)), limits, 456); - assertEq(tokensToEnable, 8 + 64, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } // ----- // @@ -240,14 +225,14 @@ contract BalancerV2VaultAdapterUnitTest is request.userData = "DUMMY DATA"; request.fromInternalBalance = false; - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.joinPool(poolId, address(0), address(0), request); vm.prank(configurator); adapter.setPoolStatus(poolId, PoolStatus.SWAP_ONLY); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.joinPool(poolId, address(0), address(0), request); @@ -257,33 +242,29 @@ contract BalancerV2VaultAdapterUnitTest is address[] memory tokensToApprove = new address[](2); tokensToApprove[0] = tokens[1]; tokensToApprove[1] = tokens[3]; - address[] memory tokensToValidate = new address[](1); - tokensToValidate[0] = tokens[0]; _readsActiveAccount(); _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: tokensToValidate, callData: abi.encodeCall(IBalancerV2Vault.joinPool, (poolId, creditAccount, creditAccount, request)) }); vm.prank(creditFacade); request.fromInternalBalance = true; - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.joinPool(poolId, address(0), address(0), request); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.joinPool(poolId, address(0), address(0), request); + assertTrue(useSafePrices); } /// @notice U:[BAL2-7]: `joinPoolSingleAsset` works as expected function test_U_BAL2_07_joinPoolSingleAsset_works_as_expected() public { - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.joinPoolSingleAsset(poolId, _asset(2), 1000, 500); vm.prank(configurator); adapter.setPoolStatus(poolId, PoolStatus.SWAP_ONLY); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.joinPoolSingleAsset(poolId, _asset(2), 1000, 500); @@ -302,29 +283,26 @@ contract BalancerV2VaultAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[2], - tokenOut: tokens[0], callData: abi.encodeCall(IBalancerV2Vault.joinPool, (poolId, creditAccount, creditAccount, request)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.joinPoolSingleAsset(poolId, _asset(2), 1000, 500); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.joinPoolSingleAsset(poolId, _asset(2), 1000, 500); + assertTrue(useSafePrices); } /// @notice U:[BAL2-8]: `joinPoolSingleAssetDiff` works as expected function test_U_BAL2_08_joinPoolSingleAssetDiff_works_as_expected() public diffTestCases { deal({token: tokens[2], to: creditAccount, give: diffMintedAmount}); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.joinPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); vm.prank(configurator); adapter.setPoolStatus(poolId, PoolStatus.SWAP_ONLY); - vm.expectRevert(PoolNotSupportedException.selector); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); vm.prank(creditFacade); adapter.joinPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); @@ -343,16 +321,12 @@ contract BalancerV2VaultAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[2], - tokenOut: tokens[0], callData: abi.encodeCall(IBalancerV2Vault.joinPool, (poolId, creditAccount, creditAccount, request)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.joinPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 4 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.joinPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); + assertTrue(useSafePrices); } // ----- // @@ -367,21 +341,23 @@ contract BalancerV2VaultAdapterUnitTest is ExitPoolRequest memory request; request.assets = _assets(0, 1, 2, 3); - address[] memory tokensToValidate = new address[](1); - tokensToValidate[0] = tokens[0]; + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); + vm.prank(creditFacade); + adapter.exitPool(poolId, address(0), payable(0), request); + + vm.prank(configurator); + adapter.setPoolStatus(poolId, PoolStatus.WITHDRAWAL_ONLY); _readsActiveAccount(); _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: tokensToValidate, callData: abi.encodeCall(IBalancerV2Vault.exitPool, (poolId, creditAccount, payable(creditAccount), request)) }); vm.prank(creditFacade); request.toInternalBalance = true; - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exitPool(poolId, address(0), payable(0), request); - assertEq(tokensToEnable, 2 + 8, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exitPool(poolId, address(0), payable(0), request); + assertTrue(useSafePrices); } /// @notice U:[BAL2-10]: `exitPoolSingleAsset` works as expected @@ -392,20 +368,23 @@ contract BalancerV2VaultAdapterUnitTest is request.minAmountsOut[2] = 500; request.userData = abi.encode(uint256(0), 1000, 1); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); + vm.prank(creditFacade); + adapter.exitPoolSingleAsset(poolId, _asset(2), 1000, 500); + + vm.prank(configurator); + adapter.setPoolStatus(poolId, PoolStatus.WITHDRAWAL_ONLY); + _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[2], callData: abi.encodeCall(IBalancerV2Vault.exitPool, (poolId, creditAccount, payable(creditAccount), request)), - requiresApproval: false, - validatesTokens: true + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exitPoolSingleAsset(poolId, _asset(2), 1000, 500); - - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exitPoolSingleAsset(poolId, _asset(2), 1000, 500); + assertTrue(useSafePrices); } /// @notice U:[BAL2-11]: `exitPoolSingleAssetDiff` works as expected @@ -418,21 +397,23 @@ contract BalancerV2VaultAdapterUnitTest is request.minAmountsOut[2] = diffInputAmount / 2; request.userData = abi.encode(uint256(0), diffInputAmount, 1); + vm.expectRevert(IBalancerV2VaultAdapter.PoolNotSupportedException.selector); + vm.prank(creditFacade); + adapter.exitPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); + + vm.prank(configurator); + adapter.setPoolStatus(poolId, PoolStatus.WITHDRAWAL_ONLY); + _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[2], callData: abi.encodeCall(IBalancerV2Vault.exitPool, (poolId, creditAccount, payable(creditAccount), request)), - requiresApproval: false, - validatesTokens: true + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.exitPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); - - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exitPoolSingleAssetDiff(poolId, _asset(2), diffLeftoverAmount, 0.5e27); + assertTrue(useSafePrices); } // ------- // @@ -441,15 +422,42 @@ contract BalancerV2VaultAdapterUnitTest is /// @notice U:[BAL2-12]: `setPoolStatus` works as expected function test_U_BAL2_12_setPoolStatus_works_as_expected() public { + vault.setPoolData("POOL_ID_INCORRECT", DUMB_ADDRESS, _assets(5, 6)); + + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatus("POOL_ID_INCORRECT", PoolStatus.SWAP_ONLY); + + IAsset[] memory assets = new IAsset[](2); + assets[0] = IAsset(tokens[1]); + assets[1] = IAsset(DUMB_ADDRESS); + + vault.setPoolData("POOL_ID_INCORRECT", tokens[0], assets); + + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatus("POOL_ID_INCORRECT", PoolStatus.SWAP_ONLY); + _revertsOnNonConfiguratorCaller(); - adapter.setPoolStatus(poolId, PoolStatus.ALLOWED); + adapter.setPoolStatus(poolId, PoolStatus.SWAP_ONLY); + + _readsTokenMask(tokens[0]); + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + _readsTokenMask(tokens[3]); vm.expectEmit(true, false, false, true); - emit SetPoolStatus(poolId, PoolStatus.ALLOWED); + emit IBalancerV2VaultAdapter.SetPoolStatus(poolId, PoolStatus.ALLOWED); vm.prank(configurator); adapter.setPoolStatus(poolId, PoolStatus.ALLOWED); assertEq(uint256(adapter.poolStatus(poolId)), uint256(PoolStatus.ALLOWED)); + + bytes32[] memory poolIds = adapter.supportedPoolIds(); + + assertEq(poolIds.length, 1, "Pool ID set length incorrect"); + + assertEq(poolIds[0], poolId, "Pool ID #0 incorrect"); } // ------- // diff --git a/contracts/test/unit/adapters/balancer/BalancerV3RouterAdapter.unit.t.sol b/contracts/test/unit/adapters/balancer/BalancerV3RouterAdapter.unit.t.sol index 2952d030..a6e52410 100644 --- a/contracts/test/unit/adapters/balancer/BalancerV3RouterAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/balancer/BalancerV3RouterAdapter.unit.t.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IBalancerV3Router} from "../../../../integrations/balancer/IBalancerV3Router.sol"; +import {IBalancerV3Pool} from "../../../../integrations/balancer/IBalancerV3Pool.sol"; import { IBalancerV3RouterAdapter, IBalancerV3RouterAdapterEvents, @@ -25,18 +26,25 @@ contract BalancerV3RouterAdapterUnitTest is BalancerV3RouterAdapter adapter; address router; - address pool; + address balancerPool; function setUp() public { _setUp(); router = makeAddr("ROUTER"); - pool = makeAddr("POOL"); + balancerPool = makeAddr("POOL"); adapter = new BalancerV3RouterAdapter(address(creditManager), router); + IERC20[] memory poolTokens = new IERC20[](2); + poolTokens[0] = IERC20(tokens[0]); + poolTokens[1] = IERC20(tokens[1]); + + // Mock pool token retrieval + vm.mockCall(balancerPool, abi.encodeCall(IBalancerV3Pool.getTokens, ()), abi.encode(poolTokens)); + // Set pool as allowed address[] memory pools = new address[](1); - pools[0] = pool; + pools[0] = balancerPool; bool[] memory statuses = new bool[](1); statuses[0] = true; vm.prank(configurator); @@ -44,19 +52,18 @@ contract BalancerV3RouterAdapterUnitTest is } /// @notice U:[BAL3-1]: Constructor works as expected - function test_U_BAL3_01_constructor_works_as_expected() public { + function test_U_BAL3_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), router, "Incorrect targetContract"); } /// @notice U:[BAL3-2]: Wrapper functions revert on wrong caller function test_U_BAL3_02_wrapper_functions_revert_on_wrong_caller() public { _revertsOnNonFacadeCaller(); - adapter.swapSingleTokenExactIn(pool, IERC20(tokens[0]), IERC20(tokens[1]), 0, 0, 0, false, ""); + adapter.swapSingleTokenExactIn(balancerPool, IERC20(tokens[0]), IERC20(tokens[1]), 0, 0, 0, false, ""); _revertsOnNonFacadeCaller(); - adapter.swapSingleTokenDiffIn(pool, IERC20(tokens[0]), IERC20(tokens[1]), 0, 0, 0); + adapter.swapSingleTokenDiffIn(balancerPool, IERC20(tokens[0]), IERC20(tokens[1]), 0, 0, 0); } /// @notice U:[BAL3-3]: `swapSingleTokenExactIn` works as expected and ignores wethIsEth and userData @@ -70,18 +77,16 @@ contract BalancerV3RouterAdapterUnitTest is // Check that allowed pool works _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( IBalancerV3Router.swapSingleTokenExactIn, - (pool, IERC20(tokens[0]), IERC20(tokens[1]), 123, 456, 789, false, "") + (balancerPool, IERC20(tokens[0]), IERC20(tokens[1]), 123, 456, 789, false, "") ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.swapSingleTokenExactIn( - pool, + bool useSafePrices = adapter.swapSingleTokenExactIn( + balancerPool, IERC20(tokens[0]), IERC20(tokens[1]), 123, @@ -91,8 +96,7 @@ contract BalancerV3RouterAdapterUnitTest is "test" // Should be ignored and set to empty string ); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[BAL3-4]: `swapSingleTokenDiffIn` works as expected @@ -106,24 +110,21 @@ contract BalancerV3RouterAdapterUnitTest is // Check that allowed pool works deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); - _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( IBalancerV3Router.swapSingleTokenExactIn, - (pool, IERC20(tokens[0]), IERC20(tokens[1]), diffInputAmount, diffInputAmount / 2, 789, false, "") + (balancerPool, IERC20(tokens[0]), IERC20(tokens[1]), diffInputAmount, diffInputAmount / 2, 789, false, "") ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapSingleTokenDiffIn(pool, IERC20(tokens[0]), IERC20(tokens[1]), diffLeftoverAmount, 0.5e27, 789); + bool useSafePrices = adapter.swapSingleTokenDiffIn( + balancerPool, IERC20(tokens[0]), IERC20(tokens[1]), diffLeftoverAmount, 0.5e27, 789 + ); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[BAL3-5]: Pool configuration works as expected @@ -145,6 +146,17 @@ contract BalancerV3RouterAdapterUnitTest is vm.prank(configurator); adapter.setPoolStatusBatch(pools, statuses); + // Mock pool token retrieval for new pools + IERC20[] memory pool1Tokens = new IERC20[](2); + pool1Tokens[0] = IERC20(tokens[0]); + pool1Tokens[1] = IERC20(tokens[1]); + vm.mockCall(pools[0], abi.encodeCall(IBalancerV3Pool.getTokens, ()), abi.encode(pool1Tokens)); + + IERC20[] memory pool2Tokens = new IERC20[](2); + pool2Tokens[0] = IERC20(tokens[1]); + pool2Tokens[1] = IERC20(tokens[2]); + vm.mockCall(pools[1], abi.encodeCall(IBalancerV3Pool.getTokens, ()), abi.encode(pool2Tokens)); + // Test setting pool statuses statuses = new bool[](2); statuses[0] = false; @@ -164,10 +176,10 @@ contract BalancerV3RouterAdapterUnitTest is // Test getAllowedPools address[] memory allowedPools = adapter.getAllowedPools(); - assertEq(allowedPools.length, 2, "Incorrect number of allowed pools"); // pool from setUp + pools[1] + assertEq(allowedPools.length, 2, "Incorrect number of allowed pools"); // balancerPool from setUp + pools[1] assertTrue( - (allowedPools[0] == pool && allowedPools[1] == pools[1]) - || (allowedPools[0] == pools[1] && allowedPools[1] == pool), + (allowedPools[0] == balancerPool && allowedPools[1] == pools[1]) + || (allowedPools[0] == pools[1] && allowedPools[1] == balancerPool), "Incorrect allowed pools" ); } diff --git a/contracts/test/unit/adapters/camelot/CamelotV3Adapter.harness.sol b/contracts/test/unit/adapters/camelot/CamelotV3Adapter.harness.sol index a8820fdb..049d0652 100644 --- a/contracts/test/unit/adapters/camelot/CamelotV3Adapter.harness.sol +++ b/contracts/test/unit/adapters/camelot/CamelotV3Adapter.harness.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {CamelotV3Adapter} from "../../../../adapters/camelot/CamelotV3Adapter.sol"; diff --git a/contracts/test/unit/adapters/camelot/CamelotV3Adapter.unit.t.sol b/contracts/test/unit/adapters/camelot/CamelotV3Adapter.unit.t.sol index 0d3ca646..f403e6db 100644 --- a/contracts/test/unit/adapters/camelot/CamelotV3Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/camelot/CamelotV3Adapter.unit.t.sol @@ -1,26 +1,23 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ICamelotV3Router} from "../../../../integrations/camelot/ICamelotV3Router.sol"; import { - ICamelotV3AdapterEvents, - ICamelotV3AdapterExceptions, + ICamelotV3Adapter, ICamelotV3AdapterTypes, - CamelotV3PoolStatus + CamelotV3PoolStatus, + CamelotV3Pool } from "../../../../interfaces/camelot/ICamelotV3Adapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {CamelotV3AdapterHarness} from "./CamelotV3Adapter.harness.sol"; +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + /// @title Camelot v3 adapter unit test /// @notice U:[CAMV3]: Unit tests for Camelot v3 swap router adapter -contract CamelotV3AdapterUnitTest is - AdapterUnitTestHelper, - ICamelotV3AdapterEvents, - ICamelotV3AdapterExceptions, - ICamelotV3AdapterTypes -{ +contract CamelotV3AdapterUnitTest is AdapterUnitTestHelper, ICamelotV3AdapterTypes { CamelotV3AdapterHarness adapter; address router; @@ -35,9 +32,8 @@ contract CamelotV3AdapterUnitTest is } /// @notice U:[CAMV3-1]: Constructor works as expected - function test_U_CAMV3_01_constructor_works_as_expected() public { + function test_U_CAMV3_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), router, "Incorrect targetContract"); } @@ -47,10 +43,16 @@ contract CamelotV3AdapterUnitTest is _revertsOnNonFacadeCaller(); adapter.exactInputSingle(p1); + _revertsOnNonFacadeCaller(); + adapter.exactInputSingleSupportingFeeOnTransferTokens(p1); + ExactDiffInputSingleParams memory p2_2; _revertsOnNonFacadeCaller(); adapter.exactDiffInputSingle(p2_2); + _revertsOnNonFacadeCaller(); + adapter.exactDiffInputSingleSupportingFeeOnTransferTokens(p2_2); + ICamelotV3Router.ExactInputParams memory p3; _revertsOnNonFacadeCaller(); adapter.exactInput(p3); @@ -68,6 +70,38 @@ contract CamelotV3AdapterUnitTest is adapter.exactOutput(p6); } + /// @notice U:[CAMV3-2A]: Functions not using `validatePath` revert on non-allowed pool + function test_U_CAMV3_02A_functions_revert_on_non_allowed_pool() public { + ICamelotV3Router.ExactInputSingleParams memory p1; + p1.tokenIn = DUMB_ADDRESS; + p1.tokenOut = tokens[0]; + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactInputSingle(p1); + + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactInputSingleSupportingFeeOnTransferTokens(p1); + + ExactDiffInputSingleParams memory p2_2; + p2_2.tokenIn = DUMB_ADDRESS; + p2_2.tokenOut = tokens[0]; + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactDiffInputSingle(p2_2); + + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactDiffInputSingleSupportingFeeOnTransferTokens(p2_2); + + ICamelotV3Router.ExactOutputSingleParams memory p5; + p5.tokenIn = DUMB_ADDRESS; + p5.tokenOut = tokens[0]; + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactOutputSingle(p5); + } + /// @notice U:[CAMV3-3]: `exactInputSingle` works as expected function test_U_CAMV3_03_exactInputSingle_works_as_expected() public { ICamelotV3Router.ExactInputSingleParams memory params = ICamelotV3Router.ExactInputSingleParams({ @@ -83,18 +117,14 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(ICamelotV3Router.exactInputSingle, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactInputSingle(params); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactInputSingle(params); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-3A]: `exactInputSingleSupportingFeeOnTransferTokens` works as expected @@ -112,19 +142,14 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(ICamelotV3Router.exactInputSingleSupportingFeeOnTransferTokens, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.exactInputSingleSupportingFeeOnTransferTokens(params); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactInputSingleSupportingFeeOnTransferTokens(params); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-4]: `exactDiffInputSingle` works as expected @@ -134,7 +159,6 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( ICamelotV3Router.exactInputSingle, ( @@ -148,13 +172,12 @@ contract CamelotV3AdapterUnitTest is limitSqrtPrice: 0 }) ) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactDiffInputSingle( + bool useSafePrices = adapter.exactDiffInputSingle( ExactDiffInputSingleParams({ tokenIn: tokens[0], tokenOut: tokens[1], @@ -165,8 +188,7 @@ contract CamelotV3AdapterUnitTest is }) ); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-4A]: `exactDiffInputSingleSupportingFeeOnTransferTokens` works as expected @@ -179,7 +201,6 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( ICamelotV3Router.exactInputSingleSupportingFeeOnTransferTokens, ( @@ -193,13 +214,12 @@ contract CamelotV3AdapterUnitTest is limitSqrtPrice: 0 }) ) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactDiffInputSingleSupportingFeeOnTransferTokens( + bool useSafePrices = adapter.exactDiffInputSingleSupportingFeeOnTransferTokens( ExactDiffInputSingleParams({ tokenIn: tokens[0], tokenOut: tokens[1], @@ -210,8 +230,7 @@ contract CamelotV3AdapterUnitTest is }) ); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-5]: `exactInput` works as expected @@ -223,7 +242,7 @@ contract CamelotV3AdapterUnitTest is deadline: 789, recipient: creditAccount }); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.exactInput(params); @@ -231,18 +250,15 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[2], callData: abi.encodeCall(ICamelotV3Router.exactInput, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactInput(params); + bool useSafePrices = adapter.exactInput(params); - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-6]: `exactDiffInput` works as expected @@ -255,7 +271,7 @@ contract CamelotV3AdapterUnitTest is leftoverAmount: diffLeftoverAmount, rateMinRAY: 0.5e27 }); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.exactDiffInput(params); @@ -263,7 +279,6 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[2], callData: abi.encodeCall( ICamelotV3Router.exactInput, ( @@ -275,16 +290,14 @@ contract CamelotV3AdapterUnitTest is recipient: creditAccount }) ) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactDiffInput(params); + bool useSafePrices = adapter.exactDiffInput(params); - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-7]: `exactOutputSingle` works as expected @@ -303,18 +316,15 @@ contract CamelotV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(ICamelotV3Router.exactOutputSingle, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactOutputSingle(params); + bool useSafePrices = adapter.exactOutputSingle(params); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-8]: `exactOutput` works as expected @@ -326,31 +336,35 @@ contract CamelotV3AdapterUnitTest is deadline: 789, recipient: creditAccount }); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(ICamelotV3Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.exactOutput(params); params.path = _makePath(3); _readsActiveAccount(); _executesSwap({ - tokenIn: tokens[2], // path is reversed for exactOutput - tokenOut: tokens[0], + tokenIn: tokens[2], callData: abi.encodeCall(ICamelotV3Router.exactOutput, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactOutput(params); + bool useSafePrices = adapter.exactOutput(params); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CAMV3-9]: `setPoolStatusBatch` works as expected function test_U_CAMV3_09_setPoolStatusBatch_works_as_expected() public { - CamelotV3PoolStatus[] memory pairs; + _setPoolsStatus(3, 0); + CamelotV3PoolStatus[] memory pairs = new CamelotV3PoolStatus[](1); + + pairs[0] = CamelotV3PoolStatus(tokens[0], DUMB_ADDRESS, true); + + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatusBatch(pairs); _revertsOnNonConfiguratorCaller(); adapter.setPoolStatusBatch(pairs); @@ -359,17 +373,28 @@ contract CamelotV3AdapterUnitTest is pairs[0] = CamelotV3PoolStatus(tokens[0], tokens[1], false); pairs[1] = CamelotV3PoolStatus(tokens[1], tokens[2], true); + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + vm.expectEmit(true, true, true, true); - emit SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false); + emit ICamelotV3Adapter.SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false); vm.expectEmit(true, true, true, true); - emit SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true); + emit ICamelotV3Adapter.SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true); vm.prank(configurator); adapter.setPoolStatusBatch(pairs); assertFalse(adapter.isPoolAllowed(tokens[0], tokens[1]), "First pool incorrectly allowed"); assertTrue(adapter.isPoolAllowed(tokens[1], tokens[2]), "Second pool incorrectly not allowed"); + + CamelotV3Pool[] memory allowedPools = adapter.supportedPools(); + + assertEq(allowedPools.length, 1, "Incorrect allowed pairs length"); + + assertEq(allowedPools[0].token0, _min(tokens[1], tokens[2]), "Incorrect allowed pool token 0"); + + assertEq(allowedPools[0].token1, _max(tokens[1], tokens[2]), "Incorrect allowed pool token 1"); } /// @notice U:[CAMV3-10]: `_validatePath` works as expected diff --git a/contracts/test/unit/adapters/compound/CompoundV2_CErc20Adapter.unit.t.sol b/contracts/test/unit/adapters/compound/CompoundV2_CErc20Adapter.unit.t.sol deleted file mode 100644 index 3077130f..00000000 --- a/contracts/test/unit/adapters/compound/CompoundV2_CErc20Adapter.unit.t.sol +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {CompoundV2_CErc20Adapter} from "../../../../adapters/compound/CompoundV2_CErc20Adapter.sol"; -import {ICErc20, ICErc20Actions} from "../../../../integrations/compound/ICErc20.sol"; -import {ICompoundV2_Exceptions} from "../../../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; -import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; - -/// @title Compound v2 CErc20 adapter unit test -/// @notice U:[COMP2T]: Unit tests for Compound v2 CErc20 token adapter -contract CompoundV2_CErc20AdapterUnitTest is AdapterUnitTestHelper, ICompoundV2_Exceptions { - CompoundV2_CErc20Adapter adapter; - - address token; - address cToken; - - uint256 tokenMask; - uint256 cTokenMask; - - function setUp() public { - _setUp(); - - creditManager.setExecuteResult(abi.encode(0)); - - (token, tokenMask) = (tokens[0], 1); - (cToken, cTokenMask) = (tokens[1], 2); - vm.mockCall(cToken, abi.encodeCall(ICErc20.underlying, ()), abi.encode(token)); - - adapter = new CompoundV2_CErc20Adapter(address(creditManager), cToken); - } - - /// @notice U:[COMP2T-1]: Constructor works as expected - function test_U_COMP2T_01_constructor_works_as_expected() public { - _readsTokenMask(token); - _readsTokenMask(cToken); - adapter = new CompoundV2_CErc20Adapter(address(creditManager), cToken); - - assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); - assertEq(adapter.targetContract(), cToken, "Incorrect targetContract"); - assertEq(adapter.cToken(), cToken, "Incorrect cToken"); - assertEq(adapter.underlying(), token, "Incorrect underlying"); - assertEq(adapter.tokenMask(), tokenMask, "Incorrect tokenMask"); - assertEq(adapter.cTokenMask(), cTokenMask, "Incorrect cTokenMask"); - } - - /// @notice U:[COMP2T-2]: Wrapper functions revert on wrong caller - function test_U_COMP2T_02_wrapper_functions_revert_on_wrong_caller() public { - _revertsOnNonFacadeCaller(); - adapter.mint(0); - - _revertsOnNonFacadeCaller(); - adapter.mintDiff(0); - - _revertsOnNonFacadeCaller(); - adapter.redeem(0); - - _revertsOnNonFacadeCaller(); - adapter.redeemDiff(0); - - _revertsOnNonFacadeCaller(); - adapter.redeemUnderlying(0); - } - - /// @notice U:[COMP2T-3]: Wrapper functions revert on cToken error - function test_U_COMP2T_03_wrapper_functions_revert_on_cToken_error() public { - creditManager.setExecuteResult(abi.encode(1)); - deal({token: token, to: creditAccount, give: 2}); - deal({token: cToken, to: creditAccount, give: 2}); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.mint(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.mintDiff(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.redeem(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.redeemDiff(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.redeemUnderlying(1); - } - - /// @notice U:[COMP2T-4]: `mint` works as expected - function test_U_COMP2T_04_mint_works_as_expected() public { - _executesSwap({ - tokenIn: token, - tokenOut: cToken, - callData: abi.encodeCall(ICErc20Actions.mint, (1000)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.mint(1000); - - assertEq(tokensToEnable, cTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2T-5]: `mintDiff` works as expected - function test_U_COMP2T_05_mintDiff_works_as_expected() public diffTestCases { - deal({token: token, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: token, - tokenOut: cToken, - callData: abi.encodeCall(ICErc20Actions.mint, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.mintDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, cTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? tokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2T-6]: `redeem` works as expected - function test_U_COMP2T_06_redeem_works_as_expected() public { - _executesSwap({ - tokenIn: cToken, - tokenOut: token, - callData: abi.encodeCall(ICErc20Actions.redeem, (1000)), - requiresApproval: false, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeem(1000); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2T-7]: `redeemDiff` works as expected - function test_U_COMP2T_07_redeemDiff_works_as_expected() public diffTestCases { - deal({token: cToken, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: cToken, - tokenOut: token, - callData: abi.encodeCall(ICErc20Actions.redeem, (diffInputAmount)), - requiresApproval: false, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeemDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? cTokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2T-8]: `redeemUnderlying` works as expected - function test_U_COMP2T_08_redeemUnderlying_works_as_expected() public { - _executesSwap({ - tokenIn: cToken, - tokenOut: token, - callData: abi.encodeCall(ICErc20Actions.redeemUnderlying, (1000)), - requiresApproval: false, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeemUnderlying(1000); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } -} diff --git a/contracts/test/unit/adapters/compound/CompoundV2_CEtherAdapter.unit.t.sol b/contracts/test/unit/adapters/compound/CompoundV2_CEtherAdapter.unit.t.sol deleted file mode 100644 index 2411de49..00000000 --- a/contracts/test/unit/adapters/compound/CompoundV2_CEtherAdapter.unit.t.sol +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {CompoundV2_CEtherAdapter} from "../../../../adapters/compound/CompoundV2_CEtherAdapter.sol"; -import {ICErc20Actions} from "../../../../integrations/compound/ICErc20.sol"; -import {ICEther} from "../../../../integrations/compound/ICEther.sol"; -import {ICompoundV2_Exceptions} from "../../../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; -import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; - -/// @title Compound v2 CEther adapter unit test -/// @notice U:[COMP2E]: Unit tests for Compound v2 CEther adapter -contract CompoundV2_CEtherAdapterUnitTest is AdapterUnitTestHelper, ICompoundV2_Exceptions { - CompoundV2_CEtherAdapter adapter; - - address gateway; - - address token; - address cToken; - - uint256 tokenMask; - uint256 cTokenMask; - - function setUp() public { - _setUp(); - - creditManager.setExecuteResult(abi.encode(0)); - - gateway = makeAddr("GATEWAY"); - (token, tokenMask) = (tokens[0], 1); - (cToken, cTokenMask) = (tokens[1], 2); - vm.mockCall(gateway, abi.encodeWithSignature("weth()"), abi.encode(token)); - vm.mockCall(gateway, abi.encodeWithSignature("ceth()"), abi.encode(cToken)); - - adapter = new CompoundV2_CEtherAdapter(address(creditManager), gateway); - } - - /// @notice U:[COMP2E-1]: Constructor works as expected - function test_U_COMP2E_01_constructor_works_as_expected() public { - _readsTokenMask(token); - _readsTokenMask(cToken); - adapter = new CompoundV2_CEtherAdapter(address(creditManager), gateway); - - assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); - assertEq(adapter.targetContract(), gateway, "Incorrect targetContract"); - assertEq(adapter.cToken(), cToken, "Incorrect cToken"); - assertEq(adapter.underlying(), token, "Incorrect underlying"); - assertEq(adapter.tokenMask(), tokenMask, "Incorrect tokenMask"); - assertEq(adapter.cTokenMask(), cTokenMask, "Incorrect cTokenMask"); - } - - /// @notice U:[COMP2E-2]: Wrapper functions revert on wrong caller - function test_U_COMP2E_02_wrapper_functions_revert_on_wrong_caller() public { - _revertsOnNonFacadeCaller(); - adapter.mint(0); - - _revertsOnNonFacadeCaller(); - adapter.mintDiff(0); - - _revertsOnNonFacadeCaller(); - adapter.redeem(0); - - _revertsOnNonFacadeCaller(); - adapter.redeemDiff(0); - - _revertsOnNonFacadeCaller(); - adapter.redeemUnderlying(0); - } - - /// @notice U:[COMP2E-3]: Wrapper functions revert on cToken error - function test_U_COMP2E_03_wrapper_functions_revert_on_cToken_error() public { - creditManager.setExecuteResult(abi.encode(1)); - deal({token: token, to: creditAccount, give: 2}); - deal({token: cToken, to: creditAccount, give: 2}); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.mint(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.mintDiff(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.redeem(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.redeemDiff(1); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, 1)); - vm.prank(creditFacade); - adapter.redeemUnderlying(1); - } - - /// @notice U:[COMP2E-4]: `mint` works as expected - function test_U_COMP2E_04_mint_works_as_expected() public { - _executesSwap({ - tokenIn: token, - tokenOut: cToken, - callData: abi.encodeCall(ICErc20Actions.mint, (1000)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.mint(1000); - - assertEq(tokensToEnable, cTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2T-5]: `mintDiff` works as expected - function test_U_COMP2E_05_mintDiff_works_as_expected() public diffTestCases { - deal({token: token, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: token, - tokenOut: cToken, - callData: abi.encodeCall(ICErc20Actions.mint, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.mintDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, cTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? tokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2E-6]: `redeem` works as expected - function test_U_COMP2E_06_redeem_works_as_expected() public { - _executesSwap({ - tokenIn: cToken, - tokenOut: token, - callData: abi.encodeCall(ICErc20Actions.redeem, (1000)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeem(1000); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2T-7]: `redeemDiff` works as expected - function test_U_COMP2T_07_redeemDiff_works_as_expected() public diffTestCases { - deal({token: cToken, to: creditAccount, give: diffMintedAmount}); - - _readsActiveAccount(); - _executesSwap({ - tokenIn: cToken, - tokenOut: token, - callData: abi.encodeCall(ICErc20Actions.redeem, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeemDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? cTokenMask : 0, "Incorrect tokensToDisable"); - } - - /// @notice U:[COMP2E-8]: `redeemUnderlying` works as expected - function test_U_COMP2E_08_redeemUnderlying_works_as_expected() public { - _executesSwap({ - tokenIn: cToken, - tokenOut: token, - callData: abi.encodeCall(ICErc20Actions.redeemUnderlying, (1000)), - requiresApproval: true, - validatesTokens: false - }); - vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeemUnderlying(1000); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); - } -} diff --git a/contracts/test/unit/adapters/convex/ConvexV1BaseRewardPoolAdapter.unit.t.sol b/contracts/test/unit/adapters/convex/ConvexV1BaseRewardPoolAdapter.unit.t.sol index a7bd23c8..5e16c10a 100644 --- a/contracts/test/unit/adapters/convex/ConvexV1BaseRewardPoolAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/convex/ConvexV1BaseRewardPoolAdapter.unit.t.sol @@ -1,13 +1,15 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ConvexV1BaseRewardPoolAdapter} from "../../../../adapters/convex/ConvexV1_BaseRewardPool.sol"; +import {IBaseRewardPool} from "../../../../integrations/convex/IBaseRewardPool.sol"; import {BaseRewardPoolMock} from "../../../mocks/integrations/convex/BaseRewardPoolMock.sol"; import {BoosterMock} from "../../../mocks/integrations/convex/BoosterMock.sol"; import {ExtraRewardWrapperMock} from "../../../mocks/integrations/convex/ExtraRewardWrapperMock.sol"; import {RewardsMock} from "../../../mocks/integrations/convex/RewardsMock.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; /// @title Convex v1 base reward pool adapter unit test @@ -65,7 +67,6 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { adapter = new ConvexV1BaseRewardPoolAdapter(address(creditManager), address(baseRewardPool), stakedPhantomToken); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), address(baseRewardPool), "Incorrect targetContract"); assertEq(adapter.curveLPtoken(), curveLPToken, "Incorrect curveLPtoken"); assertEq(adapter.stakingToken(), convexStakingToken, "Incorrect stakingToken"); @@ -74,10 +75,6 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { assertEq(adapter.extraReward2(), address(0), "Incorrect extraReward2"); assertEq(adapter.extraReward3(), address(0), "Incorrect extraReward3"); assertEq(adapter.extraReward4(), address(0), "Incorrect extraReward4"); - assertEq(adapter.curveLPTokenMask(), 1, "Incorrect curveLPTokenMask"); - assertEq(adapter.stakingTokenMask(), 2, "Incorrect stakingTokenMask"); - assertEq(adapter.stakedTokenMask(), 4, "Incorrect stakedTokenMask"); - assertEq(adapter.rewardTokensMask(), 8 + 16, "Incorrect rewardTokensMask"); } /// @notice U:[CVX1R-2]: Extra rewards are handled correctly @@ -87,7 +84,6 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { adapter = new ConvexV1BaseRewardPoolAdapter(address(creditManager), address(baseRewardPool), stakedPhantomToken); assertEq(adapter.extraReward1(), tokens[5], "Incorrect extraReward1"); assertEq(adapter.extraReward2(), address(0), "Incorrect extraReward1"); - assertEq(adapter.rewardTokensMask(), 8 + 16 + 32, "Incorrect rewardTokensMask"); baseRewardPool.setNumExtraRewards(2); _readsTokenMask(tokens[5]); @@ -95,7 +91,6 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { adapter = new ConvexV1BaseRewardPoolAdapter(address(creditManager), address(baseRewardPool), stakedPhantomToken); assertEq(adapter.extraReward1(), tokens[5], "Incorrect extraReward1"); assertEq(adapter.extraReward2(), tokens[6], "Incorrect extraReward2"); - assertEq(adapter.rewardTokensMask(), 8 + 16 + 32 + 64, "Incorrect rewardTokensMask"); baseRewardPool.setNumExtraRewards(3); _readsTokenMask(tokens[5]); @@ -105,7 +100,6 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { assertEq(adapter.extraReward1(), tokens[5], "Incorrect extraReward1"); assertEq(adapter.extraReward2(), tokens[6], "Incorrect extraReward2"); assertEq(adapter.extraReward3(), tokens[7], "Incorrect extraReward3"); - assertEq(adapter.rewardTokensMask(), 8 + 16 + 32 + 64 + 128, "Incorrect rewardTokensMask"); baseRewardPool.setNumExtraRewards(4); _readsTokenMask(tokens[5]); @@ -117,7 +111,6 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { assertEq(adapter.extraReward2(), tokens[6], "Incorrect extraReward2"); assertEq(adapter.extraReward3(), tokens[7], "Incorrect extraReward3"); assertEq(adapter.extraReward4(), tokens[8], "Incorrect extraReward4"); - assertEq(adapter.rewardTokensMask(), 8 + 16 + 32 + 64 + 128 + 256, "Incorrect rewardTokensMask"); } /// @notice U:[CVX1R-3]: Wrapper functions revert on wrong caller @@ -137,6 +130,9 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { _revertsOnNonFacadeCaller(); adapter.withdrawDiff(0, false); + _revertsOnNonFacadeCaller(); + adapter.withdrawPhantomToken(address(0), 0); + _revertsOnNonFacadeCaller(); adapter.withdrawAndUnwrap(0, false); @@ -152,15 +148,12 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { function test_U_CVX1R_04_stake_works_as_expected() public { _executesSwap({ tokenIn: convexStakingToken, - tokenOut: stakedPhantomToken, callData: abi.encodeCall(adapter.stake, (1000)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.stake(1000); - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.stake(1000); + assertFalse(useSafePrices); } /// @notice U:[CVX1R-5]: `stakeDiff` works as expected @@ -169,15 +162,12 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: convexStakingToken, - tokenOut: stakedPhantomToken, callData: abi.encodeCall(adapter.stake, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.stakeDiff(diffLeftoverAmount); - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 2 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.stakeDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } // ----- // @@ -186,15 +176,10 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { /// @notice U:[CVX1R-6]: `getReward` works as expected function test_U_CVX1R_06_getReward_works_as_expected() public { - _executesCall({ - tokensToApprove: new address[](0), - tokensToValidate: new address[](0), - callData: abi.encodeCall(adapter.getReward, ()) - }); + _executesCall({tokensToApprove: new address[](0), callData: abi.encodeCall(adapter.getReward, ())}); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.getReward(); - assertEq(tokensToEnable, 8 + 16, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.getReward(); + assertFalse(useSafePrices); } // -------- // @@ -207,15 +192,12 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { bool claim = i == 1; _executesSwap({ tokenIn: stakedPhantomToken, - tokenOut: convexStakingToken, callData: abi.encodeCall(adapter.withdraw, (1000, claim)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(1000, claim); - assertEq(tokensToEnable, claim ? (2 + 8 + 16) : 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(1000, claim); + assertFalse(useSafePrices); } } @@ -227,15 +209,12 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: stakedPhantomToken, - tokenOut: convexStakingToken, callData: abi.encodeCall(adapter.withdraw, (diffInputAmount, claim)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiff(diffLeftoverAmount, claim); - assertEq(tokensToEnable, claim ? (2 + 8 + 16) : 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 4 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdrawDiff(diffLeftoverAmount, claim); + assertFalse(useSafePrices); } } @@ -249,15 +228,12 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { bool claim = i == 1; _executesSwap({ tokenIn: stakedPhantomToken, - tokenOut: curveLPToken, callData: abi.encodeCall(adapter.withdrawAndUnwrap, (1000, claim)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawAndUnwrap(1000, claim); - assertEq(tokensToEnable, claim ? (1 + 8 + 16) : 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdrawAndUnwrap(1000, claim); + assertFalse(useSafePrices); } } @@ -269,15 +245,28 @@ contract ConvexV1BaseRewardPoolAdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: stakedPhantomToken, - tokenOut: curveLPToken, callData: abi.encodeCall(adapter.withdrawAndUnwrap, (diffInputAmount, claim)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiffAndUnwrap(diffLeftoverAmount, claim); - assertEq(tokensToEnable, claim ? (1 + 8 + 16) : 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 4 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdrawDiffAndUnwrap(diffLeftoverAmount, claim); + assertFalse(useSafePrices); } } + + /// @notice U:[CVX1R-11]: `withdrawPhantomToken` works as expected + function test_U_CVX1R_11_withdrawPhantomToken_works_as_expected() public { + vm.expectRevert(IPhantomTokenAdapter.IncorrectStakedPhantomTokenException.selector); + vm.prank(creditFacade); + adapter.withdrawPhantomToken(address(0), 1000); + + _executesSwap({ + tokenIn: stakedPhantomToken, + callData: abi.encodeCall(IBaseRewardPool.withdraw, (1000, false)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdrawPhantomToken(stakedPhantomToken, 1000); + assertFalse(useSafePrices); + } } diff --git a/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.harness.sol b/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.harness.sol index ea25b128..8bb6a68a 100644 --- a/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.harness.sol +++ b/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.harness.sol @@ -1,14 +1,23 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {ConvexV1BoosterAdapter} from "../../../../adapters/convex/ConvexV1_Booster.sol"; contract ConvexV1BoosterAdapterHarness is ConvexV1BoosterAdapter { + using EnumerableSet for EnumerableSet.UintSet; + constructor(address _creditManager, address _booster) ConvexV1BoosterAdapter(_creditManager, _booster) {} - function hackPidToPhantokToken(uint256 pid, address token) external { - pidToPhantomToken[pid] = token; + function hackPidMappings(uint256 pid, address phantomToken, address curveToken, address convexToken) external { + pidToPhantomToken[pid] = phantomToken; + pidToCurveToken[pid] = curveToken; + pidToConvexToken[pid] = convexToken; + } + + function hackSupportedPids(uint256 pid) external { + _supportedPids.add(pid); } } diff --git a/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.unit.t.sol b/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.unit.t.sol index 9aeb14b9..886888f3 100644 --- a/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/convex/ConvexV1BoosterAdapter.unit.t.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {BoosterMock} from "../../../mocks/integrations/convex/BoosterMock.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {ConvexV1BoosterAdapterHarness} from "./ConvexV1BoosterAdapter.harness.sol"; +import {IConvexV1BoosterAdapter} from "../../../../interfaces/convex/IConvexV1BoosterAdapter.sol"; /// @title Convex v1 booster adapter unit test /// @notice U:[CVX1B]: Unit tests for Convex v1 booster adapter @@ -20,13 +21,13 @@ contract ConvexV1BoosterAdapterUnitTest is AdapterUnitTestHelper { booster.setPoolInfo(42, tokens[0], tokens[1]); adapter = new ConvexV1BoosterAdapterHarness(address(creditManager), address(booster)); - adapter.hackPidToPhantokToken(42, tokens[2]); + adapter.hackSupportedPids(42); + adapter.hackPidMappings(42, tokens[2], tokens[0], tokens[1]); } /// @notice U:[CVX1B-1]: Constructor works as expected - function test_U_CVX1B_01_constructor_works_as_expected() public { + function test_U_CVX1B_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), address(booster), "Incorrect targetContract"); } @@ -45,6 +46,25 @@ contract ConvexV1BoosterAdapterUnitTest is AdapterUnitTestHelper { adapter.withdrawDiff(0, 0); } + /// @notice U:[CVX1B-2A]: Functions revert on unknown pid + function test_U_CVX1B_02A_functions_revert_on_unknown_pid() public { + vm.expectRevert(IConvexV1BoosterAdapter.UnsupportedPidException.selector); + vm.prank(creditFacade); + adapter.deposit(90, 0, false); + + vm.expectRevert(IConvexV1BoosterAdapter.UnsupportedPidException.selector); + vm.prank(creditFacade); + adapter.depositDiff(90, 0, false); + + vm.expectRevert(IConvexV1BoosterAdapter.UnsupportedPidException.selector); + vm.prank(creditFacade); + adapter.withdraw(90, 0); + + vm.expectRevert(IConvexV1BoosterAdapter.UnsupportedPidException.selector); + vm.prank(creditFacade); + adapter.withdrawDiff(90, 0); + } + /// @notice U:[CVX1B-3]: `deposit` works as expected function test_U_CVX1B_03_deposit_works_as_expected() public { for (uint256 i; i < 2; ++i) { @@ -52,17 +72,13 @@ contract ConvexV1BoosterAdapterUnitTest is AdapterUnitTestHelper { _executesSwap({ tokenIn: tokens[0], - tokenOut: stake ? tokens[2] : tokens[1], callData: abi.encodeCall(adapter.deposit, (42, 1000, stake)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(42, 1000, stake); - - assertEq(tokensToEnable, stake ? 4 : 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.deposit(42, 1000, stake); + assertFalse(useSafePrices); } } @@ -74,17 +90,14 @@ contract ConvexV1BoosterAdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: stake ? tokens[2] : tokens[1], callData: abi.encodeCall(adapter.deposit, (42, diffInputAmount, stake)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositDiff(42, diffLeftoverAmount, stake); + bool useSafePrices = adapter.depositDiff(42, diffLeftoverAmount, stake); - assertEq(tokensToEnable, stake ? 4 : 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertFalse(useSafePrices); } } @@ -92,17 +105,13 @@ contract ConvexV1BoosterAdapterUnitTest is AdapterUnitTestHelper { function test_U_CVX1B_05_withdraw_works_as_expected() public { _executesSwap({ tokenIn: tokens[1], - tokenOut: tokens[0], callData: abi.encodeCall(adapter.withdraw, (42, 1000)), - requiresApproval: false, - validatesTokens: true + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(42, 1000); - - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(42, 1000); + assertFalse(useSafePrices); } /// @notice U:[CVX1B-6]: `withdrawDiff` works as expected @@ -111,22 +120,18 @@ contract ConvexV1BoosterAdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: tokens[1], - tokenOut: tokens[0], callData: abi.encodeCall(adapter.withdraw, (42, diffInputAmount)), - requiresApproval: false, - validatesTokens: true + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiff(42, diffLeftoverAmount); - - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 2 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdrawDiff(42, diffLeftoverAmount); + assertFalse(useSafePrices); } /// @notice U:[CVX1B-7]: `updatedStakedPhantomTokensMap` reverts on wrong caller function test_U_CVX1B_07_updateStakedPhantomTokensMap_reverts_on_wrong_caller() public { _revertsOnNonConfiguratorCaller(); - adapter.updateStakedPhantomTokensMap(); + adapter.updateSupportedPids(); } } diff --git a/contracts/test/unit/adapters/curve/CurveV1Adapter2Assets.unit.t.sol b/contracts/test/unit/adapters/curve/CurveV1Adapter2Assets.unit.t.sol index ab184c47..62fe8581 100644 --- a/contracts/test/unit/adapters/curve/CurveV1Adapter2Assets.unit.t.sol +++ b/contracts/test/unit/adapters/curve/CurveV1Adapter2Assets.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {CurveV1Adapter2Assets} from "../../../../adapters/curve/CurveV1_2.sol"; import {ICurvePool2Assets} from "../../../../integrations/curve/ICurvePool_2.sol"; @@ -12,29 +12,25 @@ import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; /// @notice U:[CRV2]: Unit tests for Curve 2 coins pool adapter contract CurveV1Adapter2AssetsUnitTest is AdapterUnitTestHelper { CurveV1Adapter2Assets adapter; - PoolMock pool; + PoolMock curvePool; address token0; address token1; address lpToken; - uint256 token0Mask; - uint256 token1Mask; - uint256 lpTokenMask; - function setUp() public { _setUp(); - (token0, token0Mask) = (tokens[0], 1); - (token1, token1Mask) = (tokens[1], 2); - (lpToken, lpTokenMask) = (tokens[2], 4); + token0 = tokens[0]; + token1 = tokens[1]; + lpToken = tokens[2]; address[] memory coins = new address[](2); coins[0] = token0; coins[1] = token1; - pool = new PoolMock(PoolType.Stable, coins, new address[](0)); + curvePool = new PoolMock(PoolType.Stable, coins, new address[](0)); - adapter = new CurveV1Adapter2Assets(address(creditManager), address(pool), lpToken, address(0)); + adapter = new CurveV1Adapter2Assets(address(creditManager), address(curvePool), lpToken, address(0), false); assertEq(adapter.nCoins(), 2, "Incorrect nCoins"); } @@ -58,44 +54,35 @@ contract CurveV1Adapter2AssetsUnitTest is AdapterUnitTestHelper { tokensToApprove[1] = token1; _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool2Assets.add_liquidity, ([uint256(750), 250], 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.add_liquidity([uint256(750), 250], 500); - - assertEq(tokensToEnable, lpTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.add_liquidity([uint256(750), 250], 500); + assertTrue(useSafePrices); } /// @notice U:[CRV2-3]: `remove_liquidity` works as expected function test_U_CRV2_03_remove_liquidity_works_as_expected() public { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool2Assets.remove_liquidity, (500, [uint256(750), 250])) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.remove_liquidity(500, [uint256(750), 250]); - - assertEq(tokensToEnable, token0Mask | token1Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity(500, [uint256(750), 250]); + assertTrue(useSafePrices); } /// @notice U:[CRV2-4]: `remove_liquidity_imbalance` works as expected function test_U_CRV2_04_remove_liquidity_imbalance_works_as_expected() public { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool2Assets.remove_liquidity_imbalance, ([uint256(0), 250], 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.remove_liquidity_imbalance([uint256(0), 250], 500); - - assertEq(tokensToEnable, token1Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity_imbalance([uint256(0), 250], 500); + assertTrue(useSafePrices); } } diff --git a/contracts/test/unit/adapters/curve/CurveV1Adapter3Assets.unit.t.sol b/contracts/test/unit/adapters/curve/CurveV1Adapter3Assets.unit.t.sol index f27ff828..a0e45ac6 100644 --- a/contracts/test/unit/adapters/curve/CurveV1Adapter3Assets.unit.t.sol +++ b/contracts/test/unit/adapters/curve/CurveV1Adapter3Assets.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {CurveV1Adapter3Assets} from "../../../../adapters/curve/CurveV1_3.sol"; import {ICurvePool3Assets} from "../../../../integrations/curve/ICurvePool_3.sol"; @@ -12,33 +12,28 @@ import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; /// @notice U:[CRV3]: Unit tests for Curve 3 coins pool adapter contract CurveV1Adapter3AssetsUnitTest is AdapterUnitTestHelper { CurveV1Adapter3Assets adapter; - PoolMock pool; + PoolMock curvePool; address token0; address token1; address token2; address lpToken; - uint256 token0Mask; - uint256 token1Mask; - uint256 token2Mask; - uint256 lpTokenMask; - function setUp() public { _setUp(); - (token0, token0Mask) = (tokens[0], 1); - (token1, token1Mask) = (tokens[1], 2); - (token2, token2Mask) = (tokens[2], 4); - (lpToken, lpTokenMask) = (tokens[3], 8); + token0 = tokens[0]; + token1 = tokens[1]; + token2 = tokens[2]; + lpToken = tokens[3]; address[] memory coins = new address[](3); coins[0] = token0; coins[1] = token1; coins[2] = token2; - pool = new PoolMock(PoolType.Stable, coins, new address[](0)); + curvePool = new PoolMock(PoolType.Stable, coins, new address[](0)); - adapter = new CurveV1Adapter3Assets(address(creditManager), address(pool), lpToken, address(0)); + adapter = new CurveV1Adapter3Assets(address(creditManager), address(curvePool), lpToken, address(0), false); assertEq(adapter.nCoins(), 3, "Incorrect nCoins"); } @@ -63,45 +58,35 @@ contract CurveV1Adapter3AssetsUnitTest is AdapterUnitTestHelper { tokensToApprove[2] = token2; _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool3Assets.add_liquidity, ([uint256(750), 500, 250], 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.add_liquidity([uint256(750), 500, 250], 500); - - assertEq(tokensToEnable, lpTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.add_liquidity([uint256(750), 500, 250], 500); + assertTrue(useSafePrices); } /// @notice U:[CRV3-3]: `remove_liquidity` works as expected function test_U_CRV3_03_remove_liquidity_works_as_expected() public { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool3Assets.remove_liquidity, (500, [uint256(750), 500, 250])) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.remove_liquidity(500, [uint256(750), 500, 250]); - - assertEq(tokensToEnable, token0Mask | token1Mask | token2Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity(500, [uint256(750), 500, 250]); + assertTrue(useSafePrices); } /// @notice U:[CRV3-4]: `remove_liquidity_imbalance` works as expected function test_U_CRV3_04_remove_liquidity_imbalance_works_as_expected() public { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool3Assets.remove_liquidity_imbalance, ([uint256(0), 500, 250], 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.remove_liquidity_imbalance([uint256(0), 500, 250], 500); - - assertEq(tokensToEnable, token1Mask | token2Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity_imbalance([uint256(0), 500, 250], 500); + assertTrue(useSafePrices); } } diff --git a/contracts/test/unit/adapters/curve/CurveV1Adapter4Assets.unit.t.sol b/contracts/test/unit/adapters/curve/CurveV1Adapter4Assets.unit.t.sol index 1cbbd013..f7e200cf 100644 --- a/contracts/test/unit/adapters/curve/CurveV1Adapter4Assets.unit.t.sol +++ b/contracts/test/unit/adapters/curve/CurveV1Adapter4Assets.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {CurveV1Adapter4Assets} from "../../../../adapters/curve/CurveV1_4.sol"; import {ICurvePool4Assets} from "../../../../integrations/curve/ICurvePool_4.sol"; @@ -12,7 +12,7 @@ import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; /// @notice U:[CRV4]: Unit tests for Curve 4 coins pool adapter contract CurveV1Adapter4AssetsUnitTest is AdapterUnitTestHelper { CurveV1Adapter4Assets adapter; - PoolMock pool; + PoolMock curvePool; address token0; address token1; @@ -20,29 +20,23 @@ contract CurveV1Adapter4AssetsUnitTest is AdapterUnitTestHelper { address token3; address lpToken; - uint256 token0Mask; - uint256 token1Mask; - uint256 token2Mask; - uint256 token3Mask; - uint256 lpTokenMask; - function setUp() public { _setUp(); - (token0, token0Mask) = (tokens[0], 1); - (token1, token1Mask) = (tokens[1], 2); - (token2, token2Mask) = (tokens[2], 4); - (token3, token3Mask) = (tokens[3], 8); - (lpToken, lpTokenMask) = (tokens[4], 16); + token0 = tokens[0]; + token1 = tokens[1]; + token2 = tokens[2]; + token3 = tokens[3]; + lpToken = tokens[4]; address[] memory coins = new address[](4); coins[0] = token0; coins[1] = token1; coins[2] = token2; coins[3] = token3; - pool = new PoolMock(PoolType.Stable, coins, new address[](0)); + curvePool = new PoolMock(PoolType.Stable, coins, new address[](0)); - adapter = new CurveV1Adapter4Assets(address(creditManager), address(pool), lpToken, address(0)); + adapter = new CurveV1Adapter4Assets(address(creditManager), address(curvePool), lpToken, address(0), false); assertEq(adapter.nCoins(), 4, "Incorrect nCoins"); } @@ -68,45 +62,35 @@ contract CurveV1Adapter4AssetsUnitTest is AdapterUnitTestHelper { tokensToApprove[3] = token3; _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool4Assets.add_liquidity, ([uint256(750), 500, 500, 250], 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.add_liquidity([uint256(750), 500, 500, 250], 500); - - assertEq(tokensToEnable, lpTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.add_liquidity([uint256(750), 500, 500, 250], 500); + assertTrue(useSafePrices); } /// @notice U:[CRV4-3]: `remove_liquidity` works as expected function test_U_CRV4_03_remove_liquidity_works_as_expected() public { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool4Assets.remove_liquidity, (500, [uint256(750), 500, 500, 250])) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.remove_liquidity(500, [uint256(750), 500, 500, 250]); - - assertEq(tokensToEnable, token0Mask | token1Mask | token2Mask | token3Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity(500, [uint256(750), 500, 500, 250]); + assertTrue(useSafePrices); } /// @notice U:[CRV4-4]: `remove_liquidity_imbalance` works as expected function test_U_CRV4_04_remove_liquidity_imbalance_works_as_expected() public { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePool4Assets.remove_liquidity_imbalance, ([uint256(0), 500, 0, 250], 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.remove_liquidity_imbalance([uint256(0), 500, 0, 250], 500); - - assertEq(tokensToEnable, token1Mask | token3Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity_imbalance([uint256(0), 500, 0, 250], 500); + assertTrue(useSafePrices); } } diff --git a/contracts/test/unit/adapters/curve/CurveV1AdapterBase.harness.sol b/contracts/test/unit/adapters/curve/CurveV1AdapterBase.harness.sol index f0a7dcc5..af76b756 100644 --- a/contracts/test/unit/adapters/curve/CurveV1AdapterBase.harness.sol +++ b/contracts/test/unit/adapters/curve/CurveV1AdapterBase.harness.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {AdapterType} from "@gearbox-protocol/sdk-gov/contracts/AdapterType.sol"; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {CurveV1AdapterBase} from "../../../../adapters/curve/CurveV1_Base.sol"; import {ICurvePool2Assets} from "../../../../integrations/curve/ICurvePool_2.sol"; @@ -11,14 +9,21 @@ import {ICurvePool3Assets} from "../../../../integrations/curve/ICurvePool_3.sol import {ICurvePool4Assets} from "../../../../integrations/curve/ICurvePool_4.sol"; contract CurveV1AdapterBaseHarness is CurveV1AdapterBase { - constructor(address _creditManager, address _curvePool, address _lp_token, address _metapoolBase, uint256 _nCoins) - CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, _nCoins) - {} + constructor( + address _creditManager, + address _curvePool, + address _lp_token, + address _metapoolBase, + uint256 _nCoins, + bool _use256 + ) CurveV1AdapterBase(_creditManager, _curvePool, _lp_token, _metapoolBase, _nCoins, _use256) {} - function _gearboxAdapterType() external view override returns (AdapterType) { - return nCoins == 2 - ? AdapterType.CURVE_V1_2ASSETS - : (nCoins == 3 ? AdapterType.CURVE_V1_3ASSETS : AdapterType.CURVE_V1_4ASSETS); + function contractType() public view override returns (bytes32) { + return ( + nCoins == 2 + ? bytes32("AD_CURVE_V1_2ASSETS") + : (nCoins == 3 ? bytes32("AD_CURVE_V1_3ASSETS") : bytes32("AD_CURVE_V1_4ASSETS")) + ); } function _getAddLiquidityOneCoinCallData(uint256 i, uint256 amount, uint256 minAmount) @@ -71,4 +76,8 @@ contract CurveV1AdapterBaseHarness is CurveV1AdapterBase { ); } } + + function serialize() external view returns (bytes memory serializedData) { + serializedData = abi.encode(creditManager, targetContract); + } } diff --git a/contracts/test/unit/adapters/curve/CurveV1AdapterBase.unit.t.sol b/contracts/test/unit/adapters/curve/CurveV1AdapterBase.unit.t.sol index aa107eba..2a81ac93 100644 --- a/contracts/test/unit/adapters/curve/CurveV1AdapterBase.unit.t.sol +++ b/contracts/test/unit/adapters/curve/CurveV1AdapterBase.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import { IncorrectParameterException, @@ -17,7 +17,7 @@ import {CurveV1AdapterBaseHarness} from "./CurveV1AdapterBase.harness.sol"; contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { CurveV1AdapterBaseHarness adapter; PoolMock basePool; - PoolMock pool; + PoolMock curvePool; address token0; address token1; @@ -25,12 +25,6 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { address underlying1; address lpToken; - uint256 token0Mask; - uint256 token1Mask; - uint256 underlying0Mask; - uint256 underlying1Mask; - uint256 lpTokenMask; - // ----- // // SETUP // // ----- // @@ -57,11 +51,11 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { function setUp() public { _setUp(); - (token0, token0Mask) = (tokens[0], 1); - (token1, token1Mask) = (tokens[1], 2); - (underlying0, underlying0Mask) = (tokens[2], 4); - (underlying1, underlying1Mask) = (tokens[3], 8); - (lpToken, lpTokenMask) = (tokens[4], 16); + token0 = tokens[0]; + token1 = tokens[1]; + underlying0 = tokens[2]; + underlying1 = tokens[3]; + lpToken = tokens[4]; } function _setupPoolAndAdapter(PoolType poolType) internal { @@ -73,9 +67,11 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { address[] memory coins = new address[](2); coins[0] = token0; coins[1] = token1; - pool = new PoolMock(poolType, coins, new address[](0)); + curvePool = new PoolMock(poolType, coins, new address[](0)); - adapter = new CurveV1AdapterBaseHarness(address(creditManager), address(pool), lpToken, address(basePool), 2); + adapter = new CurveV1AdapterBaseHarness( + address(creditManager), address(curvePool), lpToken, address(basePool), 2, poolType == PoolType.Crypto + ); assertEq(adapter.use256(), poolType == PoolType.Crypto, "Incorrect use256"); } @@ -86,40 +82,37 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { /// @notice U:[CRVB-1]: Constructor works as expected function test_U_CRVB_01_constructor_works_as_expected() public { - pool = new PoolMock(PoolType.Stable, new address[](0), new address[](0)); + curvePool = new PoolMock(PoolType.Stable, new address[](0), new address[](0)); // reverts on zero LP token vm.expectRevert(ZeroAddressException.selector); - new CurveV1AdapterBaseHarness(address(creditManager), address(pool), address(0), address(0), 2); + new CurveV1AdapterBaseHarness(address(creditManager), address(curvePool), address(0), address(0), 2, false); // reverts when pool has fewer coins than needed vm.expectRevert(IncorrectParameterException.selector); - new CurveV1AdapterBaseHarness(address(creditManager), address(pool), lpToken, address(0), 2); + new CurveV1AdapterBaseHarness(address(creditManager), address(curvePool), lpToken, address(0), 2, false); // plain pool address[] memory coins = new address[](2); coins[0] = token0; coins[1] = token1; - pool = new PoolMock(PoolType.Stable, coins, new address[](0)); + curvePool = new PoolMock(PoolType.Stable, coins, new address[](0)); _readsTokenMask(token0); _readsTokenMask(token1); _readsTokenMask(lpToken); - adapter = new CurveV1AdapterBaseHarness(address(creditManager), address(pool), lpToken, address(0), 2); + adapter = + new CurveV1AdapterBaseHarness(address(creditManager), address(curvePool), lpToken, address(0), 2, false); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); - assertEq(adapter.targetContract(), address(pool), "Incorrect targetContract"); + assertEq(adapter.targetContract(), address(curvePool), "Incorrect targetContract"); assertEq(adapter.token(), lpToken, "Incorrect token"); assertEq(adapter.lp_token(), lpToken, "Incorrect token"); - assertEq(adapter.lpTokenMask(), lpTokenMask, "Incorrect lpTokenMask"); assertEq(adapter.metapoolBase(), address(0), "Incorrect metapoolBase"); assertEq(adapter.nCoins(), 2, "Incorrect nCoins"); assertEq(adapter.token0(), token0, "Incorrect token0"); assertEq(adapter.token1(), token1, "Incorrect token1"); - assertEq(adapter.token0Mask(), token0Mask, "Incorrect token0Mask"); - assertEq(adapter.token1Mask(), token1Mask, "Incorrect token1Mask"); // metapool address[] memory underlyings = new address[](2); @@ -132,30 +125,28 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _readsTokenMask(underlying0); _readsTokenMask(underlying1); _readsTokenMask(lpToken); - adapter = new CurveV1AdapterBaseHarness(address(creditManager), address(pool), lpToken, address(basePool), 2); + adapter = new CurveV1AdapterBaseHarness( + address(creditManager), address(curvePool), lpToken, address(basePool), 2, false + ); assertEq(adapter.metapoolBase(), address(basePool), "Incorrect metapoolBase"); assertEq(adapter.underlying0(), token0, "Incorrect underlying0"); assertEq(adapter.underlying1(), underlying0, "Incorrect underlying1"); assertEq(adapter.underlying2(), underlying1, "Incorrect underlying2"); - assertEq(adapter.underlying0Mask(), token0Mask, "Incorrect underlying0Mask"); - assertEq(adapter.underlying1Mask(), underlying0Mask, "Incorrect underlying1Mask"); - assertEq(adapter.underlying2Mask(), underlying1Mask, "Incorrect underlying2Mask"); // lending pool - pool = new PoolMock(PoolType.Stable, coins, underlyings); + curvePool = new PoolMock(PoolType.Stable, coins, underlyings); _readsTokenMask(token0); _readsTokenMask(token1); _readsTokenMask(underlying0); _readsTokenMask(underlying1); _readsTokenMask(lpToken); - adapter = new CurveV1AdapterBaseHarness(address(creditManager), address(pool), lpToken, address(0), 2); + adapter = + new CurveV1AdapterBaseHarness(address(creditManager), address(curvePool), lpToken, address(0), 2, false); assertEq(adapter.metapoolBase(), address(0), "Incorrect metapoolBase"); assertEq(adapter.underlying0(), underlying0, "Incorrect underlying0"); assertEq(adapter.underlying1(), underlying1, "Incorrect underlying1"); - assertEq(adapter.underlying0Mask(), underlying0Mask, "Incorrect underlying0Mask"); - assertEq(adapter.underlying1Mask(), underlying1Mask, "Incorrect underlying1Mask"); } /// @notice U:[CRVB-2]: Wrapper functions revert on wrong caller @@ -205,27 +196,23 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _executesSwap({ tokenIn: token0, - tokenOut: token1, callData: abi.encodeWithSignature( - pool.isCrypto() + curvePool.isCrypto() ? "exchange(uint256,uint256,uint256,uint256)" : "exchange(int128,int128,uint256,uint256)", 0, 1, 1000, 500 - ), - requiresApproval: true, - validatesTokens: false + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = use256 + bool useSafePrices = use256 ? adapter.exchange(uint256(0), uint256(1), 1000, 500) : adapter.exchange(int128(0), int128(1), 1000, 500); - - assertEq(tokensToEnable, token1Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } } @@ -236,24 +223,22 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: token0, - tokenOut: token1, callData: abi.encodeWithSignature( - pool.isCrypto() ? "exchange(uint256,uint256,uint256,uint256)" : "exchange(int128,int128,uint256,uint256)", + curvePool.isCrypto() + ? "exchange(uint256,uint256,uint256,uint256)" + : "exchange(int128,int128,uint256,uint256)", 0, 1, diffInputAmount, diffInputAmount / 2 - ), - requiresApproval: true, - validatesTokens: false + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.exchange_diff(uint256(0), uint256(1), diffLeftoverAmount, 0.5e27); + bool useSafePrices = adapter.exchange_diff(uint256(0), uint256(1), diffLeftoverAmount, 0.5e27); - assertEq(tokensToEnable, token1Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? token0Mask : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[CRVB-5]: `exchange_underlying` works as expected @@ -263,27 +248,24 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _executesSwap({ tokenIn: token0, - tokenOut: underlying0, callData: abi.encodeWithSignature( - pool.isCrypto() + curvePool.isCrypto() ? "exchange_underlying(uint256,uint256,uint256,uint256)" : "exchange_underlying(int128,int128,uint256,uint256)", 0, 1, 1000, 500 - ), - requiresApproval: true, - validatesTokens: false + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = use256 + bool useSafePrices = use256 ? adapter.exchange_underlying(uint256(0), uint256(1), 1000, 500) : adapter.exchange_underlying(int128(0), int128(1), 1000, 500); - assertEq(tokensToEnable, underlying0Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } } @@ -298,26 +280,21 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: token0, - tokenOut: underlying0, callData: abi.encodeWithSignature( - pool.isCrypto() + curvePool.isCrypto() ? "exchange_underlying(uint256,uint256,uint256,uint256)" : "exchange_underlying(int128,int128,uint256,uint256)", 0, 1, diffInputAmount, diffInputAmount / 2 - ), - requiresApproval: true, - validatesTokens: false + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.exchange_diff_underlying(uint256(0), uint256(1), diffLeftoverAmount, 0.5e27); - - assertEq(tokensToEnable, underlying0Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? token0Mask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exchange_diff_underlying(uint256(0), uint256(1), diffLeftoverAmount, 0.5e27); + assertTrue(useSafePrices); } // ------------- // @@ -328,17 +305,13 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { function test_U_CRVB_07_add_liquidity_one_coin_works_as_expected() public onlyStablePools { _executesSwap({ tokenIn: token0, - tokenOut: lpToken, callData: abi.encodeWithSignature("add_liquidity(uint256[2],uint256)", 1000, 0, 500), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.add_liquidity_one_coin(1000, 0, 500); - - assertEq(tokensToEnable, lpTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.add_liquidity_one_coin(1000, 0, 500); + assertTrue(useSafePrices); } /// @notice U:[CRVB-8]: `add_diff_liquidity_one_coin` works as expected @@ -347,18 +320,13 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _executesSwap({ tokenIn: token0, - tokenOut: lpToken, callData: abi.encodeWithSignature("add_liquidity(uint256[2],uint256)", diffInputAmount, 0, diffInputAmount / 2), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.add_diff_liquidity_one_coin(diffLeftoverAmount, 0, 0.5e27); - - assertEq(tokensToEnable, lpTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? token0Mask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.add_diff_liquidity_one_coin(diffLeftoverAmount, 0, 0.5e27); + assertTrue(useSafePrices); } // ---------------- // @@ -372,26 +340,23 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _executesSwap({ tokenIn: lpToken, - tokenOut: token0, callData: abi.encodeWithSignature( - pool.isCrypto() + curvePool.isCrypto() ? "remove_liquidity_one_coin(uint256,uint256,uint256)" : "remove_liquidity_one_coin(uint256,int128,uint256)", 1000, 0, 500 - ), - requiresApproval: false, - validatesTokens: false + ), + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = use256 + bool useSafePrices = use256 ? adapter.remove_liquidity_one_coin(1000, uint256(0), 500) : adapter.remove_liquidity_one_coin(1000, int128(0), 500); - assertEq(tokensToEnable, token0Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } } @@ -406,24 +371,19 @@ contract CurveV1AdapterBaseUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: lpToken, - tokenOut: token0, callData: abi.encodeWithSignature( - pool.isCrypto() + curvePool.isCrypto() ? "remove_liquidity_one_coin(uint256,uint256,uint256)" : "remove_liquidity_one_coin(uint256,int128,uint256)", diffInputAmount, 0, diffInputAmount / 2 - ), - requiresApproval: false, - validatesTokens: false + ), + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.remove_diff_liquidity_one_coin(diffLeftoverAmount, uint256(0), 0.5e27); - - assertEq(tokensToEnable, token0Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? lpTokenMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_diff_liquidity_one_coin(diffLeftoverAmount, uint256(0), 0.5e27); + assertTrue(useSafePrices); } } diff --git a/contracts/test/unit/adapters/curve/CurveV1AdapterStableNG.unit.t.sol b/contracts/test/unit/adapters/curve/CurveV1AdapterStableNG.unit.t.sol index 81e1d5d0..2d59aeb2 100644 --- a/contracts/test/unit/adapters/curve/CurveV1AdapterStableNG.unit.t.sol +++ b/contracts/test/unit/adapters/curve/CurveV1AdapterStableNG.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {CurveV1AdapterStableNG} from "../../../../adapters/curve/CurveV1_StableNG.sol"; import {ICurvePoolStableNG} from "../../../../integrations/curve/ICurvePool_StableNG.sol"; @@ -12,33 +12,28 @@ import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; /// @notice U:[CRVNG]: Unit tests for Curve StableNG pool adapter contract CurveV1AdapterStablNGUnitTest is AdapterUnitTestHelper { CurveV1AdapterStableNG adapter; - PoolMock pool; + PoolMock curvePool; address token0; address token1; address token2; address lpToken; - uint256 token0Mask; - uint256 token1Mask; - uint256 token2Mask; - uint256 lpTokenMask; - function setUp() public { _setUp(); - (token0, token0Mask) = (tokens[0], 1); - (token1, token1Mask) = (tokens[1], 2); - (token2, token2Mask) = (tokens[2], 4); - (lpToken, lpTokenMask) = (tokens[3], 8); + token0 = tokens[0]; + token1 = tokens[1]; + token2 = tokens[2]; + lpToken = tokens[3]; address[] memory coins = new address[](3); coins[0] = token0; coins[1] = token1; coins[2] = token2; - pool = new PoolMock(PoolType.Stable, coins, new address[](0)); + curvePool = new PoolMock(PoolType.Stable, coins, new address[](0)); - adapter = new CurveV1AdapterStableNG(address(creditManager), address(pool), lpToken, address(0)); + adapter = new CurveV1AdapterStableNG(address(creditManager), address(curvePool), lpToken, address(0), false); assertEq(adapter.nCoins(), 3, "Incorrect nCoins"); } @@ -70,15 +65,12 @@ contract CurveV1AdapterStablNGUnitTest is AdapterUnitTestHelper { _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePoolStableNG.add_liquidity, (amounts, 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.add_liquidity(amounts, 500); - - assertEq(tokensToEnable, lpTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.add_liquidity(amounts, 500); + assertTrue(useSafePrices); } /// @notice U:[CRVNG-3]: `remove_liquidity` works as expected @@ -90,15 +82,12 @@ contract CurveV1AdapterStablNGUnitTest is AdapterUnitTestHelper { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePoolStableNG.remove_liquidity, (500, amounts)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.remove_liquidity(500, amounts); - - assertEq(tokensToEnable, token0Mask | token1Mask | token2Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity(500, amounts); + assertTrue(useSafePrices); } /// @notice U:[CRVNG-4]: `remove_liquidity_imbalance` works as expected @@ -110,14 +99,11 @@ contract CurveV1AdapterStablNGUnitTest is AdapterUnitTestHelper { _executesCall({ tokensToApprove: new address[](0), - tokensToValidate: new address[](0), callData: abi.encodeCall(ICurvePoolStableNG.remove_liquidity_imbalance, (amounts, 500)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.remove_liquidity_imbalance(amounts, 500); - - assertEq(tokensToEnable, token0Mask | token2Mask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.remove_liquidity_imbalance(amounts, 500); + assertTrue(useSafePrices); } } diff --git a/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.harness.sol b/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.harness.sol index 5a116d45..acc4ed91 100644 --- a/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.harness.sol +++ b/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.harness.sol @@ -1,18 +1,14 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {EqualizerRouterAdapter, Route} from "../../../../adapters/equalizer/EqualizerRouterAdapter.sol"; contract EqualizerRouterAdapterHarness is EqualizerRouterAdapter { constructor(address creditManager, address router) EqualizerRouterAdapter(creditManager, router) {} - function validatePath(Route[] memory routes) - external - view - returns (bool valid, address tokenIn, address tokenOut) - { - return _validatePath(routes); + function validatePath(Route[] memory routes) external view returns (bool valid, address tokenIn) { + (valid, tokenIn) = _validatePath(routes); } } diff --git a/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.unit.t.sol b/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.unit.t.sol index 1168072e..74d1ac84 100644 --- a/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/equalizer/EqualizerRouterAdapter.unit.t.sol @@ -1,24 +1,22 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IEqualizerRouter, Route} from "../../../../integrations/equalizer/IEqualizerRouter.sol"; import { - IEqualizerRouterAdapterEvents, - IEqualizerRouterAdapterExceptions, - EqualizerPoolStatus + IEqualizerRouterAdapter, + EqualizerPoolStatus, + EqualizerPool } from "../../../../interfaces/equalizer/IEqualizerRouterAdapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {EqualizerRouterAdapterHarness} from "./EqualizerRouterAdapter.harness.sol"; +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + /// @title Equalizer adapter unit test -/// @notice U:[EQLZ]: Unit tests for Equalizer swap router adapter -contract EqualizerRouterAdapterUnitTest is - AdapterUnitTestHelper, - IEqualizerRouterAdapterEvents, - IEqualizerRouterAdapterExceptions -{ +/// @notice U:[EQLZ-1]: Unit tests for Equalizer swap router adapter +contract EqualizerRouterAdapterUnitTest is AdapterUnitTestHelper { EqualizerRouterAdapterHarness adapter; address router; @@ -32,9 +30,8 @@ contract EqualizerRouterAdapterUnitTest is } /// @notice U:[EQLZ-1]: Constructor works as expected - function test_U_EQLZ_01_constructor_works_as_expected() public { + function test_U_EQLZ_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), router, "Incorrect targetContract"); } @@ -52,7 +49,7 @@ contract EqualizerRouterAdapterUnitTest is /// @notice U:[EQLZ-3]: `swapExactTokensForTokens` works as expected function test_U_EQLZ_03_swapExactTokensForTokens_works_as_expected() public { Route[] memory routes = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IEqualizerRouterAdapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapExactTokensForTokens(123, 456, routes, address(0), 789); @@ -60,18 +57,13 @@ contract EqualizerRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(IEqualizerRouter.swapExactTokensForTokens, (123, 456, routes, creditAccount, 789)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapExactTokensForTokens(123, 456, routes, address(0), 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapExactTokensForTokens(123, 456, routes, address(0), 789); + assertTrue(useSafePrices); } /// @notice U:[EQLZ-4]: `swapDiffTokensForTokens` works as expected @@ -79,7 +71,7 @@ contract EqualizerRouterAdapterUnitTest is deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); Route[] memory routes = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IEqualizerRouterAdapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapDiffTokensForTokens(diffInputAmount, 0.5e27, routes, 789); @@ -87,59 +79,69 @@ contract EqualizerRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( IEqualizerRouter.swapExactTokensForTokens, (diffInputAmount, diffInputAmount / 2, routes, creditAccount, 789) ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, routes, 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, routes, 789); + assertTrue(useSafePrices); } /// @notice U:[EQLZ-5]: `setPoolStatusBatch` works as expected function test_U_EQLZ_05_setPoolStatusBatch_works_as_expected() public { - EqualizerPoolStatus[] memory pools; + _setPoolsStatus(3, 0); + EqualizerPoolStatus[] memory pools = new EqualizerPoolStatus[](1); _revertsOnNonConfiguratorCaller(); adapter.setPoolStatusBatch(pools); + pools[0] = EqualizerPoolStatus(tokens[0], DUMB_ADDRESS, false, true); + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatusBatch(pools); + pools = new EqualizerPoolStatus[](2); pools[0] = EqualizerPoolStatus(tokens[0], tokens[1], false, false); pools[1] = EqualizerPoolStatus(tokens[1], tokens[2], true, true); + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + vm.expectEmit(true, true, false, true); - emit SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false, false); + emit IEqualizerRouterAdapter.SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false, false); vm.expectEmit(true, true, false, true); - emit SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true, true); + emit IEqualizerRouterAdapter.SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true, true); vm.prank(configurator); adapter.setPoolStatusBatch(pools); assertFalse(adapter.isPoolAllowed(tokens[0], tokens[1], false), "First pair incorrectly allowed"); assertTrue(adapter.isPoolAllowed(tokens[1], tokens[2], true), "Second pair incorrectly not allowed"); + + EqualizerPool[] memory allowedPools = adapter.supportedPools(); + + assertEq(allowedPools.length, 1, "Incorrect allowed pairs length"); + assertEq(allowedPools[0].token0, _min(tokens[1], tokens[2]), "Incorrect allowed pool token 0"); + assertEq(allowedPools[0].token1, _max(tokens[1], tokens[2]), "Incorrect allowed pool token 1"); + assertTrue(allowedPools[0].stable, "Incorrect allowed pools stable status"); } /// @notice U:[EQLZ-6]: `_validatePath` works as expected function test_U_EQLZ_06_validatePath_works_as_expected() public { bool isValid; address tokenIn; - address tokenOut; Route[] memory routes; // insane paths - (isValid,,) = adapter.validatePath(new Route[](0)); + (isValid,) = adapter.validatePath(new Route[](0)); assertFalse(isValid, "Empty path incorrectly valid"); - (isValid,,) = adapter.validatePath(new Route[](4)); + (isValid,) = adapter.validatePath(new Route[](4)); assertFalse(isValid, "Long path incorrectly valid"); // exhaustive search @@ -149,12 +151,11 @@ contract EqualizerRouterAdapterUnitTest is uint256 numCases = 1 << (pathLen - 1); for (uint256 mask; mask < numCases; ++mask) { _setPoolsStatus(pathLen - 1, mask); - (isValid, tokenIn, tokenOut) = adapter.validatePath(routes); + (isValid, tokenIn) = adapter.validatePath(routes); if (mask == numCases - 1) { assertTrue(isValid, "Path incorrectly invalid"); assertEq(tokenIn, tokens[0], "Incorrect tokenIn"); - assertEq(tokenOut, tokens[pathLen - 1], "Incorrect tokenOut"); } else { assertFalse(isValid, "Path incorrectly valid"); } @@ -166,7 +167,6 @@ contract EqualizerRouterAdapterUnitTest is function test_U_EQLZ_07_validatePath_filters_disjunct_paths() public { bool isValid; address tokenIn; - address tokenOut; Route[] memory routes; EqualizerPoolStatus[] memory pools = new EqualizerPoolStatus[](2); @@ -179,7 +179,7 @@ contract EqualizerRouterAdapterUnitTest is routes[0] = Route({from: tokens[0], to: tokens[1], stable: false}); routes[1] = Route({from: tokens[2], to: tokens[3], stable: false}); - (isValid, tokenIn, tokenOut) = adapter.validatePath(routes); + (isValid, tokenIn) = adapter.validatePath(routes); assertFalse(isValid, "Path incorrectly valid"); } diff --git a/contracts/test/unit/adapters/erc4626/ERC4626Adapter.unit.t.sol b/contracts/test/unit/adapters/erc4626/ERC4626Adapter.unit.t.sol index 10b605ed..cbe94768 100644 --- a/contracts/test/unit/adapters/erc4626/ERC4626Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/erc4626/ERC4626Adapter.unit.t.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IERC4626Referral} from "../../../../integrations/erc4626/IERC4626Referral.sol"; import {ERC4626Adapter} from "../../../../adapters/erc4626/ERC4626Adapter.sol"; +import {ERC4626ReferralAdapter} from "../../../../adapters/erc4626/ERC4626ReferralAdapter.sol"; import {Mellow4626VaultAdapter} from "../../../../adapters/mellow/Mellow4626VaultAdapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; @@ -16,32 +18,36 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { address asset; address vault; - - uint256 assetMask; - uint256 sharesMask; + address gateway; function setUp() public { _setUp(); - (asset, assetMask) = (tokens[0], 1); - (vault, sharesMask) = (tokens[1], 2); + asset = tokens[0]; + vault = tokens[1]; + gateway = tokens[2]; + vm.mockCall(vault, abi.encodeCall(IERC4626.asset, ()), abi.encode(asset)); - adapter = new ERC4626Adapter(address(creditManager), vault); + adapter = new ERC4626Adapter(address(creditManager), vault, address(0)); } /// @notice U:[TV-1]: Constructor works as expected function test_U_TV_01_constructor_works_as_expected() public { _readsTokenMask(asset); _readsTokenMask(vault); - adapter = new ERC4626Adapter(address(creditManager), vault); + adapter = new ERC4626Adapter(address(creditManager), vault, address(0)); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), vault, "Incorrect targetContract"); + assertEq(adapter.vault(), vault, "Incorrect vault"); + assertEq(adapter.asset(), asset, "Incorrect asset"); + + adapter = new ERC4626Adapter(address(creditManager), vault, gateway); + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), gateway, "Incorrect targetContract"); + assertEq(adapter.vault(), vault, "Incorrect vault"); assertEq(adapter.asset(), asset, "Incorrect asset"); - assertEq(adapter.assetMask(), assetMask, "Incorrect assetMask"); - assertEq(adapter.sharesMask(), sharesMask, "Incorrect sharesMask"); } /// @notice U:[TV-2]: Wrapper functions revert on wrong caller @@ -70,16 +76,12 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: asset, - tokenOut: vault, callData: abi.encodeCall(IERC4626.deposit, (1000, creditAccount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(1000, address(0)); - - assertEq(tokensToEnable, sharesMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.deposit(1000, address(0)); + assertFalse(useSafePrices); } /// @notice U:[TV-4]: `depositDiff` works as expected @@ -89,16 +91,12 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: asset, - tokenOut: vault, callData: abi.encodeCall(IERC4626.deposit, (diffInputAmount, creditAccount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, sharesMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? assetMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.depositDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } /// @notice U:[TV-5]: `mint` works as expected @@ -106,16 +104,12 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: asset, - tokenOut: vault, callData: abi.encodeCall(IERC4626.mint, (1000, creditAccount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.mint(1000, address(0)); - - assertEq(tokensToEnable, sharesMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.mint(1000, address(0)); + assertFalse(useSafePrices); } /// @notice U:[TV-6]: `withdraw` works as expected @@ -123,16 +117,12 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: vault, - tokenOut: asset, callData: abi.encodeCall(IERC4626.withdraw, (1000, creditAccount, creditAccount)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(1000, address(0), address(0)); - - assertEq(tokensToEnable, assetMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(1000, address(0), address(0)); + assertFalse(useSafePrices); } /// @notice U:[TV-7]: `redeem` works as expected @@ -140,16 +130,12 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: vault, - tokenOut: asset, callData: abi.encodeCall(IERC4626.redeem, (1000, creditAccount, creditAccount)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeem(1000, address(0), address(0)); - - assertEq(tokensToEnable, assetMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.redeem(1000, address(0), address(0)); + assertFalse(useSafePrices); } /// @notice U:[TV-8]: `redeemDiff` works as expected @@ -159,32 +145,41 @@ contract ERC4626AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: vault, - tokenOut: asset, callData: abi.encodeCall(IERC4626.redeem, (diffInputAmount, creditAccount, creditAccount)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeemDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, assetMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? sharesMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.redeemDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } - /// @notice U:[TV-9]: withdrawal functions restricted for Mellow adapter - function test_U_TV_09_withdrawal_functions_restricted_for_mellow() public diffTestCases { - adapter = new Mellow4626VaultAdapter(address(creditManager), vault); + function test_U_TV_09_referral_adapter_works_as_expected() public diffTestCases { + deal({token: asset, to: creditAccount, give: diffMintedAmount}); + + adapter = new ERC4626ReferralAdapter(address(creditManager), vault, 1); - vm.expectRevert(NotImplementedException.selector); + _executesSwap({ + tokenIn: asset, + callData: abi.encodeCall(IERC4626Referral.deposit, (1000, creditAccount, 1)), + requiresApproval: true + }); vm.prank(creditFacade); - adapter.withdraw(1000, address(0), address(0)); + adapter.deposit(1000, address(0)); - vm.expectRevert(NotImplementedException.selector); + _executesSwap({ + tokenIn: asset, + callData: abi.encodeCall(IERC4626Referral.mint, (1000, creditAccount, 1)), + requiresApproval: true + }); vm.prank(creditFacade); - adapter.redeem(1000, address(0), address(0)); + adapter.mint(1000, address(0)); - vm.expectRevert(NotImplementedException.selector); + _executesSwap({ + tokenIn: asset, + callData: abi.encodeCall(IERC4626Referral.deposit, (diffInputAmount, creditAccount, 1)), + requiresApproval: true + }); vm.prank(creditFacade); - adapter.redeemDiff(1000); + adapter.depositDiff(diffLeftoverAmount); } } diff --git a/contracts/test/unit/adapters/fluid/FluidDexAdapter.unit.t.sol b/contracts/test/unit/adapters/fluid/FluidDexAdapter.unit.t.sol new file mode 100644 index 00000000..59f50419 --- /dev/null +++ b/contracts/test/unit/adapters/fluid/FluidDexAdapter.unit.t.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {FluidDexAdapter} from "../../../../adapters/fluid/FluidDexAdapter.sol"; +import {IFluidDex, ConstantViews} from "../../../../integrations/fluid/IFluidDex.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; +import {RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol"; + +/// @title FluidDex adapter unit test +/// @notice U:[FDEX]: Unit tests for FluidDex adapter +contract FluidDexAdapterUnitTest is AdapterUnitTestHelper { + FluidDexAdapter adapter; + + address token0; + address token1; + address fluidDex; + + function setUp() public { + _setUp(); + + token0 = tokens[0]; + token1 = tokens[1]; + fluidDex = tokens[2]; + + // Mock the constantsView function to return the tokens + ConstantViews memory constantViews; + constantViews.token0 = token0; + constantViews.token1 = token1; + vm.mockCall(fluidDex, abi.encodeCall(IFluidDex.constantsView, ()), abi.encode(constantViews)); + + adapter = new FluidDexAdapter(address(creditManager), fluidDex); + } + + /// @notice U:[FDEX-1]: Constructor works as expected + function test_U_FDEX_01_constructor_works_as_expected() public { + _readsTokenMask(token0); + _readsTokenMask(token1); + + // Mock the constantsView function to return the tokens + ConstantViews memory constantViews; + constantViews.token0 = token0; + constantViews.token1 = token1; + vm.mockCall(fluidDex, abi.encodeCall(IFluidDex.constantsView, ()), abi.encode(constantViews)); + + adapter = new FluidDexAdapter(address(creditManager), fluidDex); + + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), fluidDex, "Incorrect targetContract"); + assertEq(adapter.token0(), token0, "Incorrect token0"); + assertEq(adapter.token1(), token1, "Incorrect token1"); + } + + /// @notice U:[FDEX-2]: Wrapper functions revert on wrong caller + function test_U_FDEX_02_wrapper_functions_revert_on_wrong_caller() public { + _revertsOnNonFacadeCaller(); + adapter.swapIn(true, 0, 0, address(0)); + + _revertsOnNonFacadeCaller(); + adapter.swapInDiff(true, 0, 0); + } + + /// @notice U:[FDEX-3]: `swapIn()` works as expected for token0 to token1 + function test_U_FDEX_03_swapIn_works_as_expected_0to1() public { + uint256 amountIn = 1000; + uint256 amountOutMin = 900; + bool swap0to1 = true; + + _readsActiveAccount(); + _executesSwap({ + tokenIn: token0, + callData: abi.encodeCall(IFluidDex.swapIn, (swap0to1, amountIn, amountOutMin, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.swapIn(swap0to1, amountIn, amountOutMin, address(0)); + assertTrue(useSafePrices); + } + + /// @notice U:[FDEX-4]: `swapIn()` works as expected for token1 to token0 + function test_U_FDEX_04_swapIn_works_as_expected_1to0() public { + uint256 amountIn = 1000; + uint256 amountOutMin = 900; + bool swap0to1 = false; + + _readsActiveAccount(); + _executesSwap({ + tokenIn: token1, + callData: abi.encodeCall(IFluidDex.swapIn, (swap0to1, amountIn, amountOutMin, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.swapIn(swap0to1, amountIn, amountOutMin, address(0)); + assertTrue(useSafePrices); + } + + /// @notice U:[FDEX-5]: `swapInDiff()` works as expected for token0 to token1 + function test_U_FDEX_05_swapInDiff_works_as_expected_0to1() public diffTestCases { + uint256 rateMinRAY = 9 * (RAY / 10); // 0.9 * RAY, equivalent to 90% of the input amount + bool swap0to1 = true; + deal({token: token0, to: creditAccount, give: diffMintedAmount}); + + uint256 expectedAmountOutMin = (diffInputAmount * rateMinRAY) / RAY; + + _readsActiveAccount(); + _executesSwap({ + tokenIn: token0, + callData: abi.encodeCall(IFluidDex.swapIn, (swap0to1, diffInputAmount, expectedAmountOutMin, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.swapInDiff(swap0to1, diffLeftoverAmount, rateMinRAY); + assertTrue(useSafePrices); + } + + /// @notice U:[FDEX-6]: `swapInDiff()` works as expected for token1 to token0 + function test_U_FDEX_06_swapInDiff_works_as_expected_1to0() public diffTestCases { + uint256 rateMinRAY = 9 * (RAY / 10); // 0.9 * RAY, equivalent to 90% of the input amount + bool swap0to1 = false; + deal({token: token1, to: creditAccount, give: diffMintedAmount}); + + uint256 expectedAmountOutMin = (diffInputAmount * rateMinRAY) / RAY; + + _readsActiveAccount(); + _executesSwap({ + tokenIn: token1, + callData: abi.encodeCall(IFluidDex.swapIn, (swap0to1, diffInputAmount, expectedAmountOutMin, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.swapInDiff(swap0to1, diffLeftoverAmount, rateMinRAY); + assertTrue(useSafePrices); + } + + /// @notice U:[FDEX-7]: `swapInDiff()` returns false if balance <= leftoverAmount + function test_U_FDEX_07_swapInDiff_returns_false_if_balance_too_low() public { + uint256 balance = 1000; + uint256 leftoverAmount = 1000; // Equal to balance + bool swap0to1 = true; + + deal({token: token0, to: creditAccount, give: balance}); + + _readsActiveAccount(); + vm.prank(creditFacade); + bool useSafePrices = adapter.swapInDiff(swap0to1, leftoverAmount, 0); + assertFalse(useSafePrices); + + // Test with balance less than leftoverAmount + leftoverAmount = 1001; + vm.prank(creditFacade); + useSafePrices = adapter.swapInDiff(swap0to1, leftoverAmount, 0); + assertFalse(useSafePrices); + } +} diff --git a/contracts/test/unit/adapters/infrared/InfraredVaultAdapter.unit.t.sol b/contracts/test/unit/adapters/infrared/InfraredVaultAdapter.unit.t.sol new file mode 100644 index 00000000..0416bf01 --- /dev/null +++ b/contracts/test/unit/adapters/infrared/InfraredVaultAdapter.unit.t.sol @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {InfraredVaultAdapter} from "../../../../adapters/infrared/InfraredVaultAdapter.sol"; +import {IInfraredVault, UserReward} from "../../../../integrations/infrared/IInfraredVault.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; + +/// @title InfraredVault adapter unit test +/// @notice U:[IRV]: Unit tests for InfraredVault adapter +contract InfraredVaultAdapterUnitTest is AdapterUnitTestHelper { + InfraredVaultAdapter adapter; + + address infraredVault; + address stakingToken; + address stakedPhantomToken; + address[] rewardTokens; + + function setUp() public { + _setUp(); + + stakingToken = tokens[0]; + stakedPhantomToken = tokens[1]; + infraredVault = tokens[2]; + + // Setup multiple reward tokens + rewardTokens = new address[](3); + rewardTokens[0] = tokens[3]; + rewardTokens[1] = tokens[4]; + rewardTokens[2] = tokens[5]; + + vm.mockCall(infraredVault, abi.encodeCall(IInfraredVault.stakingToken, ()), abi.encode(stakingToken)); + vm.mockCall(infraredVault, abi.encodeCall(IInfraredVault.getAllRewardTokens, ()), abi.encode(rewardTokens)); + + adapter = new InfraredVaultAdapter(address(creditManager), infraredVault, stakedPhantomToken); + } + + /// @notice U:[IRV-1]: Constructor works as expected + function test_U_IRV_01_constructor_works_as_expected() public { + _readsTokenMask(stakingToken); + _readsTokenMask(stakedPhantomToken); + + // Check that the adapter registers all reward tokens + for (uint256 i = 0; i < rewardTokens.length; i++) { + _readsTokenMask(rewardTokens[i]); + } + + adapter = new InfraredVaultAdapter(address(creditManager), infraredVault, stakedPhantomToken); + + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), infraredVault, "Incorrect targetContract"); + assertEq(adapter.stakingToken(), stakingToken, "Incorrect stakingToken"); + assertEq(adapter.stakedPhantomToken(), stakedPhantomToken, "Incorrect stakedPhantomToken"); + } + + /// @notice U:[IRV-2]: Wrapper functions revert on wrong caller + function test_U_IRV_02_wrapper_functions_revert_on_wrong_caller() public { + _revertsOnNonFacadeCaller(); + adapter.stake(0); + + _revertsOnNonFacadeCaller(); + adapter.stakeDiff(0); + + _revertsOnNonFacadeCaller(); + adapter.getReward(); + + _revertsOnNonFacadeCaller(); + adapter.withdraw(0); + + _revertsOnNonFacadeCaller(); + adapter.withdrawDiff(0); + + _revertsOnNonFacadeCaller(); + adapter.exit(); + + _revertsOnNonFacadeCaller(); + adapter.withdrawPhantomToken(address(0), 0); + } + + // ----- // + // STAKE // + // ----- // + + /// @notice U:[IRV-3]: `stake` works as expected + function test_U_IRV_03_stake_works_as_expected() public { + _executesSwap({ + tokenIn: stakingToken, + callData: abi.encodeCall(IInfraredVault.stake, (1000)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.stake(1000); + assertFalse(useSafePrices); + } + + /// @notice U:[IRV-4]: `stakeDiff` works as expected + function test_U_IRV_04_stakeDiff_works_as_expected() public diffTestCases { + deal({token: stakingToken, to: creditAccount, give: diffMintedAmount}); + _readsActiveAccount(); + _executesSwap({ + tokenIn: stakingToken, + callData: abi.encodeCall(IInfraredVault.stake, (diffInputAmount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.stakeDiff(diffLeftoverAmount); + assertFalse(useSafePrices); + } + + // ----- // + // CLAIM // + // ----- // + + /// @notice U:[IRV-5]: `getReward` works as expected + function test_U_IRV_05_getReward_works_as_expected() public { + _executesCall({tokensToApprove: new address[](0), callData: abi.encodeCall(IInfraredVault.getReward, ())}); + vm.prank(creditFacade); + bool useSafePrices = adapter.getReward(); + assertFalse(useSafePrices); + } + + // -------- // + // WITHDRAW // + // -------- // + + /// @notice U:[IRV-6]: `withdraw` works as expected + function test_U_IRV_06_withdraw_works_as_expected() public { + _executesSwap({ + tokenIn: stakedPhantomToken, + callData: abi.encodeCall(IInfraredVault.withdraw, (1000)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdraw(1000); + assertFalse(useSafePrices); + } + + /// @notice U:[IRV-7]: `withdrawDiff` works as expected + function test_U_IRV_07_withdrawDiff_works_as_expected() public diffTestCases { + deal({token: stakedPhantomToken, to: creditAccount, give: diffMintedAmount}); + _readsActiveAccount(); + _executesSwap({ + tokenIn: stakedPhantomToken, + callData: abi.encodeCall(IInfraredVault.withdraw, (diffInputAmount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdrawDiff(diffLeftoverAmount); + assertFalse(useSafePrices); + } + + /// @notice U:[IRV-8]: `exit` works as expected + function test_U_IRV_08_exit_works_as_expected() public { + _executesCall({tokensToApprove: new address[](0), callData: abi.encodeCall(IInfraredVault.exit, ())}); + vm.prank(creditFacade); + bool useSafePrices = adapter.exit(); + assertFalse(useSafePrices); + } + + /// @notice U:[IRV-9]: `withdrawPhantomToken` works as expected + function test_U_IRV_09_withdrawPhantomToken_works_as_expected() public { + vm.expectRevert(IPhantomTokenAdapter.IncorrectStakedPhantomTokenException.selector); + vm.prank(creditFacade); + adapter.withdrawPhantomToken(address(0), 1000); + + _executesSwap({ + tokenIn: stakedPhantomToken, + callData: abi.encodeCall(IInfraredVault.withdraw, (1000)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdrawPhantomToken(stakedPhantomToken, 1000); + assertFalse(useSafePrices); + } + + /// @notice U:[IRV-11]: `serialize` works as expected + function test_U_IRV_11_serialize_works_as_expected() public view { + bytes memory serialized = adapter.serialize(); + ( + address serializedCreditManager, + address serializedTargetContract, + address serializedStakingToken, + address serializedStakedToken + ) = abi.decode(serialized, (address, address, address, address)); + + assertEq(serializedCreditManager, address(creditManager), "Incorrect serialized creditManager"); + assertEq(serializedTargetContract, infraredVault, "Incorrect serialized targetContract"); + assertEq(serializedStakingToken, stakingToken, "Incorrect serialized stakingToken"); + assertEq(serializedStakedToken, stakedPhantomToken, "Incorrect serialized stakedPhantomToken"); + } +} diff --git a/contracts/test/unit/adapters/lido/LidoV1Adapter.unit.t.sol b/contracts/test/unit/adapters/lido/LidoV1Adapter.unit.t.sol index 0c49dc0e..e6399542 100644 --- a/contracts/test/unit/adapters/lido/LidoV1Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/lido/LidoV1Adapter.unit.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; -import {AP_TREASURY} from "@gearbox-protocol/core-v3/contracts/interfaces/IAddressProviderV3.sol"; import {LidoV1Adapter} from "../../../../adapters/lido/LidoV1.sol"; import {LidoV1Gateway} from "../../../../helpers/lido/LidoV1_WETHGateway.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; @@ -19,20 +18,18 @@ contract LidoV1AdapterUnitTest is AdapterUnitTestHelper { address weth; address stETH; - uint256 wethMask; - uint256 stETHMask; - function setUp() public { _setUp(); gateway = makeAddr("LIDO_GATEWAY"); treasury = makeAddr("TREASURY"); + address pool = makeAddr("POOL"); - vm.prank(configurator); - addressProvider.setAddress(AP_TREASURY, treasury, false); + vm.mockCall(address(creditManager), abi.encodeWithSignature("pool()"), abi.encode(pool)); + vm.mockCall(pool, abi.encodeWithSignature("treasury()"), abi.encode(treasury)); - (weth, wethMask) = (tokens[0], 1); - (stETH, stETHMask) = (tokens[1], 2); + weth = tokens[0]; + stETH = tokens[1]; vm.mockCall(gateway, abi.encodeWithSignature("weth()"), abi.encode(weth)); vm.mockCall(gateway, abi.encodeWithSignature("stETH()"), abi.encode(stETH)); @@ -47,12 +44,9 @@ contract LidoV1AdapterUnitTest is AdapterUnitTestHelper { adapter = new LidoV1Adapter(address(creditManager), gateway); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), gateway, "Incorrect targetContract"); assertEq(adapter.weth(), weth, "Incorrect weth"); assertEq(adapter.stETH(), stETH, "Incorrect stETH"); - assertEq(adapter.wethTokenMask(), wethMask, "Incorrect wethMask"); - assertEq(adapter.stETHTokenMask(), stETHMask, "Incorrect stETHMask"); assertEq(adapter.treasury(), treasury, "Incorrect treasury"); } @@ -69,16 +63,12 @@ contract LidoV1AdapterUnitTest is AdapterUnitTestHelper { function test_U_LDO1_03_submit_works_as_expected() public { _executesSwap({ tokenIn: weth, - tokenOut: stETH, callData: abi.encodeCall(LidoV1Gateway.submit, (1000, treasury)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.submit(1000); - - assertEq(tokensToEnable, stETHMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.submit(1000); + assertFalse(useSafePrices); } /// @notice U:[LDO1-4]: `submitDiff` works as expected @@ -88,15 +78,11 @@ contract LidoV1AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: weth, - tokenOut: stETH, callData: abi.encodeCall(LidoV1Gateway.submit, (diffInputAmount, treasury)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.submitDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, stETHMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? wethMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.submitDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } } diff --git a/contracts/test/unit/adapters/lido/WstETHV1Adapter.unit.t.sol b/contracts/test/unit/adapters/lido/WstETHV1Adapter.unit.t.sol index 8681b78a..f82aa71c 100644 --- a/contracts/test/unit/adapters/lido/WstETHV1Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/lido/WstETHV1Adapter.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {WstETHV1Adapter} from "../../../../adapters/lido/WstETHV1.sol"; import {IwstETH, IwstETHGetters} from "../../../../integrations/lido/IwstETH.sol"; @@ -15,14 +15,12 @@ contract WstETHV1AdapterUnitTest is AdapterUnitTestHelper { address stETH; address wstETH; - uint256 stETHMask; - uint256 wstETHMask; - function setUp() public { _setUp(); - (stETH, stETHMask) = (tokens[0], 1); - (wstETH, wstETHMask) = (tokens[1], 2); + stETH = tokens[0]; + wstETH = tokens[1]; + vm.mockCall(wstETH, abi.encodeCall(IwstETHGetters.stETH, ()), abi.encode(stETH)); adapter = new WstETHV1Adapter(address(creditManager), wstETH); @@ -35,11 +33,8 @@ contract WstETHV1AdapterUnitTest is AdapterUnitTestHelper { adapter = new WstETHV1Adapter(address(creditManager), wstETH); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), wstETH, "Incorrect targetContract"); assertEq(adapter.stETH(), stETH, "Incorrect stETH"); - assertEq(adapter.stETHTokenMask(), stETHMask, "Incorrect stETHMask"); - assertEq(adapter.wstETHTokenMask(), wstETHMask, "Incorrect wstETHMask"); } /// @notice U:[LDO1W-2]: Wrapper functions revert on wrong caller @@ -59,18 +54,10 @@ contract WstETHV1AdapterUnitTest is AdapterUnitTestHelper { /// @notice U:[LDO1W-3]: `wrap` works as expected function test_U_LDO1W_03_wrap_works_as_expected() public { - _executesSwap({ - tokenIn: stETH, - tokenOut: wstETH, - callData: abi.encodeCall(IwstETH.wrap, (1000)), - requiresApproval: true, - validatesTokens: false - }); + _executesSwap({tokenIn: stETH, callData: abi.encodeCall(IwstETH.wrap, (1000)), requiresApproval: true}); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.wrap(1000); - - assertEq(tokensToEnable, wstETHMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.wrap(1000); + assertFalse(useSafePrices); } /// @notice U:[LDO1W-4]: `wrapDiff` works as expected @@ -80,32 +67,20 @@ contract WstETHV1AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: stETH, - tokenOut: wstETH, callData: abi.encodeCall(IwstETH.wrap, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.wrapDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, wstETHMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? stETHMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.wrapDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } /// @notice U:[LDO1W-5]: `unwrap` works as expected function test_U_LDO1W_05_unwrap_works_as_expected() public { - _executesSwap({ - tokenIn: wstETH, - tokenOut: stETH, - callData: abi.encodeCall(IwstETH.unwrap, (1000)), - requiresApproval: false, - validatesTokens: false - }); + _executesSwap({tokenIn: wstETH, callData: abi.encodeCall(IwstETH.unwrap, (1000)), requiresApproval: false}); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.unwrap(1000); - - assertEq(tokensToEnable, stETHMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.unwrap(1000); + assertFalse(useSafePrices); } /// @notice U:[LDO1W-6]: `unwrapDiff` works as expected @@ -115,15 +90,11 @@ contract WstETHV1AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: wstETH, - tokenOut: stETH, callData: abi.encodeCall(IwstETH.unwrap, (diffInputAmount)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.unwrapDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, stETHMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? wstETHMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.unwrapDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } } diff --git a/contracts/test/unit/adapters/mellow/Mellow4626VaultAdapter.unit.t.sol b/contracts/test/unit/adapters/mellow/Mellow4626VaultAdapter.unit.t.sol new file mode 100644 index 00000000..72ea83f5 --- /dev/null +++ b/contracts/test/unit/adapters/mellow/Mellow4626VaultAdapter.unit.t.sol @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {Mellow4626VaultAdapter} from "../../../../adapters/mellow/Mellow4626VaultAdapter.sol"; +import {IMellowMultiVault} from "../../../../integrations/mellow/IMellowMultiVault.sol"; +import {IMellow4626VaultAdapter} from "../../../../interfaces/mellow/IMellow4626VaultAdapter.sol"; +import {MellowWithdrawalPhantomToken} from "../../../../helpers/mellow/MellowWithdrawalPhantomToken.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; + +/// @title Mellow4626Vault adapter unit test +/// @notice U:[M4626]: Unit tests for Mellow4626Vault adapter +contract Mellow4626VaultAdapterUnitTest is AdapterUnitTestHelper { + Mellow4626VaultAdapter adapter; + + address vault; + address asset; + address stakedPhantomToken; + + function setUp() public { + _setUp(); + + asset = tokens[0]; + vault = tokens[1]; + stakedPhantomToken = tokens[2]; + + vm.mockCall(vault, abi.encodeCall(IERC4626.asset, ()), abi.encode(asset)); + vm.mockCall(stakedPhantomToken, abi.encodeWithSignature("multiVault()"), abi.encode(vault)); + + adapter = new Mellow4626VaultAdapter(address(creditManager), vault, stakedPhantomToken); + } + + /// @notice U:[M4626-1]: Constructor works as expected + function test_U_M4626_01_constructor_works_as_expected() public { + _readsTokenMask(asset); + _readsTokenMask(vault); + _readsTokenMask(stakedPhantomToken); + + adapter = new Mellow4626VaultAdapter(address(creditManager), vault, stakedPhantomToken); + + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), vault, "Incorrect targetContract"); + assertEq(adapter.vault(), vault, "Incorrect vault"); + assertEq(adapter.asset(), asset, "Incorrect asset"); + } + + /// @notice U:[M4626-2]: Constructor reverts on invalid multivault + function test_U_M4626_02_constructor_reverts_on_invalid_multivault() public { + address wrongVault = makeAddr("WRONG_VAULT"); + vm.mockCall(stakedPhantomToken, abi.encodeWithSignature("multiVault()"), abi.encode(wrongVault)); + + vm.expectRevert(IMellow4626VaultAdapter.InvalidMultiVaultException.selector); + new Mellow4626VaultAdapter(address(creditManager), vault, stakedPhantomToken); + } + + /// @notice U:[M4626-3]: Wrapper functions revert on wrong caller + function test_U_M4626_03_wrapper_functions_revert_on_wrong_caller() public { + _revertsOnNonFacadeCaller(); + adapter.deposit(0, address(0)); + + _revertsOnNonFacadeCaller(); + adapter.depositDiff(0); + + _revertsOnNonFacadeCaller(); + adapter.mint(0, address(0)); + + _revertsOnNonFacadeCaller(); + adapter.withdraw(0, address(0), address(0)); + + _revertsOnNonFacadeCaller(); + adapter.redeem(0, address(0), address(0)); + + _revertsOnNonFacadeCaller(); + adapter.redeemDiff(0); + } + + /// @notice U:[M4626-4]: `deposit` works as expected + function test_U_M4626_04_deposit_works_as_expected() public { + // Test normal deposit + vm.mockCall(vault, abi.encodeCall(IMellowMultiVault.depositWhitelist, ()), abi.encode(false)); + _readsActiveAccount(); + _executesSwap({ + tokenIn: asset, + callData: abi.encodeCall(IERC4626.deposit, (1000, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.deposit(1000, address(0)); + assertFalse(useSafePrices); + } + + /// @notice U:[M4626-5]: `depositDiff` works as expected + function test_U_M4626_05_depositDiff_works_as_expected() public diffTestCases { + deal({token: asset, to: creditAccount, give: diffMintedAmount}); + + // Test normal depositDiff + vm.mockCall(vault, abi.encodeCall(IMellowMultiVault.depositWhitelist, ()), abi.encode(false)); + _readsActiveAccount(); + _executesSwap({ + tokenIn: asset, + callData: abi.encodeCall(IERC4626.deposit, (diffInputAmount, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.depositDiff(diffLeftoverAmount); + assertFalse(useSafePrices); + } + + /// @notice U:[M4626-6]: `mint` works as expected + function test_U_M4626_06_mint_works_as_expected() public { + // Test normal mint + vm.mockCall(vault, abi.encodeCall(IMellowMultiVault.depositWhitelist, ()), abi.encode(false)); + _readsActiveAccount(); + _executesSwap({ + tokenIn: asset, + callData: abi.encodeCall(IERC4626.mint, (1000, creditAccount)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.mint(1000, address(0)); + assertFalse(useSafePrices); + } + + /// @notice U:[M4626-7]: `withdraw` works as expected and returns true for safe prices + function test_U_M4626_07_withdraw_works_as_expected() public { + _readsActiveAccount(); + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IERC4626.withdraw, (1000, creditAccount, creditAccount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdraw(1000, address(0), address(0)); + assertTrue(useSafePrices, "Should use safe prices for withdrawals"); + } + + /// @notice U:[M4626-8]: `redeem` works as expected and returns true for safe prices + function test_U_M4626_08_redeem_works_as_expected() public { + _readsActiveAccount(); + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IERC4626.redeem, (1000, creditAccount, creditAccount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.redeem(1000, address(0), address(0)); + assertTrue(useSafePrices, "Should use safe prices for redemptions"); + } + + /// @notice U:[M4626-9]: `redeemDiff` works as expected and returns true for safe prices + function test_U_M4626_09_redeemDiff_works_as_expected() public diffTestCases { + deal({token: vault, to: creditAccount, give: diffMintedAmount}); + + _readsActiveAccount(); + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IERC4626.redeem, (diffInputAmount, creditAccount, creditAccount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.redeemDiff(diffLeftoverAmount); + assertTrue(useSafePrices, "Should use safe prices for redemptions"); + } + + /// @notice U:[M4626-10]: `serialize` works as expected + function test_U_M4626_10_serialize_works_as_expected() public view { + bytes memory serialized = adapter.serialize(); + (address cm, address tc, address v, address a) = abi.decode(serialized, (address, address, address, address)); + + assertEq(cm, address(creditManager), "Incorrect credit manager in serialized data"); + assertEq(tc, vault, "Incorrect target contract in serialized data"); + assertEq(v, vault, "Incorrect vault in serialized data"); + assertEq(a, asset, "Incorrect asset in serialized data"); + } +} diff --git a/contracts/test/unit/adapters/mellow/MellowClaimerAdapter.unit.t.sol b/contracts/test/unit/adapters/mellow/MellowClaimerAdapter.unit.t.sol new file mode 100644 index 00000000..e579a05d --- /dev/null +++ b/contracts/test/unit/adapters/mellow/MellowClaimerAdapter.unit.t.sol @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {MellowClaimerAdapter} from "../../../../adapters/mellow/MellowClaimerAdapter.sol"; +import {IMellowClaimer} from "../../../../integrations/mellow/IMellowClaimer.sol"; +import {IMellowMultiVault, Subvault, MellowProtocol} from "../../../../integrations/mellow/IMellowMultiVault.sol"; +import {IEigenLayerWithdrawalQueue} from "../../../../integrations/mellow/IMellowMultiVault.sol"; +import { + IMellowClaimerAdapter, + IMellowClaimerAdapterExceptions, + MellowMultiVaultStatus +} from "../../../../interfaces/mellow/IMellowClaimerAdapter.sol"; +import {MellowWithdrawalPhantomToken} from "../../../../helpers/mellow/MellowWithdrawalPhantomToken.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +/// @title MellowClaimerAdapter unit test +/// @notice U:[MCA]: Unit tests for MellowClaimerAdapter +contract MellowClaimerAdapterUnitTest is AdapterUnitTestHelper, IMellowClaimerAdapterExceptions { + MellowClaimerAdapter adapter; + + address claimer; + address multivault1; + address multivault2; + address asset1; + address asset2; + address stakedPhantomToken1; + address stakedPhantomToken2; + address withdrawalQueue; + + function setUp() public { + _setUp(); + + claimer = makeAddr("CLAIMER"); + multivault1 = tokens[0]; + multivault2 = tokens[1]; + asset1 = tokens[2]; + asset2 = tokens[3]; + stakedPhantomToken1 = tokens[4]; + stakedPhantomToken2 = tokens[5]; + withdrawalQueue = makeAddr("WITHDRAWAL_QUEUE"); + + // Mock multivault1 + vm.mockCall(multivault1, abi.encodeCall(IERC4626.asset, ()), abi.encode(asset1)); + vm.mockCall(multivault1, abi.encodeCall(IMellowMultiVault.subvaultsCount, ()), abi.encode(1)); + vm.mockCall( + multivault1, + abi.encodeCall(IMellowMultiVault.subvaultAt, (0)), + abi.encode( + Subvault({vault: tokens[6], withdrawalQueue: withdrawalQueue, protocol: MellowProtocol.EIGEN_LAYER}) + ) + ); + + // Mock multivault2 + vm.mockCall(multivault2, abi.encodeCall(IERC4626.asset, ()), abi.encode(asset2)); + vm.mockCall(multivault2, abi.encodeCall(IMellowMultiVault.subvaultsCount, ()), abi.encode(1)); + vm.mockCall( + multivault2, + abi.encodeCall(IMellowMultiVault.subvaultAt, (0)), + abi.encode( + Subvault({vault: tokens[7], withdrawalQueue: withdrawalQueue, protocol: MellowProtocol.EIGEN_LAYER}) + ) + ); + + // Mock phantom tokens + vm.mockCall(stakedPhantomToken1, abi.encodeWithSignature("multiVault()"), abi.encode(multivault1)); + vm.mockCall(stakedPhantomToken1, abi.encodeWithSignature("getPhantomTokenInfo()"), abi.encode(claimer, asset1)); + vm.mockCall(stakedPhantomToken2, abi.encodeWithSignature("multiVault()"), abi.encode(multivault2)); + vm.mockCall(stakedPhantomToken2, abi.encodeWithSignature("getPhantomTokenInfo()"), abi.encode(claimer, asset2)); + + // Mock withdrawal queue + uint256[] memory indices = new uint256[](2); + indices[0] = 0; + indices[1] = 1; + vm.mockCall( + withdrawalQueue, + abi.encodeCall(IEigenLayerWithdrawalQueue.getAccountData, (multivault1, type(uint256).max, 0, 0, 0)), + abi.encode(0, indices, 0) + ); + vm.mockCall( + withdrawalQueue, + abi.encodeCall(IEigenLayerWithdrawalQueue.getAccountData, (multivault2, type(uint256).max, 0, 0, 0)), + abi.encode(0, indices, 0) + ); + + indices = new uint256[](2); + indices[0] = 0; + indices[1] = 2; + vm.mockCall( + withdrawalQueue, + abi.encodeCall(IEigenLayerWithdrawalQueue.getAccountData, (creditAccount, type(uint256).max, 0, 0, 0)), + abi.encode(0, indices, 0) + ); + vm.mockCall( + withdrawalQueue, + abi.encodeCall(IEigenLayerWithdrawalQueue.getAccountData, (creditAccount, type(uint256).max, 0, 0, 0)), + abi.encode(0, indices, 0) + ); + + adapter = new MellowClaimerAdapter(address(creditManager), claimer); + } + + /// @notice U:[MCA-1]: Constructor works as expected + function test_U_MCA_01_constructor_works_as_expected() public { + adapter = new MellowClaimerAdapter(address(creditManager), claimer); + + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), claimer, "Incorrect targetContract"); + assertEq(adapter.allowedMultiVaults().length, 0, "Should have no allowed multivaults initially"); + } + + /// @notice U:[MCA-2]: Wrapper functions revert on wrong caller + function test_U_MCA_02_wrapper_functions_revert_on_wrong_caller() public { + uint256[] memory subvaultIndices = new uint256[](0); + uint256[][] memory indices = new uint256[][](0); + + _revertsOnNonFacadeCaller(); + adapter.multiAccept(multivault1, subvaultIndices, indices); + + _revertsOnNonFacadeCaller(); + adapter.multiAcceptAndClaim(multivault1, subvaultIndices, indices, address(0), 0); + + _revertsOnNonFacadeCaller(); + adapter.withdrawPhantomToken(stakedPhantomToken1, 0); + + _revertsOnNonFacadeCaller(); + adapter.depositPhantomToken(stakedPhantomToken1, 0); + } + + /// @notice U:[MCA-3]: `multiAccept` works as expected + function test_U_MCA_03_multiAccept_works_as_expected() public { + // Setup allowed multivault + MellowMultiVaultStatus[] memory multivaults = new MellowMultiVaultStatus[](1); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, true); + + _readsTokenMask(stakedPhantomToken1); + _readsTokenMask(asset1); + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + + uint256[] memory subvaultIndices = new uint256[](1); + subvaultIndices[0] = 0; + uint256[][] memory indices = new uint256[][](1); + indices[0] = new uint256[](2); + indices[0][0] = 0; + indices[0][1] = 1; + + // Test with non-allowed multivault + vm.expectRevert(MultiVaultNotAllowedException.selector); + vm.prank(creditFacade); + adapter.multiAccept(multivault2, subvaultIndices, indices); + + // Test with allowed multivault + _executesCall({ + tokensToApprove: new address[](0), + callData: abi.encodeCall( + IMellowClaimer.multiAcceptAndClaim, (multivault1, subvaultIndices, indices, address(0), 0) + ) + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.multiAccept(multivault1, subvaultIndices, indices); + assertFalse(useSafePrices); + } + + /// @notice U:[MCA-4]: `multiAcceptAndClaim` works as expected + function test_U_MCA_04_multiAcceptAndClaim_works_as_expected() public { + // Setup allowed multivault + MellowMultiVaultStatus[] memory multivaults = new MellowMultiVaultStatus[](1); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, true); + _readsTokenMask(stakedPhantomToken1); + _readsTokenMask(asset1); + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + + uint256[] memory subvaultIndices = new uint256[](1); + subvaultIndices[0] = 0; + uint256[][] memory indices = new uint256[][](1); + indices[0] = new uint256[](2); + indices[0][0] = 0; + indices[0][1] = 1; + + // Test with non-allowed multivault + vm.expectRevert(MultiVaultNotAllowedException.selector); + vm.prank(creditFacade); + adapter.multiAcceptAndClaim(multivault2, subvaultIndices, indices, address(0), 1000); + + // Test successful claim + _readsActiveAccount(); + deal(asset1, creditAccount, 1000); // Simulate claim result + vm.mockCall(asset1, abi.encodeCall(IERC20.balanceOf, (creditAccount)), abi.encode(0)); + _executesCall({ + tokensToApprove: new address[](0), + callData: abi.encodeCall( + IMellowClaimer.multiAcceptAndClaim, (multivault1, subvaultIndices, indices, creditAccount, 1000) + ) + }); + + bytes[] memory retdatas = new bytes[](2); + + retdatas[0] = abi.encode(2000); + retdatas[1] = abi.encode(3000); + + vm.mockCalls(asset1, abi.encodeCall(IERC20.balanceOf, (creditAccount)), retdatas); + + vm.prank(creditFacade); + bool useSafePrices = adapter.multiAcceptAndClaim(multivault1, subvaultIndices, indices, address(0), 1000); + assertFalse(useSafePrices); + + retdatas[0] = abi.encode(2000); + retdatas[1] = abi.encode(2500); + + vm.mockCalls(asset1, abi.encodeCall(IERC20.balanceOf, (creditAccount)), retdatas); + + // Test insufficient claim + _executesCall({ + tokensToApprove: new address[](0), + callData: abi.encodeCall( + IMellowClaimer.multiAcceptAndClaim, (multivault1, subvaultIndices, indices, creditAccount, 1000) + ) + }); + vm.mockCall(asset1, abi.encodeCall(IERC20.balanceOf, (creditAccount)), abi.encode(500)); + vm.expectRevert(InsufficientClaimedException.selector); + vm.prank(creditFacade); + adapter.multiAcceptAndClaim(multivault1, subvaultIndices, indices, address(0), 1000); + } + + /// @notice U:[MCA-5]: `withdrawPhantomToken` works as expected + function test_U_MCA_05_withdrawPhantomToken_works_as_expected() public { + // Setup allowed multivault + MellowMultiVaultStatus[] memory multivaults = new MellowMultiVaultStatus[](1); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, true); + _readsTokenMask(stakedPhantomToken1); + _readsTokenMask(asset1); + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + + // Test with non-allowed phantom token + vm.expectRevert(MultiVaultNotAllowedException.selector); + vm.prank(creditFacade); + adapter.withdrawPhantomToken(stakedPhantomToken2, 1000); + + // Test successful withdrawal + _readsActiveAccount(); + (uint256[] memory subvaultIndices, uint256[][] memory indices) = + adapter.getUserSubvaultIndices(multivault1, creditAccount); + deal(asset1, creditAccount, 1000); // Simulate claim result + vm.mockCall(asset1, abi.encodeCall(IERC20.balanceOf, (creditAccount)), abi.encode(0)); + _executesCall({ + tokensToApprove: new address[](0), + callData: abi.encodeCall( + IMellowClaimer.multiAcceptAndClaim, (multivault1, subvaultIndices, indices, creditAccount, 1000) + ) + }); + + bytes[] memory retdatas = new bytes[](2); + + retdatas[0] = abi.encode(2000); + retdatas[1] = abi.encode(3000); + + vm.mockCalls(asset1, abi.encodeCall(IERC20.balanceOf, (creditAccount)), retdatas); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdrawPhantomToken(stakedPhantomToken1, 1000); + assertFalse(useSafePrices); + } + + /// @notice U:[MCA-6]: `depositPhantomToken` reverts as expected + function test_U_MCA_06_depositPhantomToken_reverts_as_expected() public { + vm.expectRevert(NotImplementedException.selector); + vm.prank(creditFacade); + adapter.depositPhantomToken(stakedPhantomToken1, 1000); + } + + /// @notice U:[MCA-7]: `getMultiVaultSubvaultIndices` works as expected + function test_U_MCA_07_getMultiVaultSubvaultIndices_works_as_expected() public view { + (uint256[] memory subvaultIndices, uint256[][] memory withdrawalIndices) = + adapter.getMultiVaultSubvaultIndices(multivault1); + + assertEq(subvaultIndices.length, 1, "Incorrect subvaultIndices length"); + assertEq(subvaultIndices[0], 0, "Incorrect subvault index"); + assertEq(withdrawalIndices.length, 1, "Incorrect withdrawalIndices length"); + assertEq(withdrawalIndices[0].length, 2, "Incorrect withdrawal indices length"); + assertEq(withdrawalIndices[0][0], 0, "Incorrect withdrawal index 0"); + assertEq(withdrawalIndices[0][1], 1, "Incorrect withdrawal index 1"); + } + + /// @notice U:[MCA-7A]: `getUserSubvaultIndices` works as expected + function test_U_MCA_07A_getUserSubvaultIndices_works_as_expected() public view { + (uint256[] memory subvaultIndices, uint256[][] memory withdrawalIndices) = + adapter.getUserSubvaultIndices(multivault1, creditAccount); + + assertEq(subvaultIndices.length, 1, "Incorrect subvaultIndices length"); + assertEq(subvaultIndices[0], 0, "Incorrect subvault index"); + assertEq(withdrawalIndices.length, 1, "Incorrect withdrawalIndices length"); + assertEq(withdrawalIndices[0].length, 2, "Incorrect withdrawal indices length"); + assertEq(withdrawalIndices[0][0], 0, "Incorrect withdrawal index 0"); + assertEq(withdrawalIndices[0][1], 2, "Incorrect withdrawal index 1"); + } + + /// @notice U:[MCA-8]: `setMultiVaultStatusBatch` works as expected + function test_U_MCA_08_setMultivaultStatusBatch_works_as_expected() public { + _revertsOnNonConfiguratorCaller(); + adapter.setMultiVaultStatusBatch(new MellowMultiVaultStatus[](0)); + + // Test adding multivaults + MellowMultiVaultStatus[] memory multivaults = new MellowMultiVaultStatus[](2); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, true); + multivaults[1] = MellowMultiVaultStatus(multivault2, stakedPhantomToken2, true); + + _readsTokenMask(stakedPhantomToken1); + _readsTokenMask(asset1); + _readsTokenMask(stakedPhantomToken2); + _readsTokenMask(asset2); + + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + + address[] memory allowedMultiVaults = adapter.allowedMultiVaults(); + assertEq(allowedMultiVaults.length, 2, "Incorrect allowed multivaults length"); + assertTrue(_contains(allowedMultiVaults, multivault1), "Multivault1 not found"); + assertTrue(_contains(allowedMultiVaults, multivault2), "Multivault2 not found"); + + assertEq( + adapter.phantomTokenToMultiVault(stakedPhantomToken1), multivault1, "Incorrect phantom token mapping 1" + ); + assertEq( + adapter.phantomTokenToMultiVault(stakedPhantomToken2), multivault2, "Incorrect phantom token mapping 2" + ); + + // Test removing multivault + multivaults = new MellowMultiVaultStatus[](1); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, false); + + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + + allowedMultiVaults = adapter.allowedMultiVaults(); + assertEq(allowedMultiVaults.length, 1, "Incorrect allowed multivaults length after removal"); + assertFalse(_contains(allowedMultiVaults, multivault1), "Multivault1 should be removed"); + assertTrue(_contains(allowedMultiVaults, multivault2), "Multivault2 should remain"); + + // Test invalid multivault (phantom token doesn't match) + vm.mockCall(stakedPhantomToken1, abi.encodeWithSignature("multiVault()"), abi.encode(multivault2)); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, true); + + vm.expectRevert(InvalidMultiVaultException.selector); + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + } + + /// @notice U:[MCA-9]: `serialize` works as expected + function test_U_MCA_09_serialize_works_as_expected() public { + // Add some multivaults + MellowMultiVaultStatus[] memory multivaults = new MellowMultiVaultStatus[](2); + multivaults[0] = MellowMultiVaultStatus(multivault1, stakedPhantomToken1, true); + multivaults[1] = MellowMultiVaultStatus(multivault2, stakedPhantomToken2, true); + + _readsTokenMask(stakedPhantomToken1); + _readsTokenMask(asset1); + _readsTokenMask(stakedPhantomToken2); + _readsTokenMask(asset2); + + vm.prank(configurator); + adapter.setMultiVaultStatusBatch(multivaults); + + bytes memory serialized = adapter.serialize(); + (address cm, address tc, address[] memory allowed) = abi.decode(serialized, (address, address, address[])); + + assertEq(cm, address(creditManager), "Incorrect credit manager in serialized data"); + assertEq(tc, claimer, "Incorrect target contract in serialized data"); + assertEq(allowed.length, 2, "Incorrect allowed multivaults length in serialized data"); + assertTrue(_contains(allowed, multivault1), "Multivault1 not in serialized data"); + assertTrue(_contains(allowed, multivault2), "Multivault2 not in serialized data"); + } + + /// @dev Helper function to check if an address is in an array + function _contains(address[] memory array, address value) internal pure returns (bool) { + for (uint256 i = 0; i < array.length; i++) { + if (array[i] == value) return true; + } + return false; + } +} diff --git a/contracts/test/unit/adapters/mellow/MellowDVVAdapter.unit.t.sol b/contracts/test/unit/adapters/mellow/MellowDVVAdapter.unit.t.sol new file mode 100644 index 00000000..b7071ee9 --- /dev/null +++ b/contracts/test/unit/adapters/mellow/MellowDVVAdapter.unit.t.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {MellowDVVAdapter} from "../../../../adapters/mellow/MellowDVVAdapter.sol"; +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; + +/// @title MellowDVVAdapter unit test +/// @notice U:[MDVV]: Unit tests for MellowDVVAdapter +contract MellowDVVAdapterUnitTest is AdapterUnitTestHelper { + MellowDVVAdapter adapter; + address vault; + address asset; + + function setUp() public { + _setUp(); + asset = tokens[0]; + vault = tokens[1]; + + vm.mockCall(vault, abi.encodeCall(IERC4626.asset, ()), abi.encode(asset)); + + adapter = new MellowDVVAdapter(address(creditManager), vault); + } + + /// @notice U:[MDVV-1]: Constructor works as expected + function test_U_MDVV_01_constructor_works_as_expected() public view { + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), vault, "Incorrect targetContract"); + } + + /// @notice U:[MDVV-2]: Wrapper functions revert on wrong caller + function test_U_MDVV_02_wrapper_functions_revert_on_wrong_caller() public { + _revertsOnNonFacadeCaller(); + adapter.deposit(1000, address(0)); + + _revertsOnNonFacadeCaller(); + adapter.mint(1000, address(0)); + } + + /// @notice U:[MDVV-3]: Deposit and mint revert as not implemented + function test_U_MDVV_03_deposit_and_mint_revert() public { + vm.prank(creditFacade); + vm.expectRevert(NotImplementedException.selector); + adapter.deposit(1000, address(0)); + + vm.prank(creditFacade); + vm.expectRevert(NotImplementedException.selector); + adapter.mint(1000, address(0)); + } + + /// @notice U:[MDVV-4]: Inherited withdraw works as expected + function test_U_MDVV_04_inherited_withdraw_works_as_expected() public { + _revertsOnNonFacadeCaller(); + adapter.withdraw(1000, address(0), address(0)); + + _readsActiveAccount(); + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IERC4626.withdraw, (1000, creditAccount, creditAccount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdraw(1000, address(0), address(0)); + assertFalse(useSafePrices); + } + + /// @notice U:[MDVV-5]: Inherited redeem works as expected + function test_U_MDVV_05_inherited_redeem_works_as_expected() public { + _revertsOnNonFacadeCaller(); + adapter.redeem(1000, address(0), address(0)); + + _readsActiveAccount(); + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IERC4626.redeem, (1000, creditAccount, creditAccount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.redeem(1000, address(0), address(0)); + assertFalse(useSafePrices); + } + + /// @notice U:[MDVV-6]: Inherited redeemDiff works as expected + function test_U_MDVV_06_inherited_redeemDiff_works_as_expected() public diffTestCases { + _revertsOnNonFacadeCaller(); + adapter.redeemDiff(1000); + + deal({token: vault, to: creditAccount, give: diffMintedAmount}); + + _readsActiveAccount(); + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IERC4626.redeem, (diffInputAmount, creditAccount, creditAccount)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.redeemDiff(diffLeftoverAmount); + assertFalse(useSafePrices); + } +} diff --git a/contracts/test/unit/adapters/mellow/MellowVaultAdapter.unit.t.sol b/contracts/test/unit/adapters/mellow/MellowVaultAdapter.unit.t.sol index 079282c6..699e6cd8 100644 --- a/contracts/test/unit/adapters/mellow/MellowVaultAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/mellow/MellowVaultAdapter.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IMellowVault} from "../../../../integrations/mellow/IMellowVault.sol"; @@ -41,11 +41,9 @@ contract MellowVaultAdapterUnitTest is } /// @notice U:[MEL-1]: Constructor works as expected - function test_U_MEL_01_constructor_works_as_expected() public { + function test_U_MEL_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), vault, "Incorrect targetContract"); - assertEq(adapter.vaultTokenMask(), 8, "Incorrect vault token mask"); } /// @notice U:[MEL-2]: Wrapper functions revert on wrong caller @@ -86,15 +84,13 @@ contract MellowVaultAdapterUnitTest is _readsActiveAccount(); _executesCall({ tokensToApprove: tokensToApprove, - tokensToValidate: new address[](0), callData: abi.encodeCall(IMellowVault.deposit, (creditAccount, amounts, 0, 789)) }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(creditAccount, amounts, 0, 789); + bool useSafePrices = adapter.deposit(creditAccount, amounts, 0, 789); - assertEq(tokensToEnable, 8, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[MEL-4]: `depositOneAsset` works as expected @@ -104,6 +100,9 @@ contract MellowVaultAdapterUnitTest is adapter.depositOneAsset(tokens[1], 100, 0, 789); address nonExistentToken = makeAddr("WRONG_TOKEN"); + + creditManager.setMask(nonExistentToken, 4096); + _allowUnderlying(nonExistentToken); vm.expectRevert(abi.encodeWithSelector(UnderlyingNotFoundException.selector, nonExistentToken)); vm.prank(creditFacade); @@ -116,17 +115,14 @@ contract MellowVaultAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[3], callData: abi.encodeCall(IMellowVault.deposit, (creditAccount, amounts, 0, 789)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositOneAsset(tokens[0], 100, 0, 789); + bool useSafePrices = adapter.depositOneAsset(tokens[0], 100, 0, 789); - assertEq(tokensToEnable, 8, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[MEL-5]: `depositOneAssetDiff` works as expected @@ -138,6 +134,9 @@ contract MellowVaultAdapterUnitTest is adapter.depositOneAssetDiff(tokens[1], diffLeftoverAmount, 0.5e27, 789); address nonExistentToken = makeAddr("WRONG_TOKEN"); + + creditManager.setMask(nonExistentToken, 4096); + _allowUnderlying(nonExistentToken); vm.mockCall(nonExistentToken, abi.encodeCall(IERC20.balanceOf, (creditAccount)), abi.encode(diffMintedAmount)); vm.expectRevert(abi.encodeWithSelector(UnderlyingNotFoundException.selector, nonExistentToken)); @@ -151,18 +150,14 @@ contract MellowVaultAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[3], callData: abi.encodeCall(IMellowVault.deposit, (creditAccount, amounts, diffInputAmount / 2, 789)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.depositOneAssetDiff(tokens[0], diffLeftoverAmount, 0.5e27, 789); + bool useSafePrices = adapter.depositOneAssetDiff(tokens[0], diffLeftoverAmount, 0.5e27, 789); - assertEq(tokensToEnable, 8, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[MEL-6]: `setUnderlyingStatusBatch` works as expected @@ -185,8 +180,9 @@ contract MellowVaultAdapterUnitTest is vm.prank(configurator); adapter.setUnderlyingStatusBatch(underlyings); - assertFalse(adapter.isUnderlyingAllowed(tokens[0]), "First token is incorrectly allowed"); - assertTrue(adapter.isUnderlyingAllowed(tokens[1]), "Second token is incorrectly not allowed"); + address[] memory allowedUnderlyings = adapter.allowedUnderlyings(); + assertEq(allowedUnderlyings.length, 1, "Incorrect number of allowed underlyings"); + assertEq(allowedUnderlyings[0], tokens[1], "Incorrect allowed underlying"); } // ------- // diff --git a/contracts/test/unit/adapters/mellow/MellowWrapperAdapter.unit.t.sol b/contracts/test/unit/adapters/mellow/MellowWrapperAdapter.unit.t.sol new file mode 100644 index 00000000..5a24a8c5 --- /dev/null +++ b/contracts/test/unit/adapters/mellow/MellowWrapperAdapter.unit.t.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {MellowWrapperAdapter} from "../../../../adapters/mellow/MellowWrapperAdapter.sol"; +import { + IMellowWrapperAdapter, + MellowVaultStatus, + IMellowWrapperAdapterEvents, + IMellowWrapperAdapterExceptions +} from "../../../../interfaces/mellow/IMellowWrapperAdapter.sol"; +import {IMellowWrapper} from "../../../../integrations/mellow/IMellowWrapper.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; + +contract MellowWrapperAdapterUnitTest is + AdapterUnitTestHelper, + IMellowWrapperAdapterEvents, + IMellowWrapperAdapterExceptions +{ + MellowWrapperAdapter adapter; + address mellowWrapper; + address weth; + address referral; + address vault; + + function setUp() public { + _setUp(); + mellowWrapper = tokens[0]; + weth = tokens[1]; + referral = tokens[2]; + vault = tokens[3]; + vm.mockCall(mellowWrapper, abi.encodeCall(IMellowWrapper.WETH, ()), abi.encode(weth)); + adapter = new MellowWrapperAdapter(address(creditManager), mellowWrapper, referral); + } + + /// @notice U:[MWA-1]: Constructor works as expected + function test_U_MWA_01_constructor_works_as_expected() public view { + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), mellowWrapper, "Incorrect targetContract"); + assertEq(adapter.referral(), referral, "Incorrect referral"); + assertEq(adapter.weth(), weth, "Incorrect weth"); + } + + /// @notice U:[MWA-2]: Wrapper functions revert on wrong caller + function test_U_MWA_02_wrapper_functions_revert_on_wrong_caller() public { + _revertsOnNonFacadeCaller(); + adapter.deposit(address(0), 1000, vault, address(0), address(0)); + _revertsOnNonFacadeCaller(); + adapter.depositDiff(1000, vault); + } + + /// @notice U:[MWA-3]: Deposit reverts if vault is not allowed + function test_U_MWA_03_deposit_reverts_if_vault_not_allowed() public { + vm.prank(creditFacade); + vm.expectRevert(abi.encodeWithSelector(VaultNotAllowedException.selector, vault)); + adapter.deposit(address(0), 1000, vault, address(0), address(0)); + } + + /// @notice U:[MWA-4]: Deposit executes if vault is allowed + function test_U_MWA_04_deposit_executes_if_vault_allowed() public { + _addAllowedVault(vault); + _readsActiveAccount(); + _executesSwap({ + tokenIn: weth, + callData: abi.encodeCall(IMellowWrapper.deposit, (weth, 1000, vault, creditAccount, referral)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.deposit(address(0), 1000, vault, address(0), address(0)); + assertFalse(useSafePrices); + } + + /// @notice U:[MWA-5]: DepositDiff reverts if vault is not allowed + function test_U_MWA_05_depositDiff_reverts_if_vault_not_allowed() public { + vm.prank(creditFacade); + vm.expectRevert(abi.encodeWithSelector(VaultNotAllowedException.selector, vault)); + adapter.depositDiff(1000, vault); + } + + /// @notice U:[MWA-6]: DepositDiff returns false if balance is too low + function test_U_MWA_06_depositDiff_returns_false_if_balance_too_low() public { + _addAllowedVault(vault); + vm.mockCall(weth, abi.encodeCall(IERC20.balanceOf, (creditAccount)), abi.encode(500)); + vm.prank(creditFacade); + bool useSafePrices = adapter.depositDiff(1000, vault); + assertFalse(useSafePrices); + } + + /// @notice U:[MWA-7]: DepositDiff executes if balance is sufficient + function test_U_MWA_07_depositDiff_executes_if_balance_sufficient() public { + _addAllowedVault(vault); + vm.mockCall(weth, abi.encodeCall(IERC20.balanceOf, (creditAccount)), abi.encode(2000)); + _readsActiveAccount(); + _executesSwap({ + tokenIn: weth, + callData: abi.encodeCall(IMellowWrapper.deposit, (weth, 1000, vault, creditAccount, referral)), + requiresApproval: true + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.depositDiff(1000, vault); + assertFalse(useSafePrices); + } + + /// @notice U:[MWA-8]: allowedVaults returns correct list + function test_U_MWA_08_allowedVaults_returns_correct_list() public { + assertEq(adapter.allowedVaults().length, 0, "Should be empty initially"); + _addAllowedVault(vault); + address[] memory allowed = adapter.allowedVaults(); + assertEq(allowed.length, 1, "Should have one allowed vault"); + assertEq(allowed[0], vault, "Incorrect allowed vault"); + } + + /// @notice U:[MWA-9]: setVaultStatusBatch works as expected + function test_U_MWA_09_setVaultStatusBatch_works_as_expected() public { + MellowVaultStatus[] memory vaults = new MellowVaultStatus[](2); + vaults[0] = MellowVaultStatus(vault, true); + vaults[1] = MellowVaultStatus(tokens[4], true); + _revertsOnNonConfiguratorCaller(); + adapter.setVaultStatusBatch(vaults); + vm.expectEmit(true, false, false, true); + emit SetVaultStatus(vault, true); + vm.expectEmit(true, false, false, true); + emit SetVaultStatus(tokens[4], true); + vm.prank(configurator); + adapter.setVaultStatusBatch(vaults); + address[] memory allowed = adapter.allowedVaults(); + assertEq(allowed.length, 2, "Should have two allowed vaults"); + assertEq(allowed[0], vault, "First allowed vault incorrect"); + assertEq(allowed[1], tokens[4], "Second allowed vault incorrect"); + // Now remove one + vaults[0] = MellowVaultStatus(vault, false); + vm.expectEmit(true, false, false, true); + emit SetVaultStatus(vault, false); + vm.prank(configurator); + adapter.setVaultStatusBatch(vaults); + allowed = adapter.allowedVaults(); + assertEq(allowed.length, 1, "Should have one allowed vault after removal"); + assertEq(allowed[0], tokens[4], "Remaining allowed vault incorrect"); + } + + // ------- // + // HELPERS // + // ------- // + function _addAllowedVault(address _vault) internal { + MellowVaultStatus[] memory vaults = new MellowVaultStatus[](1); + vaults[0] = MellowVaultStatus(_vault, true); + vm.prank(configurator); + adapter.setVaultStatusBatch(vaults); + } +} diff --git a/contracts/test/unit/adapters/pendle/PendleRouterAdapter.unit.t.sol b/contracts/test/unit/adapters/pendle/PendleRouterAdapter.unit.t.sol index c2133da0..911d95f8 100644 --- a/contracts/test/unit/adapters/pendle/PendleRouterAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/pendle/PendleRouterAdapter.unit.t.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2024. -pragma solidity ^0.8.17; +pragma solidity ^0.8.23; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IPendleRouter, IPendleMarket, @@ -57,9 +58,8 @@ contract PendleRouterAdapterUnitTest is } /// @notice U:[PEND-1]: Constructor works as expected - function test_U_PEND_01_constructor_works_as_expected() public { + function test_U_PEND_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), pendleRouter, "Incorrect targetContract"); } @@ -111,20 +111,16 @@ contract PendleRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: pt, callData: abi.encodeCall( IPendleRouter.swapExactTokenForPt, (creditAccount, market, 0, approxParams, input, limitOrderData) ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapExactTokenForPt(address(0), market, 0, approxParams, input, limitOrderData); + bool useSafePrices = adapter.swapExactTokenForPt(address(0), market, 0, approxParams, input, limitOrderData); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[PEND-4]: `swapDiffTokenForPt` works as expected @@ -151,21 +147,18 @@ contract PendleRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: pt, callData: abi.encodeCall( IPendleRouter.swapExactTokenForPt, (creditAccount, market, diffInputAmount / 2, approxParams, input, limitOrderData) ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = + bool useSafePrices = adapter.swapDiffTokenForPt(market, 0.5e27, approxParams, TokenDiffInput(tokens[0], diffLeftoverAmount)); - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[PEND-5]: `swapExactPtForToken` works as expected @@ -188,20 +181,16 @@ contract PendleRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: pt, - tokenOut: tokens[0], callData: abi.encodeCall( IPendleRouter.swapExactPtForToken, (creditAccount, market, 100, output, limitOrderData) ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapExactPtForToken(address(0), market, 100, output, limitOrderData); + bool useSafePrices = adapter.swapExactPtForToken(address(0), market, 100, output, limitOrderData); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[PEND-6]: `swapDiffPtForToken` works as expected @@ -226,20 +215,16 @@ contract PendleRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: pt, - tokenOut: tokens[0], callData: abi.encodeCall( IPendleRouter.swapExactPtForToken, (creditAccount, market, diffInputAmount, output, limitOrderData) ), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapDiffPtForToken(market, diffLeftoverAmount, TokenDiffOutput(tokens[0], 0.5e27)); + bool useSafePrices = adapter.swapDiffPtForToken(market, diffLeftoverAmount, TokenDiffOutput(tokens[0], 0.5e27)); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 2 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[PEND-7]: `redeemPyToToken` works as expected @@ -277,17 +262,14 @@ contract PendleRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: pt, - tokenOut: tokens[0], callData: abi.encodeCall(IPendleRouter.redeemPyToToken, (creditAccount, yt, 100, output)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.redeemPyToToken(address(0), yt, 100, output); + bool useSafePrices = adapter.redeemPyToToken(address(0), yt, 100, output); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[PEND-8]: `redeemDiffPyToToken` works as expected @@ -327,18 +309,14 @@ contract PendleRouterAdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: pt, - tokenOut: tokens[0], callData: abi.encodeCall(IPendleRouter.redeemPyToToken, (creditAccount, yt, diffInputAmount, output)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.redeemDiffPyToToken(yt, diffLeftoverAmount, TokenDiffOutput(tokens[0], 0.5e27)); + bool useSafePrices = adapter.redeemDiffPyToToken(yt, diffLeftoverAmount, TokenDiffOutput(tokens[0], 0.5e27)); - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 2 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices, "Should use safe prices"); } /// @notice U:[PEND-9]: `setPairStatusBatch` works as expected @@ -372,8 +350,8 @@ contract PendleRouterAdapterUnitTest is "Second pair status is incorrect" ); assertEq(adapter.ptToMarket(pt), market, "Incorrect market for PT"); - assertEq(adapter.isRedemptionAllowed(tokens[0], pt), false, "Incorrect redemption status for first pair"); - assertEq(adapter.isRedemptionAllowed(tokens[1], pt), true, "Incorrect redemption status for second pair"); + assertFalse(adapter.isRedemptionAllowed(tokens[0], pt), "Incorrect redemption status for first pair"); + assertTrue(adapter.isRedemptionAllowed(tokens[1], pt), "Incorrect redemption status for second pair"); PendlePairStatus[] memory allowedPairs = adapter.getAllowedPairs(); assertEq(allowedPairs.length, 1, "Incorrect number of allowed pairs"); diff --git a/contracts/test/unit/adapters/sky/DaiUsdsAdapter.unit.t.sol b/contracts/test/unit/adapters/sky/DaiUsdsAdapter.unit.t.sol index 7b2959f7..7666a184 100644 --- a/contracts/test/unit/adapters/sky/DaiUsdsAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/sky/DaiUsdsAdapter.unit.t.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {DaiUsdsAdapter} from "../../../../adapters/sky/DaiUsdsAdapter.sol"; import {IDaiUsds} from "../../../../integrations/sky/IDaiUsds.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; -/// @title DAI/USDS adapter unit test +/// @title DaiUsds adapter unit test /// @notice U:[DUSDS]: Unit tests for DAI/USDS adapter contract DaiUsdsAdapterUnitTest is AdapterUnitTestHelper { DaiUsdsAdapter adapter; @@ -16,14 +16,11 @@ contract DaiUsdsAdapterUnitTest is AdapterUnitTestHelper { address usds; address daiUsdsExchange; - uint256 daiMask; - uint256 usdsMask; - function setUp() public { _setUp(); - (dai, daiMask) = (tokens[0], 1); - (usds, usdsMask) = (tokens[1], 2); + dai = tokens[0]; + usds = tokens[1]; daiUsdsExchange = tokens[2]; vm.mockCall(daiUsdsExchange, abi.encodeCall(IDaiUsds.dai, ()), abi.encode(dai)); @@ -39,12 +36,9 @@ contract DaiUsdsAdapterUnitTest is AdapterUnitTestHelper { adapter = new DaiUsdsAdapter(address(creditManager), daiUsdsExchange); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), daiUsdsExchange, "Incorrect targetContract"); assertEq(adapter.dai(), dai, "Incorrect dai"); assertEq(adapter.usds(), usds, "Incorrect usds"); - assertEq(adapter.daiMask(), daiMask, "Incorrect daiMask"); - assertEq(adapter.usdsMask(), usdsMask, "Incorrect usdsMask"); } /// @notice U:[DUSDS-2]: Wrapper functions revert on wrong caller @@ -62,73 +56,63 @@ contract DaiUsdsAdapterUnitTest is AdapterUnitTestHelper { adapter.usdsToDaiDiff(0); } - /// @notice U:[DUSDS-3]: `daiToUsds` works as expected + /// @notice U:[DUSDS-3]: `daiToUsds()` works as expected function test_U_DUSDS_03_daiToUsds_works_as_expected() public { + uint256 amount = 1000; + + _readsActiveAccount(); _executesSwap({ tokenIn: dai, - tokenOut: usds, - callData: abi.encodeCall(IDaiUsds.daiToUsds, (creditAccount, 1000)), - requiresApproval: true, - validatesTokens: false + callData: abi.encodeCall(IDaiUsds.daiToUsds, (creditAccount, amount)), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.daiToUsds(address(0), 1000); - - assertEq(tokensToEnable, usdsMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.daiToUsds(address(0), amount); + assertFalse(useSafePrices); } - /// @notice U:[DUSDS-4]: `daiToUsdsDiff` works as expected + /// @notice U:[DUSDS-4]: `daiToUsdsDiff()` works as expected function test_U_DUSDS_04_daiToUsdsDiff_works_as_expected() public diffTestCases { deal({token: dai, to: creditAccount, give: diffMintedAmount}); _readsActiveAccount(); _executesSwap({ tokenIn: dai, - tokenOut: usds, callData: abi.encodeCall(IDaiUsds.daiToUsds, (creditAccount, diffInputAmount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.daiToUsdsDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, usdsMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? daiMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.daiToUsdsDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } - /// @notice U:[DUSDS-5]: `usdsToDai` works as expected + /// @notice U:[DUSDS-5]: `usdsToDai()` works as expected function test_U_DUSDS_05_usdsToDai_works_as_expected() public { + uint256 amount = 1000; + + _readsActiveAccount(); _executesSwap({ tokenIn: usds, - tokenOut: dai, - callData: abi.encodeCall(IDaiUsds.usdsToDai, (creditAccount, 1000)), - requiresApproval: true, - validatesTokens: false + callData: abi.encodeCall(IDaiUsds.usdsToDai, (creditAccount, amount)), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.usdsToDai(address(0), 1000); - - assertEq(tokensToEnable, daiMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.usdsToDai(address(0), amount); + assertFalse(useSafePrices); } - /// @notice U:[DUSDS-6]: `usdsToDaiDiff` works as expected + /// @notice U:[DUSDS-6]: `usdsToDaiDiff()` works as expected function test_U_DUSDS_06_usdsToDaiDiff_works_as_expected() public diffTestCases { deal({token: usds, to: creditAccount, give: diffMintedAmount}); _readsActiveAccount(); _executesSwap({ tokenIn: usds, - tokenOut: dai, callData: abi.encodeCall(IDaiUsds.usdsToDai, (creditAccount, diffInputAmount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.usdsToDaiDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, daiMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? usdsMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.usdsToDaiDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } } diff --git a/contracts/test/unit/adapters/sky/StakingRewardsAdapter.unit.t.sol b/contracts/test/unit/adapters/sky/StakingRewardsAdapter.unit.t.sol index cfe83c8d..105297bf 100644 --- a/contracts/test/unit/adapters/sky/StakingRewardsAdapter.unit.t.sol +++ b/contracts/test/unit/adapters/sky/StakingRewardsAdapter.unit.t.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {StakingRewardsAdapter} from "../../../../adapters/sky/StakingRewardsAdapter.sol"; import {IStakingRewards} from "../../../../integrations/sky/IStakingRewards.sol"; +import {IStakingRewardsReferral} from "../../../../integrations/sky/IStakingRewards.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; /// @title Staking Rewards adapter unit test @@ -12,27 +14,23 @@ import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; contract StakingRewardsAdapterUnitTest is AdapterUnitTestHelper { StakingRewardsAdapter adapter; + address stakingRewards; address stakingToken; address rewardsToken; address stakedPhantomToken; - address stakingRewards; - - uint256 stakingTokenMask; - uint256 rewardsTokenMask; - uint256 stakedPhantomTokenMask; function setUp() public { _setUp(); - (stakingToken, stakingTokenMask) = (tokens[0], 1); - (rewardsToken, rewardsTokenMask) = (tokens[1], 2); - (stakedPhantomToken, stakedPhantomTokenMask) = (tokens[2], 4); + stakingToken = tokens[0]; + rewardsToken = tokens[1]; + stakedPhantomToken = tokens[2]; stakingRewards = tokens[3]; vm.mockCall(stakingRewards, abi.encodeCall(IStakingRewards.stakingToken, ()), abi.encode(stakingToken)); vm.mockCall(stakingRewards, abi.encodeCall(IStakingRewards.rewardsToken, ()), abi.encode(rewardsToken)); - adapter = new StakingRewardsAdapter(address(creditManager), stakingRewards, stakedPhantomToken); + adapter = new StakingRewardsAdapter(address(creditManager), stakingRewards, stakedPhantomToken, 0); } /// @notice U:[SR-1]: Constructor works as expected @@ -40,17 +38,14 @@ contract StakingRewardsAdapterUnitTest is AdapterUnitTestHelper { _readsTokenMask(stakingToken); _readsTokenMask(rewardsToken); _readsTokenMask(stakedPhantomToken); - adapter = new StakingRewardsAdapter(address(creditManager), stakingRewards, stakedPhantomToken); + adapter = new StakingRewardsAdapter(address(creditManager), stakingRewards, stakedPhantomToken, 1); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), stakingRewards, "Incorrect targetContract"); assertEq(adapter.stakingToken(), stakingToken, "Incorrect stakingToken"); assertEq(adapter.rewardsToken(), rewardsToken, "Incorrect rewardsToken"); assertEq(adapter.stakedPhantomToken(), stakedPhantomToken, "Incorrect stakedPhantomToken"); - assertEq(adapter.stakingTokenMask(), stakingTokenMask, "Incorrect stakingTokenMask"); - assertEq(adapter.rewardsTokenMask(), rewardsTokenMask, "Incorrect rewardsTokenMask"); - assertEq(adapter.stakedPhantomTokenMask(), stakedPhantomTokenMask, "Incorrect stakedPhantomTokenMask"); + assertEq(adapter.referral(), 1, "Incorrect referral"); } /// @notice U:[SR-2]: Wrapper functions revert on wrong caller @@ -69,89 +64,118 @@ contract StakingRewardsAdapterUnitTest is AdapterUnitTestHelper { _revertsOnNonFacadeCaller(); adapter.withdrawDiff(0); + + _revertsOnNonFacadeCaller(); + adapter.withdrawPhantomToken(address(0), 0); } + // ----- // + // STAKE // + // ----- // + /// @notice U:[SR-3]: `stake` works as expected function test_U_SR_03_stake_works_as_expected() public { _executesSwap({ tokenIn: stakingToken, - tokenOut: stakedPhantomToken, callData: abi.encodeCall(IStakingRewards.stake, (1000)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.stake(1000); - - assertEq(tokensToEnable, stakedPhantomTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.stake(1000); + assertFalse(useSafePrices); } /// @notice U:[SR-4]: `stakeDiff` works as expected function test_U_SR_04_stakeDiff_works_as_expected() public diffTestCases { deal({token: stakingToken, to: creditAccount, give: diffMintedAmount}); - _readsActiveAccount(); _executesSwap({ tokenIn: stakingToken, - tokenOut: stakedPhantomToken, callData: abi.encodeCall(IStakingRewards.stake, (diffInputAmount)), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.stakeDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, stakedPhantomTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? stakingTokenMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.stakeDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } + // ----- // + // CLAIM // + // ----- // + /// @notice U:[SR-5]: `getReward` works as expected function test_U_SR_05_getReward_works_as_expected() public { - _executesCall({ - tokensToApprove: new address[](0), - tokensToValidate: new address[](0), - callData: abi.encodeCall(IStakingRewards.getReward, ()) - }); + _executesCall({tokensToApprove: new address[](0), callData: abi.encodeCall(IStakingRewards.getReward, ())}); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.getReward(); - - assertEq(tokensToEnable, rewardsTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.getReward(); + assertFalse(useSafePrices); } + // -------- // + // WITHDRAW // + // -------- // + /// @notice U:[SR-6]: `withdraw` works as expected function test_U_SR_06_withdraw_works_as_expected() public { _executesSwap({ tokenIn: stakedPhantomToken, - tokenOut: stakingToken, callData: abi.encodeCall(IStakingRewards.withdraw, (1000)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(1000); - - assertEq(tokensToEnable, stakingTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(1000); + assertFalse(useSafePrices); } /// @notice U:[SR-7]: `withdrawDiff` works as expected function test_U_SR_07_withdrawDiff_works_as_expected() public diffTestCases { deal({token: stakedPhantomToken, to: creditAccount, give: diffMintedAmount}); - _readsActiveAccount(); _executesSwap({ tokenIn: stakedPhantomToken, - tokenOut: stakingToken, callData: abi.encodeCall(IStakingRewards.withdraw, (diffInputAmount)), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiff(diffLeftoverAmount); + bool useSafePrices = adapter.withdrawDiff(diffLeftoverAmount); + assertFalse(useSafePrices); + } + + /// @notice U:[SR-8]: `withdrawPhantomToken` works as expected + function test_U_SR_08_withdrawPhantomToken_works_as_expected() public { + vm.expectRevert(IPhantomTokenAdapter.IncorrectStakedPhantomTokenException.selector); + vm.prank(creditFacade); + adapter.withdrawPhantomToken(address(0), 1000); - assertEq(tokensToEnable, stakingTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? stakedPhantomTokenMask : 0, "Incorrect tokensToDisable"); + _executesSwap({ + tokenIn: stakedPhantomToken, + callData: abi.encodeCall(IStakingRewards.withdraw, (1000)), + requiresApproval: false + }); + vm.prank(creditFacade); + bool useSafePrices = adapter.withdrawPhantomToken(stakedPhantomToken, 1000); + assertFalse(useSafePrices); + } + + function test_U_SR_09_stake_with_referral_works_as_expected() public diffTestCases { + deal({token: stakingToken, to: creditAccount, give: diffMintedAmount}); + + adapter = new StakingRewardsAdapter(address(creditManager), stakingRewards, stakedPhantomToken, 1); + + _executesSwap({ + tokenIn: stakingToken, + callData: abi.encodeCall(IStakingRewardsReferral.stake, (1000, 1)), + requiresApproval: true + }); + vm.prank(creditFacade); + adapter.stake(1000); + + _executesSwap({ + tokenIn: stakingToken, + callData: abi.encodeCall(IStakingRewardsReferral.stake, (diffInputAmount, 1)), + requiresApproval: true + }); + vm.prank(creditFacade); + adapter.stakeDiff(diffLeftoverAmount); } } diff --git a/contracts/test/unit/adapters/traderjoe/TraderJoeRouterAdapter.harness.sol b/contracts/test/unit/adapters/traderjoe/TraderJoeRouterAdapter.harness.sol new file mode 100644 index 00000000..34632bb4 --- /dev/null +++ b/contracts/test/unit/adapters/traderjoe/TraderJoeRouterAdapter.harness.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {TraderJoeRouterAdapter} from "../../../../adapters/traderjoe/TraderJoeRouterAdapter.sol"; +import {Path} from "../../../../integrations/traderjoe/ITraderJoeRouter.sol"; + +/// @title TraderJoeRouterAdapter harness +/// @notice Exposes internal functions in TraderJoeRouterAdapter +contract TraderJoeRouterAdapterHarness is TraderJoeRouterAdapter { + constructor(address _creditManager, address _router) TraderJoeRouterAdapter(_creditManager, _router) {} + + /// @notice Exposes internal _validatePath function + function validatePath(Path memory path) external view returns (bool valid, address tokenIn) { + return _validatePath(path); + } +} diff --git a/contracts/test/unit/adapters/traderjoe/TraderJoeRouterAdapter.unit.t.sol b/contracts/test/unit/adapters/traderjoe/TraderJoeRouterAdapter.unit.t.sol new file mode 100644 index 00000000..59728a0e --- /dev/null +++ b/contracts/test/unit/adapters/traderjoe/TraderJoeRouterAdapter.unit.t.sol @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {ITraderJoeRouter, Path, Version, IERC20} from "../../../../integrations/traderjoe/ITraderJoeRouter.sol"; +import { + ITraderJoeRouterAdapter, + TraderJoePoolStatus, + TraderJoePool +} from "../../../../interfaces/traderjoe/ITraderJoeRouterAdapter.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; +import {TraderJoeRouterAdapterHarness} from "./TraderJoeRouterAdapter.harness.sol"; + +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + +/// @title TraderJoe adapter unit test +/// @notice U:[TJ-1]: Unit tests for TraderJoe swap router adapter +contract TraderJoeRouterAdapterUnitTest is AdapterUnitTestHelper { + TraderJoeRouterAdapterHarness adapter; + address router; + + function setUp() public { + _setUp(); + + router = makeAddr("ROUTER"); + adapter = new TraderJoeRouterAdapterHarness(address(creditManager), router); + + _setPoolsStatus(3, 7); + } + + /// @notice U:[TJ-1]: Constructor works as expected + function test_U_TJ_01_constructor_works_as_expected() public view { + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), router, "Incorrect targetContract"); + } + + /// @notice U:[TJ-2]: Wrapper functions revert on wrong caller + function test_U_TJ_02_wrapper_functions_revert_on_wrong_caller() public { + Path memory emptyPath; + + _revertsOnNonFacadeCaller(); + adapter.swapExactTokensForTokens(0, 0, emptyPath, address(0), 0); + + _revertsOnNonFacadeCaller(); + adapter.swapExactTokensForTokensSupportingFeeOnTransferTokens(0, 0, emptyPath, address(0), 0); + + _revertsOnNonFacadeCaller(); + adapter.swapDiffTokensForTokens(0, 0, emptyPath, 0); + + _revertsOnNonFacadeCaller(); + adapter.swapDiffTokensForTokensSupportingFeeOnTransferTokens(0, 0, emptyPath, 0); + } + + /// @notice U:[TJ-3]: `swapExactTokensForTokens` works as expected + function test_U_TJ_03_swapExactTokensForTokens_works_as_expected() public { + Path memory path = _makePath(0); + vm.expectRevert(ITraderJoeRouterAdapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); + + path = _makePath(2); + _readsActiveAccount(); + _executesSwap({ + tokenIn: tokens[0], + callData: abi.encodeCall(ITraderJoeRouter.swapExactTokensForTokens, (123, 456, path, creditAccount, 789)), + requiresApproval: true + }); + + vm.prank(creditFacade); + bool useSafePrices = adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); + assertTrue(useSafePrices); + } + + /// @notice U:[TJ-4]: `swapExactTokensForTokensSupportingFeeOnTransferTokens` works as expected + function test_U_TJ_04_swapExactTokensForTokensSupportingFeeOnTransferTokens_works_as_expected() public { + Path memory path = _makePath(0); + vm.expectRevert(ITraderJoeRouterAdapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.swapExactTokensForTokensSupportingFeeOnTransferTokens(123, 456, path, address(0), 789); + + path = _makePath(2); + _readsActiveAccount(); + _executesSwap({ + tokenIn: tokens[0], + callData: abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens, (123, 456, path, creditAccount, 789) + ), + requiresApproval: true + }); + + vm.prank(creditFacade); + bool useSafePrices = + adapter.swapExactTokensForTokensSupportingFeeOnTransferTokens(123, 456, path, address(0), 789); + assertTrue(useSafePrices); + } + + /// @notice U:[TJ-5]: `swapDiffTokensForTokens` works as expected + function test_U_TJ_05_swapDiffTokensForTokens_works_as_expected() public diffTestCases { + deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); + + Path memory path = _makePath(0); + vm.expectRevert(ITraderJoeRouterAdapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.swapDiffTokensForTokens(diffInputAmount, 0.5e27, path, 789); + + path = _makePath(2); + _readsActiveAccount(); + _executesSwap({ + tokenIn: tokens[0], + callData: abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokens, (diffInputAmount, diffInputAmount / 2, path, creditAccount, 789) + ), + requiresApproval: true + }); + + vm.prank(creditFacade); + bool useSafePrices = adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, path, 789); + assertTrue(useSafePrices); + } + + /// @notice U:[TJ-6]: `swapDiffTokensForTokensSupportingFeeOnTransferTokens` works as expected + function test_U_TJ_06_swapDiffTokensForTokensSupportingFeeOnTransferTokens_works_as_expected() + public + diffTestCases + { + deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); + + Path memory path = _makePath(0); + vm.expectRevert(ITraderJoeRouterAdapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.swapDiffTokensForTokensSupportingFeeOnTransferTokens(diffInputAmount, 0.5e27, path, 789); + + path = _makePath(2); + _readsActiveAccount(); + _executesSwap({ + tokenIn: tokens[0], + callData: abi.encodeCall( + ITraderJoeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens, + (diffInputAmount, diffInputAmount / 2, path, creditAccount, 789) + ), + requiresApproval: true + }); + + vm.prank(creditFacade); + bool useSafePrices = + adapter.swapDiffTokensForTokensSupportingFeeOnTransferTokens(diffLeftoverAmount, 0.5e27, path, 789); + assertTrue(useSafePrices); + } + + /// @notice U:[TJ-7]: `setPoolStatusBatch` works as expected + function test_U_TJ_07_setPoolStatusBatch_works_as_expected() public { + _setPoolsStatus(3, 0); + TraderJoePoolStatus[] memory pools = new TraderJoePoolStatus[](1); + + _revertsOnNonConfiguratorCaller(); + adapter.setPoolStatusBatch(pools); + + pools[0] = TraderJoePoolStatus(tokens[0], DUMB_ADDRESS, 10, Version.V2, true); + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatusBatch(pools); + + pools = new TraderJoePoolStatus[](2); + pools[0] = TraderJoePoolStatus(tokens[0], tokens[1], 10, Version.V2, false); + pools[1] = TraderJoePoolStatus(tokens[1], tokens[2], 20, Version.V2_1, true); + + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + + vm.expectEmit(true, true, false, true); + emit ITraderJoeRouterAdapter.SetPoolStatus( + _min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), 10, Version.V2, false + ); + + vm.expectEmit(true, true, false, true); + emit ITraderJoeRouterAdapter.SetPoolStatus( + _min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), 20, Version.V2_1, true + ); + + vm.prank(configurator); + adapter.setPoolStatusBatch(pools); + + assertFalse(adapter.isPoolAllowed(tokens[0], tokens[1], 10, Version.V2), "First pair incorrectly allowed"); + assertTrue(adapter.isPoolAllowed(tokens[1], tokens[2], 20, Version.V2_1), "Second pair incorrectly not allowed"); + + TraderJoePool[] memory allowedPools = adapter.supportedPools(); + + assertEq(allowedPools.length, 1, "Incorrect allowed pairs length"); + assertEq(allowedPools[0].token0, _min(tokens[1], tokens[2]), "Incorrect allowed pool token 0"); + assertEq(allowedPools[0].token1, _max(tokens[1], tokens[2]), "Incorrect allowed pool token 1"); + assertEq(allowedPools[0].binStep, 20, "Incorrect allowed pool binStep"); + assertEq(uint8(allowedPools[0].poolVersion), uint8(Version.V2_1), "Incorrect allowed pool version"); + } + + /// @notice U:[TJ-8]: `_validatePath` works as expected + function test_U_TJ_08_validatePath_works_as_expected() public { + bool isValid; + address tokenIn; + Path memory path; + + // insane paths + (isValid,) = adapter.validatePath(_makePath(0)); + assertFalse(isValid, "Empty path incorrectly valid"); + + (isValid,) = adapter.validatePath(_makePath(5)); + assertFalse(isValid, "Long path incorrectly valid"); + + // path with mismatched array lengths + path = _makePath(3); + path.pairBinSteps = new uint256[](1); + (isValid,) = adapter.validatePath(path); + assertFalse(isValid, "Path with mismatched arrays incorrectly valid"); + + // Path with correct length but invalid pools + path = _makePath(3); + _setPoolsStatus(3, 0); // Set all pools as invalid + (isValid, tokenIn) = adapter.validatePath(path); + assertFalse(isValid, "Path with invalid pools incorrectly valid"); + + // Valid path + path = _makePath(3); + _setPoolsStatus(3, 7); // Set all pools as valid + (isValid, tokenIn) = adapter.validatePath(path); + assertTrue(isValid, "Valid path incorrectly invalid"); + assertEq(tokenIn, tokens[0], "Incorrect tokenIn for valid path"); + + // Path with break in the middle + path = _makePath(3); + _setPoolsStatus(3, 5); // Set pool 1-2 as invalid + (isValid, tokenIn) = adapter.validatePath(path); + assertFalse(isValid, "Path with middle break incorrectly valid"); + } + + // ------- // + // HELPERS // + // ------- // + + /// @dev Returns a swap path with specified length (number of tokens = length + 1) + function _makePath(uint256 len) internal view returns (Path memory path) { + if (len < 2) { + return path; // Return empty path for len < 2 + } + + path.tokenPath = new IERC20[](len); + path.pairBinSteps = new uint256[](len - 1); + path.versions = new Version[](len - 1); + + for (uint256 i = 0; i < len; i++) { + path.tokenPath[i] = IERC20(tokens[i]); + } + + for (uint256 i = 0; i < len - 1; i++) { + path.pairBinSteps[i] = 10 * (i + 1); // 10, 20, 30, ... + path.versions[i] = Version.V2; + } + + return path; + } + + /// @dev Sets statuses for `len` consecutive pairs of `tokens` based on `allowedPoolsMask` + function _setPoolsStatus(uint256 len, uint256 allowedPoolsMask) internal { + TraderJoePoolStatus[] memory pools = new TraderJoePoolStatus[](len); + for (uint256 i = 0; i < len; i++) { + uint256 mask = 1 << i; + pools[i] = + TraderJoePoolStatus(tokens[i], tokens[i + 1], 10 * (i + 1), Version.V2, allowedPoolsMask & mask != 0); + } + vm.prank(configurator); + adapter.setPoolStatusBatch(pools); + } + + /// @dev Returns smaller of two addresses + function _min(address token0, address token1) internal pure returns (address) { + return token0 < token1 ? token0 : token1; + } + + /// @dev Returns larger of two addresses + function _max(address token0, address token1) internal pure returns (address) { + return token0 < token1 ? token1 : token0; + } +} diff --git a/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.harness.sol b/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.harness.sol index e186dd10..8c6f533a 100644 --- a/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.harness.sol +++ b/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.harness.sol @@ -1,18 +1,14 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {UniswapV2Adapter} from "../../../../adapters/uniswap/UniswapV2.sol"; contract UniswapV2AdapterHarness is UniswapV2Adapter { constructor(address creditManager, address router) UniswapV2Adapter(creditManager, router) {} - function validatePath(address[] memory path) - external - view - returns (bool valid, address tokenIn, address tokenOut) - { - (valid, tokenIn, tokenOut) = _validatePath(path); + function validatePath(address[] memory path) external view returns (bool valid, address tokenIn) { + (valid, tokenIn) = _validatePath(path); } } diff --git a/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.unit.t.sol b/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.unit.t.sol index 5f68a824..da492764 100644 --- a/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/uniswap/UniswapV2Adapter.unit.t.sol @@ -1,20 +1,20 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IUniswapV2Router01} from "../../../../integrations/uniswap/IUniswapV2Router01.sol"; import { - IUniswapV2AdapterEvents, - IUniswapV2AdapterExceptions, - UniswapV2PairStatus + IUniswapV2Adapter, UniswapV2PairStatus, UniswapV2Pair } from "../../../../interfaces/uniswap/IUniswapV2Adapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {UniswapV2AdapterHarness} from "./UniswapV2Adapter.harness.sol"; +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + /// @title Uniswap v2 adapter unit test /// @notice U:[UNI2]: Unit tests for Uniswap v2 swap router adapter -contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEvents, IUniswapV2AdapterExceptions { +contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper { UniswapV2AdapterHarness adapter; address router; @@ -29,9 +29,8 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve } /// @notice U:[UNI2-1]: Constructor works as expected - function test_U_UNI2_01_constructor_works_as_expected() public { + function test_U_UNI2_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), router, "Incorrect targetContract"); } @@ -52,7 +51,7 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve /// @notice U:[UNI2-3]: `swapTokensForExactTokens` works as expected function test_U_UNI2_03_swapTokensForExactTokens_works_as_expected() public { address[] memory path = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IUniswapV2Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); @@ -60,24 +59,19 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(IUniswapV2Router01.swapExactTokensForTokens, (123, 456, path, creditAccount, 789)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); + assertTrue(useSafePrices); } /// @notice U:[UNI2-4]: `swapExactTokensForTokens` works as expected function test_U_UNI2_04_swapExactTokensForTokens_works_as_expected() public { address[] memory path = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IUniswapV2Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); @@ -85,18 +79,13 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(IUniswapV2Router01.swapExactTokensForTokens, (123, 456, path, creditAccount, 789)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapExactTokensForTokens(123, 456, path, address(0), 789); + assertTrue(useSafePrices); } /// @notice U:[UNI2-5]: `swapDiffTokensForTokens` works as expected @@ -104,7 +93,7 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); address[] memory path = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IUniswapV2Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapDiffTokensForTokens(diffInputAmount, 0.5e27, path, 789); @@ -112,26 +101,27 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( IUniswapV2Router01.swapExactTokensForTokens, (diffInputAmount, diffInputAmount / 2, path, creditAccount, 789) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, path, 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, path, 789); + assertTrue(useSafePrices); } /// @notice U:[UNI2-6]: `setPairStatusBatch` works as expected function test_U_UNI2_06_setPairStatusBatch_works_as_expected() public { - UniswapV2PairStatus[] memory pairs; + _setPairsStatus(3, 0); + UniswapV2PairStatus[] memory pairs = new UniswapV2PairStatus[](1); + + pairs[0] = UniswapV2PairStatus(tokens[0], DUMB_ADDRESS, true); + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPairStatusBatch(pairs); _revertsOnNonConfiguratorCaller(); adapter.setPairStatusBatch(pairs); @@ -140,34 +130,44 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve pairs[0] = UniswapV2PairStatus(tokens[0], tokens[1], false); pairs[1] = UniswapV2PairStatus(tokens[1], tokens[2], true); + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + vm.expectEmit(true, true, false, true); - emit SetPairStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false); + emit IUniswapV2Adapter.SetPairStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false); vm.expectEmit(true, true, false, true); - emit SetPairStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true); + emit IUniswapV2Adapter.SetPairStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true); vm.prank(configurator); adapter.setPairStatusBatch(pairs); assertFalse(adapter.isPairAllowed(tokens[0], tokens[1]), "First pair incorrectly allowed"); assertTrue(adapter.isPairAllowed(tokens[1], tokens[2]), "Second pair incorrectly not allowed"); + + UniswapV2Pair[] memory allowedPairs = adapter.supportedPairs(); + + assertEq(allowedPairs.length, 1, "Incorrect allowed pairs length"); + + assertEq(allowedPairs[0].token0, _min(tokens[1], tokens[2]), "Incorrect allowed pair token 0"); + + assertEq(allowedPairs[0].token1, _max(tokens[1], tokens[2]), "Incorrect allowed pair token 1"); } /// @notice U:[UNI2-7]: `_validatePath` works as expected function test_U_UNI2_07_validatePath_works_as_expected() public { bool isValid; address tokenIn; - address tokenOut; address[] memory path; // insane paths - (isValid,,) = adapter.validatePath(new address[](0)); + (isValid,) = adapter.validatePath(new address[](0)); assertFalse(isValid, "Empty path incorrectly valid"); - (isValid,,) = adapter.validatePath(new address[](1)); + (isValid,) = adapter.validatePath(new address[](1)); assertFalse(isValid, "Short path incorrectly valid"); - (isValid,,) = adapter.validatePath(new address[](5)); + (isValid,) = adapter.validatePath(new address[](5)); assertFalse(isValid, "Long path incorrectly valid"); // exhaustive search @@ -177,12 +177,11 @@ contract UniswapV2AdapterUnitTest is AdapterUnitTestHelper, IUniswapV2AdapterEve uint256 numCases = 1 << (pathLen - 1); for (uint256 mask; mask < numCases; ++mask) { _setPairsStatus(pathLen - 1, mask); - (isValid, tokenIn, tokenOut) = adapter.validatePath(path); + (isValid, tokenIn) = adapter.validatePath(path); if (mask == numCases - 1) { assertTrue(isValid, "Path incorrectly invalid"); assertEq(tokenIn, tokens[0], "Incorrect tokenIn"); - assertEq(tokenOut, tokens[pathLen - 1], "Incorrect tokenOut"); } else { assertFalse(isValid, "Path incorrectly valid"); } diff --git a/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.harness.sol b/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.harness.sol index 8672d144..0664ea41 100644 --- a/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.harness.sol +++ b/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.harness.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {UniswapV3Adapter} from "../../../../adapters/uniswap/UniswapV3.sol"; diff --git a/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.unit.t.sol b/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.unit.t.sol index be9c540a..e3d9e414 100644 --- a/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/uniswap/UniswapV3Adapter.unit.t.sol @@ -1,26 +1,23 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ISwapRouter} from "../../../../integrations/uniswap/IUniswapV3.sol"; import { - IUniswapV3AdapterEvents, - IUniswapV3AdapterExceptions, + IUniswapV3Adapter, IUniswapV3AdapterTypes, - UniswapV3PoolStatus + UniswapV3PoolStatus, + UniswapV3Pool } from "../../../../interfaces/uniswap/IUniswapV3Adapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {UniswapV3AdapterHarness} from "./UniswapV3Adapter.harness.sol"; +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + /// @title Uniswap v3 adapter unit test /// @notice U:[UNI3]: Unit tests for Uniswap v3 swap router adapter -contract UniswapV3AdapterUnitTest is - AdapterUnitTestHelper, - IUniswapV3AdapterEvents, - IUniswapV3AdapterExceptions, - IUniswapV3AdapterTypes -{ +contract UniswapV3AdapterUnitTest is AdapterUnitTestHelper, IUniswapV3AdapterTypes { UniswapV3AdapterHarness adapter; address router; @@ -35,9 +32,8 @@ contract UniswapV3AdapterUnitTest is } /// @notice U:[UNI3-1]: Constructor works as expected - function test_U_UNI3_01_constructor_works_as_expected() public { + function test_U_UNI3_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), router, "Incorrect targetContract"); } @@ -68,6 +64,31 @@ contract UniswapV3AdapterUnitTest is adapter.exactOutput(p6); } + /// @notice U:[UNI3-2A]: Functions not utilizing `validatePath` revert on + /// unknown pool + function test_U_UNI3_02A_functions_revert_on_non_allowed_pool() public { + ISwapRouter.ExactInputSingleParams memory p1; + p1.tokenIn = DUMB_ADDRESS; + p1.tokenOut = tokens[0]; + vm.expectRevert(IUniswapV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactInputSingle(p1); + + ExactDiffInputSingleParams memory p2_2; + p2_2.tokenIn = DUMB_ADDRESS; + p2_2.tokenOut = tokens[0]; + vm.expectRevert(IUniswapV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactDiffInputSingle(p2_2); + + ISwapRouter.ExactOutputSingleParams memory p5; + p5.tokenIn = DUMB_ADDRESS; + p5.tokenOut = tokens[0]; + vm.expectRevert(IUniswapV3Adapter.InvalidPathException.selector); + vm.prank(creditFacade); + adapter.exactOutputSingle(p5); + } + /// @notice U:[UNI3-3]: `exactInputSingle` works as expected function test_U_UNI3_03_exactInputSingle_works_as_expected() public { ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ @@ -84,18 +105,14 @@ contract UniswapV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(ISwapRouter.exactInputSingle, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactInputSingle(params); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactInputSingle(params); + assertTrue(useSafePrices); } /// @notice U:[UNI3-4]: `exactDiffInputSingle` works as expected @@ -105,7 +122,6 @@ contract UniswapV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( ISwapRouter.exactInputSingle, ( @@ -120,13 +136,12 @@ contract UniswapV3AdapterUnitTest is sqrtPriceLimitX96: 0 }) ) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactDiffInputSingle( + bool useSafePrices = adapter.exactDiffInputSingle( ExactDiffInputSingleParams({ tokenIn: tokens[0], tokenOut: tokens[1], @@ -137,9 +152,7 @@ contract UniswapV3AdapterUnitTest is sqrtPriceLimitX96: 0 }) ); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + assertTrue(useSafePrices); } /// @notice U:[UNI3-5]: `exactInput` works as expected @@ -151,7 +164,7 @@ contract UniswapV3AdapterUnitTest is deadline: 789, recipient: creditAccount }); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IUniswapV3Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.exactInput(params); @@ -159,18 +172,14 @@ contract UniswapV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[2], callData: abi.encodeCall(ISwapRouter.exactInput, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactInput(params); - - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactInput(params); + assertTrue(useSafePrices); } /// @notice U:[UNI3-6]: `exactDiffInput` works as expected @@ -183,7 +192,7 @@ contract UniswapV3AdapterUnitTest is leftoverAmount: diffLeftoverAmount, rateMinRAY: 0.5e27 }); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IUniswapV3Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.exactDiffInput(params); @@ -191,7 +200,6 @@ contract UniswapV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[2], callData: abi.encodeCall( ISwapRouter.exactInput, ( @@ -203,16 +211,13 @@ contract UniswapV3AdapterUnitTest is recipient: creditAccount }) ) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactDiffInput(params); - - assertEq(tokensToEnable, 4, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactDiffInput(params); + assertTrue(useSafePrices); } /// @notice U:[UNI3-7]: `exactOutputSingle` works as expected @@ -231,18 +236,14 @@ contract UniswapV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(ISwapRouter.exactOutputSingle, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactOutputSingle(params); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactOutputSingle(params); + assertTrue(useSafePrices); } /// @notice U:[UNI3-8]: `exactOutput` works as expected @@ -254,7 +255,7 @@ contract UniswapV3AdapterUnitTest is deadline: 789, recipient: creditAccount }); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IUniswapV3Adapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.exactOutput(params); @@ -262,42 +263,58 @@ contract UniswapV3AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[2], // path is reversed for exactOutput - tokenOut: tokens[0], callData: abi.encodeCall(ISwapRouter.exactOutput, (params)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); params.recipient = address(0); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.exactOutput(params); - - assertEq(tokensToEnable, 1, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.exactOutput(params); + assertTrue(useSafePrices); } /// @notice U:[UNI3-9]: `setPoolStatusBatch` works as expected function test_U_UNI3_09_setPoolStatusBatch_works_as_expected() public { - UniswapV3PoolStatus[] memory pairs; + _setPoolsStatus(3, 0); + + UniswapV3PoolStatus[] memory pairs = new UniswapV3PoolStatus[](1); _revertsOnNonConfiguratorCaller(); adapter.setPoolStatusBatch(pairs); + pairs[0] = UniswapV3PoolStatus(DUMB_ADDRESS, tokens[2], 3000, true); + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatusBatch(pairs); + pairs = new UniswapV3PoolStatus[](2); pairs[0] = UniswapV3PoolStatus(tokens[0], tokens[1], 500, false); pairs[1] = UniswapV3PoolStatus(tokens[1], tokens[2], 3000, true); + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + vm.expectEmit(true, true, true, true); - emit SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), 500, false); + emit IUniswapV3Adapter.SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), 500, false); vm.expectEmit(true, true, true, true); - emit SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), 3000, true); + emit IUniswapV3Adapter.SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), 3000, true); vm.prank(configurator); adapter.setPoolStatusBatch(pairs); assertFalse(adapter.isPoolAllowed(tokens[0], tokens[1], 500), "First pool incorrectly allowed"); assertTrue(adapter.isPoolAllowed(tokens[1], tokens[2], 3000), "Second pool incorrectly not allowed"); + + UniswapV3Pool[] memory allowedPools = adapter.supportedPools(); + + assertEq(allowedPools.length, 1, "Incorrect allowed pairs length"); + + assertEq(allowedPools[0].token0, _min(tokens[1], tokens[2]), "Incorrect allowed pool token 0"); + + assertEq(allowedPools[0].token1, _max(tokens[1], tokens[2]), "Incorrect allowed pool token 1"); + + assertEq(allowedPools[0].fee, 3000, "Incorrect allowed pool fee"); } /// @notice U:[UNI3-10]: `_validatePath` works as expected diff --git a/contracts/test/unit/adapters/upshift/UpshiftVaultAdapter.unit.t.sol b/contracts/test/unit/adapters/upshift/UpshiftVaultAdapter.unit.t.sol new file mode 100644 index 00000000..a83148ee --- /dev/null +++ b/contracts/test/unit/adapters/upshift/UpshiftVaultAdapter.unit.t.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {UpshiftVaultAdapter} from "../../../../adapters/upshift/UpshiftVaultAdapter.sol"; +import {UpshiftVaultGateway} from "../../../../helpers/upshift/UpshiftVaultGateway.sol"; +import {IUpshiftVaultGateway} from "../../../../interfaces/upshift/IUpshiftVaultGateway.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IPhantomTokenAdapter} from "../../../../interfaces/IPhantomTokenAdapter.sol"; +import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +/// @title UpshiftVault adapter unit test +/// @notice U:[UV]: Unit tests for UpshiftVault adapter +contract UpshiftVaultAdapterUnitTest is AdapterUnitTestHelper { + UpshiftVaultAdapter adapter; + + address gateway; + address vault; + address asset; + address stakedPhantomToken; + + function setUp() public { + _setUp(); + + asset = tokens[0]; + vault = tokens[1]; + stakedPhantomToken = tokens[2]; + + vm.mockCall(vault, abi.encodeCall(IERC4626.asset, ()), abi.encode(asset)); + + gateway = address(new UpshiftVaultGateway(vault)); + + adapter = new UpshiftVaultAdapter(address(creditManager), gateway, stakedPhantomToken); + } + + /// @notice U:[UV-1]: Constructor works as expected + function test_U_UV_01_constructor_works_as_expected() public { + _readsTokenMask(asset); + _readsTokenMask(vault); + _readsTokenMask(stakedPhantomToken); + + adapter = new UpshiftVaultAdapter(address(creditManager), gateway, stakedPhantomToken); + + assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); + assertEq(adapter.targetContract(), gateway, "Incorrect targetContract"); + assertEq(adapter.asset(), asset, "Incorrect asset"); + assertEq(adapter.stakedPhantomToken(), stakedPhantomToken, "Incorrect stakedPhantomToken"); + assertEq(adapter.vault(), vault, "Incorrect vaultToken"); + } + + /// @notice U:[UV-2]: Wrapper functions revert on wrong caller + function test_U_UV_02_wrapper_functions_revert_on_wrong_caller() public { + _revertsOnNonFacadeCaller(); + adapter.requestRedeem(1000); + + _revertsOnNonFacadeCaller(); + adapter.claim(1000); + + _revertsOnNonFacadeCaller(); + adapter.withdrawPhantomToken(address(0), 0); + + _revertsOnNonFacadeCaller(); + adapter.depositPhantomToken(address(0), 0); + } + + /// @notice U:[UV-3]: Direct withdraw/redeem functions revert as expected + function test_U_UV_03_direct_withdraw_redeem_revert() public { + vm.prank(creditFacade); + vm.expectRevert(NotImplementedException.selector); + adapter.withdraw(1000, address(0), address(0)); + + vm.prank(creditFacade); + vm.expectRevert(NotImplementedException.selector); + adapter.redeem(1000, address(0), address(0)); + } + + /// @notice U:[UV-4]: `requestRedeem` works as expected + function test_U_UV_04_requestRedeem_works_as_expected() public { + _executesSwap({ + tokenIn: vault, + callData: abi.encodeCall(IUpshiftVaultGateway.requestRedeem, (1000)), + requiresApproval: true + }); + + vm.prank(creditFacade); + bool useSafePrices = adapter.requestRedeem(1000); + assertTrue(useSafePrices); + } + + /// @notice U:[UV-5]: `claim` works as expected + function test_U_UV_05_claim_works_as_expected() public { + _executesSwap({ + tokenIn: address(0), + callData: abi.encodeCall(IUpshiftVaultGateway.claim, (1000)), + requiresApproval: false + }); + + vm.prank(creditFacade); + bool useSafePrices = adapter.claim(1000); + assertFalse(useSafePrices); + } + + /// @notice U:[UV-6]: `withdrawPhantomToken` works as expected + function test_U_UV_06_withdrawPhantomToken_works_as_expected() public { + // Test with incorrect token + vm.expectRevert(IPhantomTokenAdapter.IncorrectStakedPhantomTokenException.selector); + vm.prank(creditFacade); + adapter.withdrawPhantomToken(address(0), 1000); + + // Test with correct token + _executesSwap({ + tokenIn: address(0), + callData: abi.encodeCall(IUpshiftVaultGateway.claim, (1000)), + requiresApproval: false + }); + + vm.prank(creditFacade); + bool useSafePrices = adapter.withdrawPhantomToken(stakedPhantomToken, 1000); + assertFalse(useSafePrices); + } + + /// @notice U:[UV-7]: `depositPhantomToken` reverts as expected + function test_U_UV_07_depositPhantomToken_reverts() public { + vm.prank(creditFacade); + vm.expectRevert(NotImplementedException.selector); + adapter.depositPhantomToken(stakedPhantomToken, 1000); + } +} diff --git a/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.harness.sol b/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.harness.sol index 49bd32d4..7d79c13b 100644 --- a/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.harness.sol +++ b/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.harness.sol @@ -1,18 +1,14 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {VelodromeV2RouterAdapter, Route} from "../../../../adapters/velodrome/VelodromeV2RouterAdapter.sol"; contract VelodromeV2AdapterHarness is VelodromeV2RouterAdapter { constructor(address creditManager, address router) VelodromeV2RouterAdapter(creditManager, router) {} - function validatePath(Route[] memory routes) - external - view - returns (bool valid, address tokenIn, address tokenOut) - { - (valid, tokenIn, tokenOut) = _validatePath(routes); + function validatePath(Route[] memory routes) external view returns (bool valid, address tokenIn) { + (valid, tokenIn) = _validatePath(routes); } } diff --git a/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.unit.t.sol b/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.unit.t.sol index 0031562f..74f1c3dc 100644 --- a/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/velodrome/VelodromeV2Adapter.unit.t.sol @@ -1,24 +1,22 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IVelodromeV2Router, Route} from "../../../../integrations/velodrome/IVelodromeV2Router.sol"; import { - IVelodromeV2AdapterEvents, - IVelodromeV2AdapterExceptions, - VelodromeV2PoolStatus + IVelodromeV2RouterAdapter, + VelodromeV2PoolStatus, + VelodromeV2Pool } from "../../../../interfaces/velodrome/IVelodromeV2RouterAdapter.sol"; import {AdapterUnitTestHelper} from "../AdapterUnitTestHelper.sol"; import {VelodromeV2AdapterHarness} from "./VelodromeV2Adapter.harness.sol"; +import "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; + /// @title Velodtome v2 adapter unit test /// @notice U:[VELO2]: Unit tests for Velodtome v2 swap router adapter -contract VelodtomeV2AdapterUnitTest is - AdapterUnitTestHelper, - IVelodromeV2AdapterEvents, - IVelodromeV2AdapterExceptions -{ +contract VelodtomeV2AdapterUnitTest is AdapterUnitTestHelper { VelodromeV2AdapterHarness adapter; address router; @@ -33,9 +31,8 @@ contract VelodtomeV2AdapterUnitTest is } /// @notice U:[VELO2-1]: Constructor works as expected - function test_U_VELO2_01_constructor_works_as_expected() public { + function test_U_VELO2_01_constructor_works_as_expected() public view { assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), router, "Incorrect targetContract"); } @@ -53,7 +50,7 @@ contract VelodtomeV2AdapterUnitTest is /// @notice U:[VELO2-3]: `swapExactTokensForTokens` works as expected function test_U_VELO2_03_swapExactTokensForTokens_works_as_expected() public { Route[] memory routes = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IVelodromeV2RouterAdapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapExactTokensForTokens(123, 456, routes, address(0), 789); @@ -61,18 +58,13 @@ contract VelodtomeV2AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall(IVelodromeV2Router.swapExactTokensForTokens, (123, 456, routes, creditAccount, 789)), - requiresApproval: true, - validatesTokens: true + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapExactTokensForTokens(123, 456, routes, address(0), 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapExactTokensForTokens(123, 456, routes, address(0), 789); + assertTrue(useSafePrices); } /// @notice U:[VELO2-4]: `swapDiffTokensForTokens` works as expected @@ -80,7 +72,7 @@ contract VelodtomeV2AdapterUnitTest is deal({token: tokens[0], to: creditAccount, give: diffMintedAmount}); Route[] memory routes = _makePath(0); - vm.expectRevert(InvalidPathException.selector); + vm.expectRevert(IVelodromeV2RouterAdapter.InvalidPathException.selector); vm.prank(creditFacade); adapter.swapDiffTokensForTokens(diffInputAmount, 0.5e27, routes, 789); @@ -88,39 +80,47 @@ contract VelodtomeV2AdapterUnitTest is _readsActiveAccount(); _executesSwap({ tokenIn: tokens[0], - tokenOut: tokens[1], callData: abi.encodeCall( IVelodromeV2Router.swapExactTokensForTokens, (diffInputAmount, diffInputAmount / 2, routes, creditAccount, 789) - ), - requiresApproval: true, - validatesTokens: true + ), + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = - adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, routes, 789); - - assertEq(tokensToEnable, 2, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? 1 : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.swapDiffTokensForTokens(diffLeftoverAmount, 0.5e27, routes, 789); + assertTrue(useSafePrices); } /// @notice U:[VELO2-5]: `setPoolStatusBatch` works as expected - function test_U_VELO2_05_setPoolStatusBatch_oolworks_as_expected() public { - VelodromeV2PoolStatus[] memory pools; + function test_U_VELO2_05_setPoolStatusBatch_works_as_expected() public { + _setPoolsStatus(3, 0); + VelodromeV2PoolStatus[] memory pools = new VelodromeV2PoolStatus[](1); _revertsOnNonConfiguratorCaller(); adapter.setPoolStatusBatch(pools); + pools[0] = VelodromeV2PoolStatus(tokens[0], DUMB_ADDRESS, false, address(42), true); + _revertsOnUnknownToken(); + vm.prank(configurator); + adapter.setPoolStatusBatch(pools); + pools = new VelodromeV2PoolStatus[](2); pools[0] = VelodromeV2PoolStatus(tokens[0], tokens[1], false, address(42), false); pools[1] = VelodromeV2PoolStatus(tokens[1], tokens[2], true, address(32), true); + _readsTokenMask(tokens[1]); + _readsTokenMask(tokens[2]); + vm.expectEmit(true, true, false, true); - emit SetPoolStatus(_min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false, address(42), false); + emit IVelodromeV2RouterAdapter.SetPoolStatus( + _min(tokens[0], tokens[1]), _max(tokens[0], tokens[1]), false, address(42), false + ); vm.expectEmit(true, true, false, true); - emit SetPoolStatus(_min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true, address(32), true); + emit IVelodromeV2RouterAdapter.SetPoolStatus( + _min(tokens[1], tokens[2]), _max(tokens[1], tokens[2]), true, address(32), true + ); vm.prank(configurator); adapter.setPoolStatusBatch(pools); @@ -129,20 +129,31 @@ contract VelodtomeV2AdapterUnitTest is assertTrue( adapter.isPoolAllowed(tokens[1], tokens[2], true, address(32)), "Second pair incorrectly not allowed" ); + + VelodromeV2Pool[] memory allowedPools = adapter.supportedPools(); + + assertEq(allowedPools.length, 1, "Incorrect allowed pairs length"); + + assertEq(allowedPools[0].token0, _min(tokens[1], tokens[2]), "Incorrect allowed pool token 0"); + + assertEq(allowedPools[0].token1, _max(tokens[1], tokens[2]), "Incorrect allowed pool token 1"); + + assertTrue(allowedPools[0].stable, "Incorrect allowed pools stable status"); + + assertEq(allowedPools[0].factory, address(32), "Incorrect allowed pool factory"); } /// @notice U:[VELO2-6]: `_validatePath` works as expected function test_U_VELO2_06_validatePath_works_as_expected() public { bool isValid; address tokenIn; - address tokenOut; Route[] memory routes; // insane paths - (isValid,,) = adapter.validatePath(new Route[](0)); + (isValid,) = adapter.validatePath(new Route[](0)); assertFalse(isValid, "Empty path incorrectly valid"); - (isValid,,) = adapter.validatePath(new Route[](4)); + (isValid,) = adapter.validatePath(new Route[](4)); assertFalse(isValid, "Long path incorrectly valid"); // exhaustive search @@ -152,12 +163,11 @@ contract VelodtomeV2AdapterUnitTest is uint256 numCases = 1 << (pathLen - 1); for (uint256 mask; mask < numCases; ++mask) { _setPoolsStatus(pathLen - 1, mask); - (isValid, tokenIn, tokenOut) = adapter.validatePath(routes); + (isValid, tokenIn) = adapter.validatePath(routes); if (mask == numCases - 1) { assertTrue(isValid, "Path incorrectly invalid"); assertEq(tokenIn, tokens[0], "Incorrect tokenIn"); - assertEq(tokenOut, tokens[pathLen - 1], "Incorrect tokenOut"); } else { assertFalse(isValid, "Path incorrectly valid"); } @@ -169,7 +179,6 @@ contract VelodtomeV2AdapterUnitTest is function test_U_VELO2_07_validatePath_filters_disjunct_paths() public { bool isValid; address tokenIn; - address tokenOut; Route[] memory routes; VelodromeV2PoolStatus[] memory pools = new VelodromeV2PoolStatus[](2); @@ -182,7 +191,7 @@ contract VelodtomeV2AdapterUnitTest is routes[0] = Route({from: tokens[0], to: tokens[1], stable: false, factory: address(42)}); routes[1] = Route({from: tokens[2], to: tokens[3], stable: false, factory: address(42)}); - (isValid, tokenIn, tokenOut) = adapter.validatePath(routes); + (isValid, tokenIn) = adapter.validatePath(routes); assertFalse(isValid, "Path incorrectly valid"); } diff --git a/contracts/test/unit/adapters/yearn/YearnV2Adapter.unit.t.sol b/contracts/test/unit/adapters/yearn/YearnV2Adapter.unit.t.sol index 02bbddb3..d8cd8003 100644 --- a/contracts/test/unit/adapters/yearn/YearnV2Adapter.unit.t.sol +++ b/contracts/test/unit/adapters/yearn/YearnV2Adapter.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {YearnV2Adapter} from "../../../../adapters/yearn/YearnV2.sol"; import {IYVault} from "../../../../integrations/yearn/IYVault.sol"; @@ -15,14 +15,12 @@ contract YearnV2AdapterUnitTest is AdapterUnitTestHelper { address token; address yToken; - uint256 tokenMask; - uint256 yTokenMask; - function setUp() public { _setUp(); - (token, tokenMask) = (tokens[0], 1); - (yToken, yTokenMask) = (tokens[1], 2); + token = tokens[0]; + yToken = tokens[1]; + vm.mockCall(yToken, abi.encodeCall(IYVault.token, ()), abi.encode(token)); adapter = new YearnV2Adapter(address(creditManager), yToken); @@ -35,11 +33,8 @@ contract YearnV2AdapterUnitTest is AdapterUnitTestHelper { adapter = new YearnV2Adapter(address(creditManager), yToken); assertEq(adapter.creditManager(), address(creditManager), "Incorrect creditManager"); - assertEq(adapter.addressProvider(), address(addressProvider), "Incorrect addressProvider"); assertEq(adapter.targetContract(), yToken, "Incorrect targetContract"); assertEq(adapter.token(), token, "Incorrect token"); - assertEq(adapter.tokenMask(), tokenMask, "Incorrect tokenMask"); - assertEq(adapter.yTokenMask(), yTokenMask, "Incorrect yTokenMask"); } /// @notice U:[YFI2-2]: Wrapper functions revert on wrong caller @@ -73,48 +68,36 @@ contract YearnV2AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: token, - tokenOut: yToken, callData: abi.encodeWithSignature("deposit(uint256)", diffInputAmount), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.depositDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, yTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? tokenMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.depositDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } /// @notice U:[YFI2-4]: `deposit(uint256)` works as expected function test_U_YFI2_04_deposit_uint256_works_as_expected() public { _executesSwap({ tokenIn: token, - tokenOut: yToken, callData: abi.encodeWithSignature("deposit(uint256)", 1000), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(1000); - - assertEq(tokensToEnable, yTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.deposit(1000); + assertFalse(useSafePrices); } /// @notice U:[YFI2-5]: `deposit(uint256,address)` works as expected function test_U_YFI2_05_deposit_uint256_address_works_as_expected() public { _executesSwap({ tokenIn: token, - tokenOut: yToken, callData: abi.encodeWithSignature("deposit(uint256)", 1000), - requiresApproval: true, - validatesTokens: false + requiresApproval: true }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.deposit(1000, address(0)); - - assertEq(tokensToEnable, yTokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.deposit(1000, address(0)); + assertFalse(useSafePrices); } /// @notice U:[YFI2-6]: `withdrawDiff()` works as expected @@ -124,48 +107,36 @@ contract YearnV2AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: yToken, - tokenOut: token, callData: abi.encodeWithSignature("withdraw(uint256)", diffInputAmount), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdrawDiff(diffLeftoverAmount); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, diffDisableTokenIn ? yTokenMask : 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdrawDiff(diffLeftoverAmount); + assertFalse(useSafePrices); } /// @notice U:[YFI2-7]: `withdraw(uint256)` works as expected function test_U_YFI2_07_withdraw_uint256_works_as_expected() public { _executesSwap({ tokenIn: yToken, - tokenOut: token, callData: abi.encodeWithSignature("withdraw(uint256)", 1000), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(1000); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(1000); + assertFalse(useSafePrices); } /// @notice U:[YFI2-8]: `withdraw(uint256,address)` works as expected function test_U_YFI2_08_withdraw_uint256_address_works_as_expected() public { _executesSwap({ tokenIn: yToken, - tokenOut: token, callData: abi.encodeWithSignature("withdraw(uint256)", 1000), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(1000, address(0)); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(1000, address(0)); + assertFalse(useSafePrices); } /// @notice U:[YFI2-9]: `withdraw(uint256,address,uint256)` works as expected @@ -173,15 +144,11 @@ contract YearnV2AdapterUnitTest is AdapterUnitTestHelper { _readsActiveAccount(); _executesSwap({ tokenIn: yToken, - tokenOut: token, callData: abi.encodeWithSignature("withdraw(uint256,address,uint256)", 1000, creditAccount, 10), - requiresApproval: false, - validatesTokens: false + requiresApproval: false }); vm.prank(creditFacade); - (uint256 tokensToEnable, uint256 tokensToDisable) = adapter.withdraw(1000, address(0), 10); - - assertEq(tokensToEnable, tokenMask, "Incorrect tokensToEnable"); - assertEq(tokensToDisable, 0, "Incorrect tokensToDisable"); + bool useSafePrices = adapter.withdraw(1000, address(0), 10); + assertFalse(useSafePrices); } } diff --git a/contracts/test/unit/helpers/aave/AaveV2_WrappedAToken.unit.t.sol b/contracts/test/unit/helpers/aave/AaveV2_WrappedAToken.unit.t.sol deleted file mode 100644 index ff6f9fcb..00000000 --- a/contracts/test/unit/helpers/aave/AaveV2_WrappedAToken.unit.t.sol +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {Test} from "forge-std/Test.sol"; - -import {WAD} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; -import {ZeroAddressException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; - -import {IWrappedATokenEvents, WrappedAToken} from "../../../../helpers/aave/AaveV2_WrappedAToken.sol"; - -import {LendingPoolMock} from "../../../mocks/integrations/aave/LendingPoolMock.sol"; -import {ERC20Mock} from "@gearbox-protocol/core-v3/contracts/test/mocks/token/ERC20Mock.sol"; -import {FRIEND, USER} from "@gearbox-protocol/core-v3/contracts/test/lib/constants.sol"; -import {BalanceHelper} from "@gearbox-protocol/core-v3/contracts/test/helpers/BalanceHelper.sol"; -import {TokensTestSuite} from "@gearbox-protocol/core-v3/contracts/test/suites/TokensTestSuite.sol"; - -/// @title Wrapped aToken unit test -/// @notice U:[WAT]: Unit tests for Wrapped aToken -contract WrappedATokenUnitTest is Test, BalanceHelper, IWrappedATokenEvents { - WrappedAToken public waToken; - - LendingPoolMock lendingPool; - address token; - address aToken; - - uint256 constant TOKEN_AMOUNT = 1e10; - - function setUp() public { - tokenTestSuite = new TokensTestSuite(); - lendingPool = new LendingPoolMock(); - - token = address(new ERC20Mock("Test Token", "TEST", 6)); - aToken = lendingPool.addReserve(token, 0.02e27); // 2% - deal(token, aToken, 1e12); // add some liquidity - waToken = new WrappedAToken(aToken); - - vm.label(token, "TOKEN"); - vm.label(aToken, "aTOKEN"); - vm.label(address(waToken), "waTOKEN"); - vm.label(address(lendingPool), "LENDING_POOL"); - - vm.warp(block.timestamp + 365 days); - } - - /// @notice U:[WAT-1]: Constructor reverts on zero address - function test_U_WAT_01_constructor_reverts_on_zero_address() public { - vm.expectRevert(ZeroAddressException.selector); - new WrappedAToken(address(0)); - } - - /// @notice U:[WAT-2]: Constructor sets correct values - function test_U_WAT_02_constructor_sets_correct_values() public { - assertEq(waToken.aToken(), aToken, "Incorrect aUSDC address"); - assertEq(waToken.underlying(), token, "Incorrect USDC address"); - assertEq(waToken.lendingPool(), address(lendingPool), "Incorrect lending pool address"); - assertEq(waToken.name(), "Wrapped Aave interest bearing Test Token", "Incorrect name"); - assertEq(waToken.symbol(), "waTEST", "Incorrect symbol"); - assertEq(waToken.decimals(), 6, "Incorrect decimals"); - assertEq( - ERC20Mock(token).allowance(address(waToken), address(lendingPool)), type(uint256).max, "Incorrect allowance" - ); - } - - /// @notice U:[WAT-3]: `balanceOfUnderlying` works correctly - /// @dev Fuzzing times before measuring balances - /// @dev Small deviations in expected and actual balances are allowed due to rounding errors - /// Generally, dust size grows with time and number of operations on the wrapper - /// Nevertheless, the test shows that wrapper stays solvent and doesn't lose deposited funds - function test_U_WAT_03_balanceOfUnderlying_works_correctly(uint256 timedelta1, uint256 timedelta2) public { - vm.assume(timedelta1 < 5 * 365 days && timedelta2 < 5 * 365 days); - uint256 balance1; - uint256 balance2; - - // mint equivalent amounts of aTokens and waTokens to first user and wait for some time - _mintAToken(USER); - _mintWAToken(USER); - vm.warp(block.timestamp + timedelta1); - - // balances must stay equivalent (up to some dust) - balance1 = waToken.balanceOfUnderlying(USER); - expectBalanceGe(aToken, USER, balance1, "user 1 after t1"); - expectBalanceLe(aToken, USER, balance1 + 2, "user 1 after t1"); - - // also, wrapper's total balance of aToken must be equal to user's balances of underlying - expectBalanceGe(aToken, address(waToken), balance1, "wrapper after t1"); - expectBalanceLe(aToken, address(waToken), balance1 + 2, "wrapper after t1"); - - // now mint equivalent amounts of aTokens and waTokens to second user and wait for more time - _mintAToken(FRIEND); - _mintWAToken(FRIEND); - vm.warp(block.timestamp + timedelta2); - - // balances must stay equivalent for both users - balance1 = waToken.balanceOfUnderlying(USER); - expectBalanceGe(aToken, USER, balance1, "user 1 after t2"); - expectBalanceLe(aToken, USER, balance1 + 2, "user 1 after t2"); - - balance2 = waToken.balanceOfUnderlying(FRIEND); - expectBalanceGe(aToken, FRIEND, balance2, "user 2 after t2"); - expectBalanceLe(aToken, FRIEND, balance2 + 2, "user 2 after t2"); - - // finally, wrapper's total balance of aToken must be equal to sum of users' balances of underlying - expectBalanceGe(aToken, address(waToken), balance1 + balance2 - 1, "wrapper after t2"); - expectBalanceLe(aToken, address(waToken), balance1 + balance2 + 4, "wrapper after t2"); - } - - /// @notice U:[WAT-4]: `exchangeRate` can not be manipulated - function test_U_WAT_04_exchangeRate_can_not_be_manipulated() public { - uint256 exchangeRateBefore = waToken.exchangeRate(); - - deal(token, address(this), TOKEN_AMOUNT); - tokenTestSuite.approve(token, address(this), address(lendingPool), TOKEN_AMOUNT); - lendingPool.deposit(token, TOKEN_AMOUNT, address(waToken), 0); - - assertEq(waToken.exchangeRate(), exchangeRateBefore, "exchangeRate changed"); - } - - /// @notice U:[WAT-5]: `deposit` works correctly - /// @dev Fuzzing time before deposit to see if wrapper handles interest properly - /// @dev Final aToken balances are allowed to deviate by 1 from expected values due to rounding - function test_U_WAT_05_deposit_works_correctly(uint256 timedelta) public { - vm.assume(timedelta < 3 * 365 days); - vm.warp(block.timestamp + timedelta); - uint256 amount = _mintAToken(USER); - - uint256 assets = amount / 2; - uint256 expectedShares = assets * WAD / waToken.exchangeRate(); - - tokenTestSuite.approve(aToken, USER, address(waToken), assets); - - vm.expectEmit(true, false, false, true); - emit Deposit(USER, assets, expectedShares); - - vm.prank(USER); - uint256 shares = waToken.deposit(assets); - - assertEq(shares, expectedShares); - - expectBalanceGe(aToken, USER, amount - assets - 1, ""); - expectBalanceLe(aToken, USER, amount - assets + 1, ""); - expectBalance(address(waToken), USER, shares); - - assertEq(waToken.totalSupply(), shares); - expectBalanceGe(aToken, address(waToken), assets - 1, ""); - expectBalanceLe(aToken, address(waToken), assets + 1, ""); - } - - /// @notice U:[WAT-6]: `depositUnderlying` works correctly - /// @dev Fuzzing time before deposit to see if wrapper handles interest properly - /// @dev Final aToken balances are allowed to deviate by 1 from expected values due to rounding - function test_U_WAT_06_depositUnderlying_works_correctly(uint256 timedelta) public { - vm.assume(timedelta < 3 * 365 days); - vm.warp(block.timestamp + timedelta); - uint256 amount = _mintUnderlying(USER); - - uint256 assets = amount / 2; - uint256 expectedShares = assets * WAD / waToken.exchangeRate(); - - tokenTestSuite.approve(token, USER, address(waToken), assets); - - vm.expectCall(address(lendingPool), abi.encodeCall(lendingPool.deposit, (token, assets, address(waToken), 0))); - - vm.expectEmit(true, false, false, true); - emit Deposit(USER, assets, expectedShares); - - vm.prank(USER); - uint256 shares = waToken.depositUnderlying(assets); - - assertEq(shares, expectedShares); - - expectBalance(token, USER, amount - assets); - expectBalance(address(waToken), USER, shares); - - assertEq(waToken.totalSupply(), shares); - expectBalance(token, address(waToken), 0); - expectBalanceGe(aToken, address(waToken), assets - 1, ""); - expectBalanceLe(aToken, address(waToken), assets + 1, ""); - assertEq( - ERC20Mock(token).allowance(address(waToken), address(lendingPool)), type(uint256).max, "Incorrect allowance" - ); - } - - /// @notice U:[WAT-7]: `withdraw` works correctly - /// @dev Fuzzing time before deposit to see if wrapper handles interest properly - /// @dev Final aToken balances are allowed to deviate by 1 from expected values due to rounding - function test_U_WAT_07_withdraw_works_correctly(uint256 timedelta) public { - vm.assume(timedelta < 3 * 365 days); - uint256 amount = _mintWAToken(USER); - vm.warp(block.timestamp + timedelta); - - uint256 shares = amount / 2; - uint256 expectedAssets = shares * waToken.exchangeRate() / WAD; - uint256 wrapperBalance = tokenTestSuite.balanceOf(aToken, address(waToken)); - - vm.expectEmit(true, false, false, true); - emit Withdraw(USER, expectedAssets, shares); - - vm.prank(USER); - uint256 assets = waToken.withdraw(shares); - - assertEq(assets, expectedAssets); - - expectBalanceGe(aToken, USER, assets - 1, ""); - expectBalanceLe(aToken, USER, assets + 1, ""); - expectBalance(address(waToken), USER, amount - shares); - - assertEq(waToken.totalSupply(), amount - shares); - expectBalanceGe(aToken, address(waToken), wrapperBalance - assets - 1, ""); - expectBalanceLe(aToken, address(waToken), wrapperBalance - assets + 1, ""); - } - - /// @notice U:[WAT-8]: `withdrawUnderlying` works correctly - /// @dev Fuzzing time before deposit to see if wrapper handles interest properly - /// @dev Final aToken balances are allowed to deviate by 1 from expected values due to rounding - function test_U_WAT_08_withdrawUnderlying_works_correctly(uint256 timedelta) public { - vm.assume(timedelta < 3 * 365 days); - uint256 amount = _mintWAToken(USER); - vm.warp(block.timestamp + timedelta); - - uint256 shares = amount / 2; - uint256 expectedAssets = shares * waToken.exchangeRate() / WAD; - uint256 wrapperBalance = tokenTestSuite.balanceOf(aToken, address(waToken)); - - vm.expectEmit(true, false, false, true); - emit Withdraw(USER, expectedAssets, shares); - - vm.expectCall(address(lendingPool), abi.encodeCall(lendingPool.withdraw, (token, expectedAssets, USER))); - - vm.prank(USER); - uint256 assets = waToken.withdrawUnderlying(shares); - - assertEq(assets, expectedAssets); - - expectBalance(token, USER, assets); - expectBalance(address(waToken), USER, amount - shares); - - assertEq(waToken.totalSupply(), amount - shares); - expectBalance(token, address(waToken), 0); - expectBalanceGe(aToken, address(waToken), wrapperBalance - assets - 1, ""); - expectBalanceLe(aToken, address(waToken), wrapperBalance - assets + 1, ""); - } - - /// @dev Mints token to user - function _mintUnderlying(address user) internal returns (uint256 amount) { - amount = TOKEN_AMOUNT; - deal(token, user, amount); - } - - /// @dev Mints aToken to user - function _mintAToken(address user) internal returns (uint256 amount) { - amount = _mintUnderlying(user); - tokenTestSuite.approve(token, user, address(lendingPool), amount); - vm.prank(user); - lendingPool.deposit(token, amount, address(user), 0); - } - - /// @dev Mints waToken to user - function _mintWAToken(address user) internal returns (uint256 amount) { - uint256 assets = _mintUnderlying(user); - tokenTestSuite.approve(token, user, address(waToken), assets); - vm.prank(user); - amount = waToken.depositUnderlying(assets); - } -} diff --git a/contracts/test/unit/helpers/compound/CompoundV2_CEtherGateway.unit.t.sol b/contracts/test/unit/helpers/compound/CompoundV2_CEtherGateway.unit.t.sol deleted file mode 100644 index aec82c13..00000000 --- a/contracts/test/unit/helpers/compound/CompoundV2_CEtherGateway.unit.t.sol +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {Test} from "forge-std/Test.sol"; - -import {Address} from "@openzeppelin/contracts/utils/Address.sol"; - -import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; -import {ZeroAddressException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; -import "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; -import {TokensTestSuite} from "@gearbox-protocol/core-v3/contracts/test/suites/TokensTestSuite.sol"; - -import {CEtherGateway} from "../../../../helpers/compound/CompoundV2_CEtherGateway.sol"; -import {ICompoundV2_Exceptions} from "../../../../interfaces/compound/ICompoundV2_CTokenAdapter.sol"; - -import {CEtherMock, REDEEM_ERROR, REDEEM_UNDERLYING_ERROR} from "../../../mocks/integrations/compound/CEtherMock.sol"; - -/// @title CEther gateway unit test -/// @notice U:[CEG]: Unit tests for Compound v2 CEther gateway -contract CEtherGatewayUnitTest is Test, ICompoundV2_Exceptions { - using Address for address payable; - - IWETH weth; - CEtherMock ceth; - CEtherGateway gateway; - - address user; - - TokensTestSuite tokensTestSuite; - uint256 constant WETH_AMOUNT = 10 ether; - - function setUp() public { - tokensTestSuite = new TokensTestSuite(); - - weth = IWETH(tokensTestSuite.addressOf(TOKEN_WETH)); - - // initial exchange rate 0.02 cETH per ETH, 5% yearly interest - ceth = new CEtherMock(0.02 ether, 0.05 ether); - vm.deal(address(ceth), 100 ether); - skip(365 days); - - gateway = new CEtherGateway(address(weth), address(ceth)); - - vm.label(address(weth), "WETH"); - vm.label(address(ceth), "cETH"); - vm.label(address(gateway), "cETH_GATEWAY"); - - user = makeAddr("user"); - } - - /// @notice U:[CEG-1]: Constructor works as expected - function test_U_CEG_01_constructor_works_as_expected() public { - vm.expectRevert(ZeroAddressException.selector); - new CEtherGateway(address(0), address(ceth)); - - vm.expectRevert(ZeroAddressException.selector); - new CEtherGateway(address(weth), address(0)); - - assertEq(gateway.weth(), address(weth), "Incorrect WETH address"); - assertEq(gateway.ceth(), address(ceth), "Incorrect cETH address"); - } - - /// @notice U:[CEG-2]: Gateway can receive ETH - function test_U_CEG_02_gateway_can_receive_eth() public { - assertEq(address(gateway).balance, 0); - payable(gateway).sendValue(1 ether); - assertEq(address(gateway).balance, 1 ether); - } - - /// @notice U:[CEG-3]: `mint` works as expected - function test_U_CEG_03_mint_works_as_expected() public { - uint256 mintAmount = 10 ether; - tokensTestSuite.mint(TOKEN_WETH, user, mintAmount); - tokensTestSuite.approve(TOKEN_WETH, user, address(gateway), mintAmount); - - uint256 cethBalanceExpected = mintAmount * 1 ether / ceth.exchangeRateCurrent(); - - vm.expectCall(address(weth), abi.encodeCall(IWETH.withdraw, (mintAmount))); - vm.expectCall(address(ceth), mintAmount, abi.encodeCall(CEtherMock.mint, ())); - - vm.prank(user); - uint256 error = gateway.mint(mintAmount); - - assertEq(error, 0, "Non-zero error code"); - assertEq(tokensTestSuite.balanceOf(address(weth), user), 0, "Incorrect WETH balance"); - assertEq(tokensTestSuite.balanceOf(address(ceth), user), cethBalanceExpected, "Incorrect cETH balance"); - } - - /// @notice U:[CEG-4]: `redeem` works as expected - function test_U_CEG_04_redeem_works_as_expected() public { - uint256 cethBalance = _mintCEther(10 ether); - - uint256 redeemTokens = cethBalance / 2; - tokensTestSuite.approve(address(ceth), user, address(gateway), redeemTokens); - - uint256 redeemAmountExpected = redeemTokens * ceth.exchangeRateCurrent() / 1 ether; - - vm.expectCall(address(ceth), abi.encodeCall(CEtherMock.redeem, (redeemTokens))); - vm.expectCall(address(weth), redeemAmountExpected, abi.encodeCall(IWETH.deposit, ())); - - vm.prank(user); - uint256 error = gateway.redeem(redeemTokens); - - assertEq(error, 0, "Non-zero error code"); - assertEq(tokensTestSuite.balanceOf(address(weth), user), redeemAmountExpected, "Incorrect WETH balance"); - assertEq(tokensTestSuite.balanceOf(address(ceth), user), cethBalance - redeemTokens, "Incorrect cETH balance"); - } - - /// @notice U:[CEG-5]: `redeemUnderlying` works as expected - function test_U_CEG_05_redeemUnderlying_works_as_expected() public { - uint256 cethBalance = _mintCEther(10 ether); - - uint256 redeemAmount = 5 ether; - tokensTestSuite.approve(address(ceth), user, address(gateway), cethBalance); - - uint256 redeemTokensExpected = redeemAmount * 1 ether / ceth.exchangeRateCurrent(); - - vm.expectCall(address(ceth), abi.encodeCall(CEtherMock.redeemUnderlying, (redeemAmount))); - vm.expectCall(address(weth), redeemAmount, abi.encodeCall(IWETH.deposit, ())); - - vm.prank(user); - uint256 error = gateway.redeemUnderlying(redeemAmount); - - assertEq(error, 0, "Non-zero error code"); - assertEq(tokensTestSuite.balanceOf(address(weth), user), redeemAmount, "Incorrect WETH balance"); - assertEq( - tokensTestSuite.balanceOf(address(ceth), user), cethBalance - redeemTokensExpected, "Incorrect cETH balance" - ); - } - - /// @notice U:[CEG-6]: redeem functions revert on non-zero CEther error code - function test_U_CEG_06_redeem_functions_revert_on_non_zero_error_code() public { - uint256 cethBalance = _mintCEther(10 ether); - tokensTestSuite.approve(address(ceth), user, address(gateway), cethBalance); - - ceth.setFailing(true); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, REDEEM_ERROR)); - vm.prank(user); - gateway.redeem(1 ether); - - vm.expectRevert(abi.encodeWithSelector(CTokenError.selector, REDEEM_UNDERLYING_ERROR)); - vm.prank(user); - gateway.redeemUnderlying(1 ether); - } - - /// @dev Deposits given amount of WETH to cETH through gateway for user - function _mintCEther(uint256 mintAmount) internal returns (uint256 cethBalance) { - tokensTestSuite.mint(TOKEN_WETH, user, mintAmount); - tokensTestSuite.approve(TOKEN_WETH, user, address(gateway), mintAmount); - vm.prank(user); - gateway.mint(WETH_AMOUNT); - - cethBalance = tokensTestSuite.balanceOf(address(ceth), user); - skip(365 days); - } -} diff --git a/contracts/test/unit/helpers/fluid/FluidDexETHGateway.unit.t.sol b/contracts/test/unit/helpers/fluid/FluidDexETHGateway.unit.t.sol new file mode 100644 index 00000000..971f57c1 --- /dev/null +++ b/contracts/test/unit/helpers/fluid/FluidDexETHGateway.unit.t.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; + +import {Test} from "forge-std/Test.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ERC20Mock} from "@gearbox-protocol/core-v3/contracts/test/mocks/token/ERC20Mock.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; +import {ZeroAddressException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; + +import {FluidDexETHGateway} from "../../../../helpers/fluid/FluidDexETHGateway.sol"; +import {IFluidDex, ConstantViews, Implementations} from "../../../../integrations/fluid/IFluidDex.sol"; +import {WETHMock} from "../../../mocks/token/WETHMock.sol"; + +/// @title Mock FluidDex pool contract for testing +contract FluidDexPoolMock is IFluidDex { + address public immutable token0; + address public immutable token1; + uint256 public immutable dexId; + + // Exchange rate: 1 ETH = exchangeRate tokens (scaled by 1e18) + uint256 public exchangeRate = 1e18; // 1:1 by default + + // Special ETH address used by Fluid + address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + constructor(address _token0, address _token1, uint256 _dexId) { + token0 = _token0; + token1 = _token1; + dexId = _dexId; + } + + function setExchangeRate(uint256 _rate) external { + exchangeRate = _rate; + } + + function swapIn(bool swap0to1, uint256 amountIn, uint256, address to) + external + payable + returns (uint256 amountOut) + { + if (swap0to1) { + if (token0 == ETH) { + require(msg.value == amountIn, "ETH amount mismatch"); + amountOut = (amountIn * exchangeRate) / 1e18; + IERC20(token1).transfer(to, amountOut); + } else { + IERC20(token0).transferFrom(msg.sender, address(this), amountIn); + amountOut = (amountIn * exchangeRate) / 1e18; + payable(to).transfer(amountOut); + } + } else { + if (token1 == ETH) { + require(msg.value == amountIn, "ETH amount mismatch"); + amountOut = (amountIn * 1e18) / exchangeRate; + IERC20(token0).transfer(to, amountOut); + } else { + IERC20(token1).transferFrom(msg.sender, address(this), amountIn); + amountOut = (amountIn * 1e18) / exchangeRate; + payable(to).transfer(amountOut); + } + } + } + + function constantsView() external view returns (ConstantViews memory) { + ConstantViews memory views; + views.token0 = token0; + views.token1 = token1; + views.dexId = dexId; + return views; + } + + receive() external payable {} +} + +/// @title FluidDexETHGateway unit test +/// @notice U:[FDEXG]: Unit tests for FluidDexETHGateway +contract FluidDexETHGatewayTest is Test { + FluidDexETHGateway gateway; + FluidDexPoolMock pool; + WETHMock weth; + ERC20Mock otherToken; + + address user; + + // Special ETH address used by Fluid + address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + uint256 constant AMOUNT_IN = 1 ether; + uint256 constant AMOUNT_OUT = 0.95 ether; + uint256 constant MIN_AMOUNT_OUT = 0.9 ether; + uint256 constant EXCHANGE_RATE = 0.95e18; // 1 ETH = 0.95 tokens + + function setUp() public { + user = makeAddr("user"); + + // Deploy mock contracts + weth = new WETHMock(); + otherToken = new ERC20Mock("TestToken", "TEST", 18); + pool = new FluidDexPoolMock(ETH, address(otherToken), 123); + + // Set exchange rate + pool.setExchangeRate(EXCHANGE_RATE); + + // Fund the pool with ETH for swaps + vm.deal(address(pool), 100 ether); + + // Deploy gateway + gateway = new FluidDexETHGateway(address(pool), address(weth)); + + // Fund user with tokens + vm.deal(user, 10 ether); + + vm.prank(user); + weth.deposit{value: 10 ether}(); + + otherToken.mint(user, 10 ether); + otherToken.mint(address(pool), 100 ether); + } + + /// @notice U:[FDEXG-1]: Constructor works as expected + function test_U_FDEXG_01_constructor_works_as_expected() public { + assertEq(gateway.pool(), address(pool), "Incorrect pool address"); + assertEq(gateway.weth(), address(weth), "Incorrect WETH address"); + assertEq(gateway.otherToken(), address(otherToken), "Incorrect other token address"); + assertTrue(gateway.ethIsToken0(), "ETH should be token0"); + + // Test with ETH as token1 + FluidDexPoolMock pool2 = new FluidDexPoolMock(address(otherToken), ETH, 456); + FluidDexETHGateway gateway2 = new FluidDexETHGateway(address(pool2), address(weth)); + + assertEq(gateway2.pool(), address(pool2), "Incorrect pool address"); + assertEq(gateway2.weth(), address(weth), "Incorrect WETH address"); + assertEq(gateway2.otherToken(), address(otherToken), "Incorrect other token address"); + assertFalse(gateway2.ethIsToken0(), "ETH should be token1"); + } + + /// @notice U:[FDEXG-2]: Constructor reverts on zero addresses + function test_U_FDEXG_02_constructor_reverts_on_zero_addresses() public { + vm.expectRevert(ZeroAddressException.selector); + new FluidDexETHGateway(address(0), address(weth)); + + vm.expectRevert(ZeroAddressException.selector); + new FluidDexETHGateway(address(pool), address(0)); + } + + /// @notice U:[FDEXG-3]: Constructor reverts when pool doesn't contain ETH + function test_U_FDEXG_03_constructor_reverts_when_pool_doesnt_contain_eth() public { + ERC20Mock randomToken1 = new ERC20Mock("TestToken", "TEST", 18); + ERC20Mock randomToken2 = new ERC20Mock("TestToken", "TEST", 18); + FluidDexPoolMock invalidPool = new FluidDexPoolMock(address(randomToken1), address(randomToken2), 789); + + vm.expectRevert("Pool does not contain ETH"); + new FluidDexETHGateway(address(invalidPool), address(weth)); + } + + /// @notice U:[FDEXG-4]: constantsView returns correct values + function test_U_FDEXG_04_constantsView_returns_correct_values() public { + ConstantViews memory returnedViews = gateway.constantsView(); + assertEq(returnedViews.token0, address(weth), "Incorrect token0 - should be WETH"); + assertEq(returnedViews.token1, address(otherToken), "Incorrect token1"); + assertEq(returnedViews.dexId, 123, "Incorrect dexId"); + } + + /// @notice U:[FDEXG-5]: swapIn works for WETH to token + function test_U_FDEXG_05_swapIn_works_for_weth_to_token() public { + bool swap0to1 = true; // ETH/WETH to token + + // Approve gateway to spend WETH + vm.prank(user); + weth.approve(address(gateway), AMOUNT_IN); + + uint256 userWethBalanceBefore = weth.balanceOf(user); + uint256 userTokenBalanceBefore = otherToken.balanceOf(user); + + vm.prank(user); + uint256 amountOut = gateway.swapIn(swap0to1, AMOUNT_IN, MIN_AMOUNT_OUT, user); + + uint256 expectedAmountOut = (AMOUNT_IN * EXCHANGE_RATE) / 1e18; + assertEq(amountOut, expectedAmountOut, "Incorrect amount out"); + assertEq(weth.balanceOf(user), userWethBalanceBefore - AMOUNT_IN, "WETH not transferred from user"); + assertEq(otherToken.balanceOf(user), userTokenBalanceBefore + expectedAmountOut, "Tokens not received by user"); + } + + /// @notice U:[FDEXG-6]: swapIn works for token to WETH + function test_U_FDEXG_06_swapIn_works_for_token_to_weth() public { + bool swap0to1 = false; // token to ETH/WETH + + // Approve gateway to spend other token + vm.prank(user); + otherToken.approve(address(gateway), AMOUNT_IN); + + uint256 userTokenBalanceBefore = otherToken.balanceOf(user); + uint256 userWethBalanceBefore = weth.balanceOf(user); + + vm.prank(user); + uint256 amountOut = gateway.swapIn(swap0to1, AMOUNT_IN, MIN_AMOUNT_OUT, user); + + uint256 expectedAmountOut = (AMOUNT_IN * 1e18) / EXCHANGE_RATE - 1; + uint256 expectedTransferAmount = expectedAmountOut; + + assertEq(amountOut, expectedAmountOut, "Incorrect amount out returned"); + assertEq(otherToken.balanceOf(user), userTokenBalanceBefore - AMOUNT_IN, "Tokens not transferred from user"); + assertEq(weth.balanceOf(user), userWethBalanceBefore + expectedTransferAmount, "WETH not received by user"); + assertEq(weth.balanceOf(address(gateway)), 1, "Gateway should keep 1 wei for gas savings"); + } + + /// @notice U:[FDEXG-7]: swapIn works with ETH as token1 + function test_U_FDEXG_07_swapIn_works_with_eth_as_token1() public { + // Create gateway with ETH as token1 + FluidDexPoolMock pool2 = new FluidDexPoolMock(address(otherToken), ETH, 456); + pool2.setExchangeRate(EXCHANGE_RATE); + vm.deal(address(pool2), 100 ether); + otherToken.mint(address(pool2), 100 ether); + + FluidDexETHGateway gateway2 = new FluidDexETHGateway(address(pool2), address(weth)); + + // Test swap from WETH to token (swap1to0) + bool swap0to1 = false; // token1 to token0 (ETH/WETH to token) + + // Approve gateway to spend WETH + vm.prank(user); + weth.approve(address(gateway2), AMOUNT_IN); + + uint256 userWethBalanceBefore = weth.balanceOf(user); + uint256 userTokenBalanceBefore = otherToken.balanceOf(user); + + vm.prank(user); + uint256 amountOut = gateway2.swapIn(swap0to1, AMOUNT_IN, MIN_AMOUNT_OUT, user); + + uint256 expectedAmountOut = (AMOUNT_IN * 1e18) / EXCHANGE_RATE; + assertEq(amountOut, expectedAmountOut, "Incorrect amount out"); + assertEq(weth.balanceOf(user), userWethBalanceBefore - AMOUNT_IN, "WETH not transferred from user"); + assertEq(otherToken.balanceOf(user), userTokenBalanceBefore + expectedAmountOut, "Tokens not received by user"); + } + + receive() external payable {} +} diff --git a/contracts/test/unit/helpers/lido/LidoV1_WETHGateway.unit.t.sol b/contracts/test/unit/helpers/lido/LidoV1_WETHGateway.unit.t.sol index a09a90cc..9d7eda7c 100644 --- a/contracts/test/unit/helpers/lido/LidoV1_WETHGateway.unit.t.sol +++ b/contracts/test/unit/helpers/lido/LidoV1_WETHGateway.unit.t.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {Test} from "forge-std/Test.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; import { ReceiveIsNotAllowedException, ZeroAddressException diff --git a/contracts/test/unit/zappers/ZapperBase.harness.sol b/contracts/test/unit/zappers/ZapperBase.harness.sol index ddfe0044..99084234 100644 --- a/contracts/test/unit/zappers/ZapperBase.harness.sol +++ b/contracts/test/unit/zappers/ZapperBase.harness.sol @@ -1,11 +1,14 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ZapperBase} from "../../../zappers/ZapperBase.sol"; contract ZapperBaseHarness is ZapperBase { + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::HARNESS"; + event ConvertTokenInToUnderlying(uint256 tokenInAmount, uint256 assets); event ConvertUnderlyingToTokenIn(uint256 assets, uint256 tokenInAmount, address receiver); event ConvertSharesToTokenOut(uint256 shares, uint256 tokenOutAmount, address receiver); diff --git a/contracts/test/unit/zappers/ZapperBase.unit.t.sol b/contracts/test/unit/zappers/ZapperBase.unit.t.sol index 4152e2a9..e97097f7 100644 --- a/contracts/test/unit/zappers/ZapperBase.unit.t.sol +++ b/contracts/test/unit/zappers/ZapperBase.unit.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {Test} from "forge-std/Test.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; @@ -48,7 +48,7 @@ contract ZapperBaseUnitTest is Test { } /// @notice U:[ZB-1]: Constructor works as expected - function test_U_ZB_01_constructor_works_as_expected() public { + function test_U_ZB_01_constructor_works_as_expected() public view { assertEq(zapper.pool(), address(pool), "Incorrect pool"); assertEq(zapper.underlying(), address(underlying), "Incorrect underlying"); assertEq(underlying.allowance(address(zapper), address(pool)), type(uint256).max, "Incorrect allowance"); diff --git a/contracts/zappers/DTokenDepositZapper.sol b/contracts/zappers/DTokenDepositZapper.sol deleted file mode 100644 index 14b70349..00000000 --- a/contracts/zappers/DTokenDepositZapper.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {DepositTrait} from "./traits/DepositTrait.sol"; -import {DTokenTrait} from "./traits/DTokenTrait.sol"; -import {ZapperBase} from "./ZapperBase.sol"; - -/// @title dToken deposit zapper -/// @notice Zapper that allows to migrate liquidity from older to newer pools -contract DTokenDepositZapper is DTokenTrait, DepositTrait { - constructor(address newPool, address oldPool) ZapperBase(newPool) DTokenTrait(oldPool) {} -} diff --git a/contracts/zappers/DTokenFarmingZapper.sol b/contracts/zappers/DTokenFarmingZapper.sol deleted file mode 100644 index f12aa820..00000000 --- a/contracts/zappers/DTokenFarmingZapper.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {FarmingTrait} from "./traits/FarmingTrait.sol"; -import {DTokenTrait} from "./traits/DTokenTrait.sol"; -import {ZapperBase} from "./ZapperBase.sol"; - -/// @title Diesel token farming zapper -/// @notice Zapper that allows to migrate liquidity from older to newer pools and stake shares in 1inch farming contract -contract DTokenFarmingZapper is DTokenTrait, FarmingTrait { - constructor(address newPool, address oldPool, address farmingPool) - ZapperBase(newPool) - DTokenTrait(oldPool) - FarmingTrait(farmingPool) - {} -} diff --git a/contracts/zappers/ERC20ZapperBase.sol b/contracts/zappers/ERC20ZapperBase.sol index 3e68548a..0f28192b 100644 --- a/contracts/zappers/ERC20ZapperBase.sol +++ b/contracts/zappers/ERC20ZapperBase.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ZapperBase} from "./ZapperBase.sol"; import {IERC20ZapperDeposits} from "../interfaces/zappers/IERC20ZapperDeposits.sol"; @@ -83,6 +83,6 @@ abstract contract ERC20ZapperBase is ZapperBase, IERC20ZapperDeposits { bytes32 s ) external returns (uint256 tokenOutAmount) { _permitAllowed(tokenIn(), nonce, expiry, v, r, s); - tokenOutAmount = _deposit(tokenInAmount, receiver, false, referralCode); + tokenOutAmount = _deposit(tokenInAmount, receiver, true, referralCode); } } diff --git a/contracts/zappers/ERC4626Zapper.sol b/contracts/zappers/ERC4626Zapper.sol new file mode 100644 index 00000000..56e07475 --- /dev/null +++ b/contracts/zappers/ERC4626Zapper.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {DepositTrait} from "./traits/DepositTrait.sol"; +import {ERC4626Trait} from "./traits/ERC4626Trait.sol"; +import {ZapperBase} from "./ZapperBase.sol"; + +/// @title ERC-4626 zapper +/// @notice Zapper that allows to move funds from an ERC-4626 vault to a Gearbox pool in one call +contract ERC4626Zapper is ERC4626Trait, DepositTrait { + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::ERC4626"; + + constructor(address pool_, address vault_) ZapperBase(pool_) ERC4626Trait(vault_) {} + + function serialize() public view override returns (bytes memory) { + return abi.encode(vault); + } +} diff --git a/contracts/zappers/ETHZapperBase.sol b/contracts/zappers/ETHZapperBase.sol index 9b723663..3e9f9683 100644 --- a/contracts/zappers/ETHZapperBase.sol +++ b/contracts/zappers/ETHZapperBase.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {ZapperBase} from "./ZapperBase.sol"; import {IETHZapperDeposits, ETH_ADDRESS} from "../interfaces/zappers/IETHZapperDeposits.sol"; diff --git a/contracts/zappers/StakedERC4626Zapper.sol b/contracts/zappers/StakedERC4626Zapper.sol new file mode 100644 index 00000000..194e6a5d --- /dev/null +++ b/contracts/zappers/StakedERC4626Zapper.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {DepositTrait} from "./traits/DepositTrait.sol"; +import {StakedERC4626Trait} from "./traits/StakedERC4626Trait.sol"; +import {ZapperBase} from "./ZapperBase.sol"; + +/// @title Staked ERC-4626 zapper +/// @notice Zapper that allows to move funds from a staked ERC-4626 vault to a Gearbox pool in one call +contract StakedERC4626Zapper is StakedERC4626Trait, DepositTrait { + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::STAKED_ERC4626"; + + constructor(address pool_, address farmingPool_) ZapperBase(pool_) StakedERC4626Trait(farmingPool_) {} + + function serialize() public view override returns (bytes memory) { + return abi.encode(farmingPool, vault); + } +} diff --git a/contracts/zappers/UnderlyingDepositZapper.sol b/contracts/zappers/UnderlyingDepositZapper.sol index b566e45a..074d4748 100644 --- a/contracts/zappers/UnderlyingDepositZapper.sol +++ b/contracts/zappers/UnderlyingDepositZapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {DepositTrait} from "./traits/DepositTrait.sol"; import {UnderlyingTrait} from "./traits/UnderlyingTrait.sol"; @@ -10,5 +10,8 @@ import {ZapperBase} from "./ZapperBase.sol"; /// @title Underlying deposit zapper /// @notice Zapper that allows to deposit underlying token into a pool in one call using permit contract UnderlyingDepositZapper is UnderlyingTrait, DepositTrait { - constructor(address pool) ZapperBase(pool) {} + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::UNDERLYING_DEPOSIT"; + + constructor(address pool_) ZapperBase(pool_) {} } diff --git a/contracts/zappers/UnderlyingFarmingZapper.sol b/contracts/zappers/UnderlyingFarmingZapper.sol index e41115e0..fa482452 100644 --- a/contracts/zappers/UnderlyingFarmingZapper.sol +++ b/contracts/zappers/UnderlyingFarmingZapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {FarmingTrait} from "./traits/FarmingTrait.sol"; import {UnderlyingTrait} from "./traits/UnderlyingTrait.sol"; @@ -10,5 +10,8 @@ import {ZapperBase} from "./ZapperBase.sol"; /// @title Underlying farming zapper /// @notice Zapper that allows to deposit underlying token into a pool and stake shares in 1inch farming contract contract UnderlyingFarmingZapper is UnderlyingTrait, FarmingTrait { - constructor(address pool, address farmingPool) ZapperBase(pool) FarmingTrait(farmingPool) {} + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::UNDERLYING_FARMING"; + + constructor(address pool_, address farmingPool) ZapperBase(pool_) FarmingTrait(farmingPool) {} } diff --git a/contracts/zappers/WATokenDepositZapper.sol b/contracts/zappers/WATokenDepositZapper.sol deleted file mode 100644 index d205345e..00000000 --- a/contracts/zappers/WATokenDepositZapper.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {DepositTrait} from "./traits/DepositTrait.sol"; -import {WATokenTrait} from "./traits/WATokenTrait.sol"; -import {ZapperBase} from "./ZapperBase.sol"; - -/// @title waToken deposit zapper -/// @notice Zapper that allows to deposit aToken directly into a waToken pool -contract WATokenDepositZapper is WATokenTrait, DepositTrait { - constructor(address pool) ZapperBase(pool) WATokenTrait() {} -} diff --git a/contracts/zappers/WATokenFarmingZapper.sol b/contracts/zappers/WATokenFarmingZapper.sol deleted file mode 100644 index d89719f0..00000000 --- a/contracts/zappers/WATokenFarmingZapper.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {FarmingTrait} from "./traits/FarmingTrait.sol"; -import {WATokenTrait} from "./traits/WATokenTrait.sol"; -import {ZapperBase} from "./ZapperBase.sol"; - -/// @title waToken farming zapper -/// @notice Zapper that allows to deposit aToken directly into a waToken pool and stake shares in 1inch farming contract -contract WATokenFarmingZapper is WATokenTrait, FarmingTrait { - constructor(address pool, address farmingPool) ZapperBase(pool) WATokenTrait() FarmingTrait(farmingPool) {} -} diff --git a/contracts/zappers/WETHDepositZapper.sol b/contracts/zappers/WETHDepositZapper.sol index 7d833e84..be7de4a0 100644 --- a/contracts/zappers/WETHDepositZapper.sol +++ b/contracts/zappers/WETHDepositZapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {DepositTrait} from "./traits/DepositTrait.sol"; import {WETHTrait} from "./traits/WETHTrait.sol"; @@ -10,5 +10,8 @@ import {ZapperBase} from "./ZapperBase.sol"; /// @title WETH deposit zapper /// @notice Zapper that allows to deposit ETH directly into a WETH pool contract WETHDepositZapper is WETHTrait, DepositTrait { - constructor(address pool) ZapperBase(pool) {} + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::WETH_DEPOSIT"; + + constructor(address pool_) ZapperBase(pool_) {} } diff --git a/contracts/zappers/WETHFarmingZapper.sol b/contracts/zappers/WETHFarmingZapper.sol index 2562fa30..b1d762fa 100644 --- a/contracts/zappers/WETHFarmingZapper.sol +++ b/contracts/zappers/WETHFarmingZapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {FarmingTrait} from "./traits/FarmingTrait.sol"; import {WETHTrait} from "./traits/WETHTrait.sol"; @@ -10,5 +10,8 @@ import {ZapperBase} from "./ZapperBase.sol"; /// @title WETH farming zapper /// @notice Zapper that allows to deposit ETH directly into a WETH pool and stake shares in 1inch farming contract contract WETHFarmingZapper is WETHTrait, FarmingTrait { - constructor(address pool, address farmingPool) ZapperBase(pool) FarmingTrait(farmingPool) {} + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::WETH_FARMING"; + + constructor(address pool_, address farmingPool) ZapperBase(pool_) FarmingTrait(farmingPool) {} } diff --git a/contracts/zappers/WstETHDepositZapper.sol b/contracts/zappers/WstETHDepositZapper.sol index 5132f1f1..7560191c 100644 --- a/contracts/zappers/WstETHDepositZapper.sol +++ b/contracts/zappers/WstETHDepositZapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {DepositTrait} from "./traits/DepositTrait.sol"; import {WstETHTrait} from "./traits/WstETHTrait.sol"; @@ -10,5 +10,8 @@ import {ZapperBase} from "./ZapperBase.sol"; /// @title wstETH deposit zapper /// @notice Zapper that allows to deposit stETH directly into a wstETH pool contract WstETHDepositZapper is WstETHTrait, DepositTrait { - constructor(address pool) ZapperBase(pool) WstETHTrait() {} + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::WSTETH_DEPOSIT"; + + constructor(address pool_) ZapperBase(pool_) WstETHTrait() {} } diff --git a/contracts/zappers/WstETHFarmingZapper.sol b/contracts/zappers/WstETHFarmingZapper.sol index a5af9c6f..2545c5cb 100644 --- a/contracts/zappers/WstETHFarmingZapper.sol +++ b/contracts/zappers/WstETHFarmingZapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {FarmingTrait} from "./traits/FarmingTrait.sol"; import {WstETHTrait} from "./traits/WstETHTrait.sol"; @@ -10,5 +10,8 @@ import {ZapperBase} from "./ZapperBase.sol"; /// @title wstETH farming zapper /// @notice Zapper that allows to deposit stETH directly into a wstETH pool and stake shares in 1inch farming contract contract WstETHFarmingZapper is WstETHTrait, FarmingTrait { - constructor(address pool, address farmingPool) ZapperBase(pool) WstETHTrait() FarmingTrait(farmingPool) {} + uint256 public constant override version = 3_10; + bytes32 public constant override contractType = "ZAPPER::WSTETH_FARMING"; + + constructor(address pool_, address farmingPool) ZapperBase(pool_) WstETHTrait() FarmingTrait(farmingPool) {} } diff --git a/contracts/zappers/ZapperBase.sol b/contracts/zappers/ZapperBase.sol index 636519cf..e819319d 100644 --- a/contracts/zappers/ZapperBase.sol +++ b/contracts/zappers/ZapperBase.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; @@ -36,6 +36,9 @@ abstract contract ZapperBase is IZapper { /// @notice Zapper's output token function tokenOut() public view virtual returns (address); + /// @notice Serializes the zapper's state into a bytes array + function serialize() public view virtual returns (bytes memory) {} + // ------- // // PREVIEW // // ------- // diff --git a/contracts/zappers/ZapperRegister.sol b/contracts/zappers/ZapperRegister.sol deleted file mode 100644 index d61e30eb..00000000 --- a/contracts/zappers/ZapperRegister.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; - -import {ACLNonReentrantTrait} from "@gearbox-protocol/core-v3/contracts/traits/ACLNonReentrantTrait.sol"; -import {ContractsRegisterTrait} from "@gearbox-protocol/core-v3/contracts/traits/ContractsRegisterTrait.sol"; - -import {IZapper} from "../interfaces/zappers/IZapper.sol"; -import {IZapperRegister} from "../interfaces/zappers/IZapperRegister.sol"; - -contract ZapperRegister is ACLNonReentrantTrait, ContractsRegisterTrait, IZapperRegister { - using EnumerableSet for EnumerableSet.AddressSet; - - uint256 public constant override version = 3_00; - - mapping(address => EnumerableSet.AddressSet) internal _zappersMap; - - constructor(address addressProvider) - ACLNonReentrantTrait(addressProvider) - ContractsRegisterTrait(addressProvider) - {} - - function zappers(address pool) external view override returns (address[] memory) { - return _zappersMap[pool].values(); - } - - function addZapper(address zapper) external override nonZeroAddress(zapper) controllerOnly { - address pool = IZapper(zapper).pool(); - _ensureRegisteredPool(pool); - - EnumerableSet.AddressSet storage zapperSet = _zappersMap[pool]; - if (!zapperSet.contains(zapper)) { - zapperSet.add(zapper); - emit AddZapper(zapper); - } - } - - function removeZapper(address zapper) external override nonZeroAddress(zapper) controllerOnly { - EnumerableSet.AddressSet storage zapperSet = _zappersMap[IZapper(zapper).pool()]; - if (zapperSet.contains(zapper)) { - zapperSet.remove(zapper); - emit RemoveZapper(zapper); - } - } -} diff --git a/contracts/zappers/traits/DTokenTrait.sol b/contracts/zappers/traits/DTokenTrait.sol deleted file mode 100644 index 485c2682..00000000 --- a/contracts/zappers/traits/DTokenTrait.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; -import {IPoolService} from "@gearbox-protocol/core-v2/contracts/interfaces/IPoolService.sol"; -import { - IncompatibleContractException, - NotImplementedException -} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; - -import {ERC20ZapperBase} from "../ERC20ZapperBase.sol"; -import {ZapperBase} from "../ZapperBase.sol"; - -/// @title dToken trait -/// @notice Implements tokenIn -> underlying conversion for pools with older diesel tokens as input tokens -abstract contract DTokenTrait is ERC20ZapperBase { - using SafeERC20 for IERC20; - - /// @dev Old pool address - address internal immutable _pool; - - /// @dev Old diesel token address - address internal immutable _dToken; - - /// @notice Constructor - /// @param pool Old pool address - constructor(address pool) { - if (IPoolService(pool).underlyingToken() != underlying) revert IncompatibleContractException(); - _pool = pool; - _dToken = IPoolService(pool).dieselToken(); - } - - /// @inheritdoc ZapperBase - /// @dev Returns older pool's diesel token address - function tokenIn() public view override returns (address) { - return _dToken; - } - - /// @inheritdoc ZapperBase - function _previewTokenInToUnderlying(uint256 tokenInAmount) internal view override returns (uint256 assets) { - assets = IPoolService(_pool).fromDiesel(tokenInAmount); - } - - /// @inheritdoc ZapperBase - /// @dev Reverts as conversion back to older diesel tokens is not supported - function _previewUnderlyingToTokenIn(uint256) internal pure override returns (uint256) { - revert NotImplementedException(); - } - - /// @inheritdoc ZapperBase - function _tokenInToUnderlying(uint256 tokenInAmount) internal override returns (uint256 assets) { - IERC20(_dToken).safeTransferFrom(msg.sender, address(this), tokenInAmount); - assets = IPoolService(_pool).removeLiquidity(tokenInAmount, address(this)); - } - - /// @inheritdoc ZapperBase - /// @dev Reverts as conversion back to older diesel tokens is not supported - function _underlyingToTokenIn(uint256, address) internal pure override returns (uint256) { - revert NotImplementedException(); - } -} diff --git a/contracts/zappers/traits/DepositTrait.sol b/contracts/zappers/traits/DepositTrait.sol index eb1fd5e5..39e314f8 100644 --- a/contracts/zappers/traits/DepositTrait.sol +++ b/contracts/zappers/traits/DepositTrait.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IFarmingPool} from "@1inch/farming/contracts/interfaces/IFarmingPool.sol"; import {ZapperBase} from "../ZapperBase.sol"; diff --git a/contracts/zappers/traits/ERC4626Trait.sol b/contracts/zappers/traits/ERC4626Trait.sol new file mode 100644 index 00000000..77329cf8 --- /dev/null +++ b/contracts/zappers/traits/ERC4626Trait.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; +import {ERC20ZapperBase} from "../ERC20ZapperBase.sol"; +import {ZapperBase} from "../ZapperBase.sol"; + +/// @title ERC-4626 trait +/// @notice Implements tokenIn -> underlying conversion for zappers with an ERC-4626 vault as input token +abstract contract ERC4626Trait is ERC20ZapperBase { + using SafeERC20 for IERC20; + + /// @notice Thrown when the vault's asset does not match the zapper's underlying token + error IncompatibleAssetException(); + + /// @notice Vault address + address public immutable vault; + + /// @notice Constructor + /// @param vault_ Vault address + constructor(address vault_) { + vault = vault_; + if (IERC4626(vault).asset() != underlying) revert IncompatibleAssetException(); + } + + /// @inheritdoc ZapperBase + /// @dev Returns vault address + function tokenIn() public view override returns (address) { + return vault; + } + + /// @inheritdoc ZapperBase + function _previewTokenInToUnderlying(uint256 tokenInAmount) internal view override returns (uint256 assets) { + assets = IERC4626(vault).previewRedeem(tokenInAmount); + } + + /// @inheritdoc ZapperBase + /// @dev Reverts as moving funds back to the vault is not supported + function _previewUnderlyingToTokenIn(uint256) internal pure override returns (uint256) { + revert NotImplementedException(); + } + + /// @inheritdoc ZapperBase + function _tokenInToUnderlying(uint256 tokenInAmount) internal override returns (uint256 assets) { + IERC20(vault).safeTransferFrom(msg.sender, address(this), tokenInAmount); + assets = IERC4626(vault).redeem(tokenInAmount, address(this), address(this)); + } + + /// @inheritdoc ZapperBase + /// @dev Reverts as moving funds back to the vault is not supported + function _underlyingToTokenIn(uint256, address) internal pure override returns (uint256) { + revert NotImplementedException(); + } +} diff --git a/contracts/zappers/traits/FarmingTrait.sol b/contracts/zappers/traits/FarmingTrait.sol index 1321e0e9..a1462d38 100644 --- a/contracts/zappers/traits/FarmingTrait.sol +++ b/contracts/zappers/traits/FarmingTrait.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; diff --git a/contracts/zappers/traits/StakedERC4626Trait.sol b/contracts/zappers/traits/StakedERC4626Trait.sol new file mode 100644 index 00000000..c51d5c1d --- /dev/null +++ b/contracts/zappers/traits/StakedERC4626Trait.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2025. +pragma solidity ^0.8.23; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {IFarmingPool} from "@1inch/farming/contracts/interfaces/IFarmingPool.sol"; +import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; +import {NotImplementedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; +import {ERC20ZapperBase} from "../ERC20ZapperBase.sol"; +import {ZapperBase} from "../ZapperBase.sol"; + +/// @title Staked ERC-4626 trait +/// @notice Implements tokenIn -> underlying conversion for zappers with an ERC-4626 vault +/// staked in 1inch farming pool as input token +abstract contract StakedERC4626Trait is ERC20ZapperBase { + using Address for address; + using SafeERC20 for IERC20; + + /// @notice Thrown when the vault's asset does not match the zapper's underlying token + error IncompatibleAssetException(); + + /// @notice 1inch farming pool address + address public immutable farmingPool; + + /// @notice Vault address + address public immutable vault; + + /// @notice Constructor + /// @param farmingPool_ Farming pool address + /// @dev Reverts if the vault's asset does not match the zapper's underlying token + constructor(address farmingPool_) { + farmingPool = farmingPool_; + vault = _getStakedToken(farmingPool_); + if (IERC4626(vault).asset() != underlying) revert IncompatibleAssetException(); + } + + /// @inheritdoc ZapperBase + /// @dev Returns farming pool address + function tokenIn() public view override returns (address) { + return farmingPool; + } + + /// @inheritdoc ZapperBase + function _previewTokenInToUnderlying(uint256 tokenInAmount) internal view override returns (uint256 assets) { + assets = IERC4626(vault).previewRedeem(tokenInAmount); + } + + /// @inheritdoc ZapperBase + /// @dev Reverts as moving funds back to the farming pool is not supported + function _previewUnderlyingToTokenIn(uint256) internal pure override returns (uint256) { + revert NotImplementedException(); + } + + /// @inheritdoc ZapperBase + function _tokenInToUnderlying(uint256 tokenInAmount) internal override returns (uint256 assets) { + IERC20(farmingPool).safeTransferFrom(msg.sender, address(this), tokenInAmount); + IFarmingPool(farmingPool).withdraw(tokenInAmount); + assets = IERC4626(vault).redeem(tokenInAmount, address(this), address(this)); + } + + /// @inheritdoc ZapperBase + /// @dev Reverts as moving funds back to the farming pool is not supported + function _underlyingToTokenIn(uint256, address) internal pure override returns (uint256) { + revert NotImplementedException(); + } + + /// @dev Returns the staked token of the farming pool + function _getStakedToken(address farmingPool_) internal view returns (address) { + bytes memory result = farmingPool_.functionStaticCall(abi.encodeWithSignature("stakingToken()")); + return abi.decode(result, (address)); + } +} diff --git a/contracts/zappers/traits/UnderlyingTrait.sol b/contracts/zappers/traits/UnderlyingTrait.sol index f6a1c8c2..159b09b5 100644 --- a/contracts/zappers/traits/UnderlyingTrait.sol +++ b/contracts/zappers/traits/UnderlyingTrait.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; diff --git a/contracts/zappers/traits/WATokenTrait.sol b/contracts/zappers/traits/WATokenTrait.sol deleted file mode 100644 index 1e0ceab4..00000000 --- a/contracts/zappers/traits/WATokenTrait.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; -import {WAD} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; -import {WrappedAToken} from "../../helpers/aave/AaveV2_WrappedAToken.sol"; -import {ERC20ZapperBase} from "../ERC20ZapperBase.sol"; -import {ZapperBase} from "../ZapperBase.sol"; - -/// @title waToken trait -/// @notice Implements tokenIn <-> underlying conversion functions for waToken pool zappers with aToken as input token -abstract contract WATokenTrait is ERC20ZapperBase { - using SafeERC20 for IERC20; - - /// @dev aToken address - address internal immutable _aToken; - - /// @notice Constructor - constructor() { - _aToken = WrappedAToken(underlying).aToken(); - _resetAllowance(_aToken, underlying); - } - - /// @inheritdoc ZapperBase - /// @dev Returns aToken address - function tokenIn() public view override returns (address) { - return _aToken; - } - - /// @inheritdoc ZapperBase - function _previewTokenInToUnderlying(uint256 tokenInAmount) internal view override returns (uint256 assets) { - assets = tokenInAmount * WAD / WrappedAToken(underlying).exchangeRate(); - } - - /// @inheritdoc ZapperBase - function _previewUnderlyingToTokenIn(uint256 assets) internal view override returns (uint256 tokenInAmount) { - tokenInAmount = assets * WrappedAToken(underlying).exchangeRate() / WAD; - } - - /// @inheritdoc ZapperBase - function _tokenInToUnderlying(uint256 tokenInAmount) internal override returns (uint256 assets) { - IERC20(_aToken).safeTransferFrom(msg.sender, address(this), tokenInAmount); - assets = WrappedAToken(underlying).deposit(tokenInAmount); - } - - /// @inheritdoc ZapperBase - function _underlyingToTokenIn(uint256 assets, address receiver) internal override returns (uint256 tokenInAmount) { - tokenInAmount = WrappedAToken(underlying).withdraw(assets); - IERC20(_aToken).safeTransfer(receiver, tokenInAmount); - } -} diff --git a/contracts/zappers/traits/WETHTrait.sol b/contracts/zappers/traits/WETHTrait.sol index b6f4c402..e36cdef8 100644 --- a/contracts/zappers/traits/WETHTrait.sol +++ b/contracts/zappers/traits/WETHTrait.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol"; +import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; import {ReceiveIsNotAllowedException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol"; import {ETHZapperBase} from "../ETHZapperBase.sol"; import {ZapperBase} from "../ZapperBase.sol"; diff --git a/contracts/zappers/traits/WstETHTrait.sol b/contracts/zappers/traits/WstETHTrait.sol index 031b757b..3e960c77 100644 --- a/contracts/zappers/traits/WstETHTrait.sol +++ b/contracts/zappers/traits/WstETHTrait.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Gearbox Protocol. Generalized leverage for DeFi protocols -// (c) Gearbox Foundation, 2023. -pragma solidity ^0.8.17; +// (c) Gearbox Foundation, 2024. +pragma solidity ^0.8.23; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; diff --git a/foundry.lock b/foundry.lock new file mode 100644 index 00000000..a7ff47f4 --- /dev/null +++ b/foundry.lock @@ -0,0 +1,23 @@ +{ + "lib/@1inch/farming": { + "rev": "47134f2828225a47183ad40bfc8f06a60bd018cd" + }, + "lib/@1inch/solidity-utils": { + "rev": "5fdd4c2c02525855e9f64d9a43d779013c6444ea" + }, + "lib/@gearbox-protocol/core-v3": { + "tag": { + "name": "v1.52.0", + "rev": "5144d61af7d117f86d3fa9b4e2aa05535e2e5433" + } + }, + "lib/@gearbox-protocol/oracles-v3": { + "tag": { + "name": "v1.14.0", + "rev": "78ad827ab9329f2c1d884672120fb61ca9fb67ec" + } + }, + "lib/@gearbox-protocol/sdk-gov": { + "rev": "ecc136f4fc0e0e6d19b9505e64de4f56d80899c2" + } +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 1946686f..445a11b1 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,9 +1,11 @@ [profile.default] -libs = ['lib'] -out = 'forge-out' -solc_version = '0.8.17' src = 'contracts' -optimizer_runs = 1000000 +libs = ['lib'] +out = 'out' +solc_version = '0.8.23' +evm_version = 'shanghai' +optimizer_runs = 1000 +bytecode_hash = 'none' # See more config options https://github.com/gakonst/foundry/tree/master/config block_number = 120000 @@ -11,5 +13,4 @@ block_timestamp = 1640000000 gas_limit = 9223372036854775807 # the gas limit in tests block_base_fee_per_gas = 100 fs_permissions = [{ access = "read-write", path = "./"}] -evm_version = "shanghai" ffi=true diff --git a/lib/@1inch/farming b/lib/@1inch/farming new file mode 160000 index 00000000..47134f28 --- /dev/null +++ b/lib/@1inch/farming @@ -0,0 +1 @@ +Subproject commit 47134f2828225a47183ad40bfc8f06a60bd018cd diff --git a/lib/@1inch/solidity-utils b/lib/@1inch/solidity-utils new file mode 160000 index 00000000..5fdd4c2c --- /dev/null +++ b/lib/@1inch/solidity-utils @@ -0,0 +1 @@ +Subproject commit 5fdd4c2c02525855e9f64d9a43d779013c6444ea diff --git a/lib/@gearbox-protocol/core-v3 b/lib/@gearbox-protocol/core-v3 new file mode 160000 index 00000000..5144d61a --- /dev/null +++ b/lib/@gearbox-protocol/core-v3 @@ -0,0 +1 @@ +Subproject commit 5144d61af7d117f86d3fa9b4e2aa05535e2e5433 diff --git a/lib/@gearbox-protocol/oracles-v3 b/lib/@gearbox-protocol/oracles-v3 new file mode 160000 index 00000000..78ad827a --- /dev/null +++ b/lib/@gearbox-protocol/oracles-v3 @@ -0,0 +1 @@ +Subproject commit 78ad827ab9329f2c1d884672120fb61ca9fb67ec diff --git a/lib/@gearbox-protocol/sdk-gov b/lib/@gearbox-protocol/sdk-gov new file mode 160000 index 00000000..ecc136f4 --- /dev/null +++ b/lib/@gearbox-protocol/sdk-gov @@ -0,0 +1 @@ +Subproject commit ecc136f4fc0e0e6d19b9505e64de4f56d80899c2 diff --git a/lib/forge-std b/lib/forge-std deleted file mode 160000 index 07263d19..00000000 --- a/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 07263d193d621c4b2b0ce8b4d54af58f6957d97d diff --git a/package.json b/package.json index e183968a..b6896003 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,6 @@ "description": "Integration contracts for Gearbox V3", "version": "1.22.0", "homepage": "https://gearbox.fi", - "main": "./npm-root/index.js", - "types": "./npm-root/index.d.ts", "keywords": [ "gearbox" ], @@ -16,42 +14,49 @@ "contracts", "dist" ], + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts", + "typings": "./dist/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.js", + "default": "./dist/cjs/index.js" + } + }, + "sideEffects": false, "license": "BUSL-1.1", "scripts": { + "clean": "forge clean && rm -rf ./dist ./src/**/*.generated.ts", + "build": "forge build --optimize false && wagmi generate && yarn build:ts", + "build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --declaration --outDir dist/types", + "build:cjs": "tsc -p tsconfig.build.json --module commonjs --outDir dist/cjs && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json", + "build:esm": "tsc -p tsconfig.build.json --module esnext --outDir dist/esm && echo '{\"type\": \"module\",\"sideEffects\":false}' > dist/esm/package.json", + "build:ts": "yarn build:types && yarn build:cjs && yarn build:esm", "prepare": "husky install", "prettier": "forge fmt", "prettier:ci": "forge fmt", "lint": "eslint \"**/*.ts\" --fix", "lint:ci": "eslint \"**/*.ts\"", - "typecheck:ci": "tsc --noEmit", - "forge-install": "forge install --no-commit foundry-rs/forge-std", - "build": "tsc --p tsconfig.build.json" + "typecheck:ci": "tsc --noEmit" }, "dependencies": {}, "devDependencies": { - "@1inch/farming": "3.1.0", - "@1inch/solidity-utils": "2.4.0", - "@chainlink/contracts": "^0.4.0", - "@commitlint/cli": "^17.1.2", - "@commitlint/config-conventional": "^17.1.0", - "@gearbox-protocol/core-v2": "1.19.0-base.10", - "@gearbox-protocol/core-v3": "^1.51.0", - "@gearbox-protocol/eslint-config": "^1.6.1", - "@gearbox-protocol/oracles-v3": "^1.12.1", - "@gearbox-protocol/prettier-config": "^1.5.0", - "@gearbox-protocol/sdk-gov": "^2.34.0", - "@openzeppelin/contracts": "4.9.3", + "@commitlint/cli": "^19.8.1", + "@commitlint/config-conventional": "^19.8.1", + "@gearbox-protocol/eslint-config": "^2.0.0-next.2", + "@gearbox-protocol/prettier-config": "^2.1.0", + "@gearbox-protocol/sdk-gov": "^2.37.0", "@redstone-finance/evm-connector": "0.2.5", - "@typechain/ethers-v5": "^10.1.0", - "dotenv": "^16.0.3", - "eslint": "^8.25.0", - "ethers": "5.4.4", - "husky": "^8.0.1", - "lint-staged": "^13.0.3", - "prettier": "^2.7.1", - "ts-node": "^10.9.1", - "typechain": "^8.1.0", - "typescript": "^4.8.2" + "@types/node": "^24.2.1", + "@wagmi/cli": "^2.3.2", + "eslint": "^8.57.1", + "husky": "^9.1.7", + "lint-staged": "^16.1.5", + "prettier": "^3.6.2", + "typescript": "^5.9.2" }, "prettier": "@gearbox-protocol/prettier-config", "lint-staged": { @@ -61,5 +66,6 @@ ], "*.sol": "forge fmt", "*.{json,md}": "prettier --write" - } + }, + "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610" } diff --git a/remappings.txt b/remappings.txt index afcf790b..522487f4 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,8 +1,5 @@ -ds-test/=lib/forge-std/lib/ds-test/src/ -forge-std/=lib/forge-std/src/ -@openzeppelin/=node_modules/@openzeppelin/ -@1inch/=node_modules/@1inch/ -@chainlink/=node_modules/@chainlink/ -@gearbox-protocol=node_modules/@gearbox-protocol/ +forge-std/=lib/@gearbox-protocol/core-v3/lib/forge-std/src/ +@1inch/=lib/@1inch/ +@openzeppelin/=lib/@gearbox-protocol/core-v3/lib/@openzeppelin/ +@gearbox-protocol=lib/@gearbox-protocol/ @redstone-finance=node_modules/@redstone-finance/ - diff --git a/tsconfig.build.json b/tsconfig.build.json index f16a886c..b90fc83e 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,11 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": [ - "**/*.spec.ts", - "node_modules", - "dist", - "forge-out", - "scripts", - "lib" - ] + "include": ["src"] } diff --git a/tsconfig.json b/tsconfig.json index 90cda46e..6b2a684f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,71 +1,15 @@ { "compilerOptions": { - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es2018" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, - "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "moduleResolution": "node", - "lib": [ - "ESNext", - "webworker" - ] /* Specify library files to be included in the compilation. */, - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true /* Generates corresponding '.d.ts' file. */, - // "composite": true, - // "declarationMap": true, - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true /* Generates corresponding '.map' file. */, - // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./build", /* Redirect output structure to the directory. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true /* Do not emit outputs. */, - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - /* Strict Type-Checking Options */ - "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, - "strictNullChecks": true /* Enable strict null checks. */, - "noErrorTruncation": true, - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - "strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */, - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ + "target": "esnext", + "module": "commonjs", + "lib": ["esnext"], + "strict": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "outDir": "dist", + "declaration": false, "skipLibCheck": true, - "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, - "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - /* Advanced Options */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "useUnknownInCatchVariables": false, - "resolveJsonModule": true, - "outDir": "./dist" + "forceConsistentCasingInFileNames": true }, - "include": ["config_scripts"], - "exclude": ["node_modules", "lib", "npm-root"] + "include": ["src", "wagmi.config.ts"] } diff --git a/wagmi.config.ts b/wagmi.config.ts new file mode 100644 index 00000000..feee9270 --- /dev/null +++ b/wagmi.config.ts @@ -0,0 +1,114 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { basename, join, relative } from "node:path"; + +import { defineConfig } from "@wagmi/cli"; +import { foundry } from "@wagmi/cli/plugins"; + +interface JsonFile { + abi: any[]; + [key: string]: any; +} + +const ARTIFACTS_DIR = "out"; +const CONTRACTS_DIR = "contracts"; +const CONTRACTS_SUBDIRS = ["adapters", "helpers", "interfaces"]; + +function filterArtifacts(): string[] { + const result: string[] = []; + const uniqJsons = new Set(); + const solFiles = listSolFiles(); + + try { + const entries = readdirSync(ARTIFACTS_DIR, { + withFileTypes: true, + recursive: true, + }); + + for (const entry of entries) { + if (entry.isFile() && entry.name.endsWith(".json")) { + const fullPath = join(entry.parentPath, entry.name); + const relPath = relative(ARTIFACTS_DIR, fullPath); + const filename = basename(fullPath); + if ( + !uniqJsons.has(filename) && + shouldInclude(solFiles, fullPath, relPath) + ) { + uniqJsons.add(filename); + result.push(relPath); + } + } + } + } catch (e) { + console.error(e); + } + + return result; +} + +function shouldInclude( + solFiles: string[], + fullPath: string, + relativePath: string, +): boolean { + const blocklist = [ + /abstract|mock|test|harness|live|deployer|build\-info/i, + /^Std/, + ]; + try { + // only include artifacts for sol files within the contracts + if (!solFiles.some(f => relativePath.includes(f))) { + return false; + } + + for (const item of blocklist) { + if (item.test(relativePath)) { + return false; + } + } + + // filter out artifacts that do not contain abi + const content = readFileSync(fullPath, "utf-8"); + const data: JsonFile = JSON.parse(content); + return data.abi && Array.isArray(data.abi) && data.abi.length > 0; + } catch (e) { + console.error(`error processing file ${relativePath}: ${e}`); + return false; + } +} + +function listSolFiles(): string[] { + const result: string[] = []; + for (const subdir of CONTRACTS_SUBDIRS) { + const entries = readdirSync(join(CONTRACTS_DIR, subdir), { + withFileTypes: true, + recursive: true, + }); + result.push( + ...entries + .filter(entry => entry.isFile() && entry.name.endsWith(".sol")) + .map(e => e.name), + ); + } + return result; +} + +export default defineConfig({ + out: "src/generated/index.ts", + plugins: [ + foundry({ + project: ".", + artifacts: ARTIFACTS_DIR, + include: filterArtifacts(), + exclude: [ + "**/IZapper.sol/**", + "**/IERC20ZapperDeposits.sol/**", + "**/IETHZapperDeposits.sol/**", + ], + forge: { + clean: false, + build: false, + rebuild: false, + }, + }), + ], +}); diff --git a/yarn.lock b/yarn.lock index 81a70afd..5daaf9ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,93 +2,29 @@ # yarn lockfile v1 -"@1inch/farming@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@1inch/farming/-/farming-3.1.0.tgz#a3e1bb4d6a99256ccc47d6d418644535bb96cff4" - integrity sha512-KrTNsq2tHqTM3TAVYlfC9G0qqYB8uuoJj9RkHxWuSg8NIZ3RzKejzDvNeVScaJFFWDJ+4vWKFUw5WHIUyoETEg== - dependencies: - "@1inch/solidity-utils" "3.0.1" - "@1inch/token-plugins" "1.1.2" - "@openzeppelin/contracts" "4.9.2" - -"@1inch/solidity-utils@2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@1inch/solidity-utils/-/solidity-utils-2.4.0.tgz#23268c5061521933b6e95a8d2c2d620d8851f7d3" - integrity sha512-qX+TkF9IPppC5Ghr+ZsZYmFVaSs+Uyc91VgRtghgj7INjjaSaTANl70wqrv5utVCiIR70s8FZGXbpzwAwIEoww== - dependencies: - "@metamask/eth-sig-util" "5.0.2" - "@nomicfoundation/hardhat-network-helpers" "1.0.8" - "@nomiclabs/hardhat-ethers" "2.2.2" - "@openzeppelin/contracts" "4.8.2" - "@uniswap/permit2-sdk" "^1.2.0" - ethereumjs-util "7.1.5" - ethers "5.7.2" - -"@1inch/solidity-utils@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@1inch/solidity-utils/-/solidity-utils-3.0.1.tgz#afce60992fff724b09d570801ed0381ac31402cf" - integrity sha512-KbLhh1JgjBIJAq6B+AGOuyLNlEf5bRvoMZb509YMeec3s3iLbTrtI5D76b+HGKR98wU3HuRiDac/7j4ck2bjBQ== - dependencies: - "@metamask/eth-sig-util" "6.0.0" - "@nomicfoundation/hardhat-ethers" "3.0.3" - "@nomicfoundation/hardhat-network-helpers" "1.0.8" - "@openzeppelin/contracts" "4.9.2" - "@uniswap/permit2-sdk" "1.2.0" - ethereumjs-util "7.1.5" - ethers "6.6.3" - hardhat-deploy "0.11.34" - -"@1inch/token-plugins@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@1inch/token-plugins/-/token-plugins-1.1.2.tgz#5381f7156c6d98760da838cd1002c38cb1f45107" - integrity sha512-ACstC+LpIbOdm7KwBG6KddjtaWHyhHfn6/2LpBdnx6PMPlgbR+IsHF3G61oah7mDtR2TurtMGQU1UCpTk2coyg== - dependencies: - "@1inch/solidity-utils" "3.0.1" - "@openzeppelin/contracts" "4.9.2" - -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - "@adraffy/ens-normalize@1.10.1": version "1.10.1" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== -"@adraffy/ens-normalize@1.9.2": - version "1.9.2" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" - integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== +"@adraffy/ens-normalize@^1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" + integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== "@babel/code-frame@^7.0.0": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" - integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA== - dependencies: - "@babel/highlight" "^7.22.10" - chalk "^2.4.2" - -"@babel/helper-validator-identifier@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" - integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== - -"@babel/highlight@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7" - integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ== + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== dependencies: - "@babel/helper-validator-identifier" "^7.22.5" - chalk "^2.4.2" + "@babel/helper-validator-identifier" "^7.27.1" js-tokens "^4.0.0" + picocolors "^1.1.1" -"@chainlink/contracts@^0.4.0": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@chainlink/contracts/-/contracts-0.4.2.tgz#2928a35e8da94664b8ffeb8f5a54b1a3f14d5b3f" - integrity sha512-wVI/KZ9nIH0iqoebVxYrZfNVWO23vwds1UrHdbF+S0JwyixtT+54xYGlot723jCrAeBeQHsDRQXnEhhbUEHpgQ== - dependencies: - "@eth-optimism/contracts" "^0.5.21" +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== "@chainlink/contracts@^0.6.1": version "0.6.1" @@ -100,190 +36,329 @@ "@openzeppelin/contracts-upgradeable" "^4.7.3" "@openzeppelin/contracts-v0.7" "npm:@openzeppelin/contracts@v3.4.2" -"@commitlint/cli@^17.1.2": - version "17.7.1" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-17.7.1.tgz#f3ab35bd38d82fcd4ab03ec5a1e9db26d57fe1b0" - integrity sha512-BCm/AT06SNCQtvFv921iNhudOHuY16LswT0R3OeolVGLk8oP+Rk9TfQfgjH7QPMjhvp76bNqGFEcpKojxUNW1g== - dependencies: - "@commitlint/format" "^17.4.4" - "@commitlint/lint" "^17.7.0" - "@commitlint/load" "^17.7.1" - "@commitlint/read" "^17.5.1" - "@commitlint/types" "^17.4.4" - execa "^5.0.0" - lodash.isfunction "^3.0.9" - resolve-from "5.0.0" - resolve-global "1.0.0" +"@commitlint/cli@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.8.1.tgz#85f7d9f331344e1f0a2b9d8b24fd3695466e1158" + integrity sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA== + dependencies: + "@commitlint/format" "^19.8.1" + "@commitlint/lint" "^19.8.1" + "@commitlint/load" "^19.8.1" + "@commitlint/read" "^19.8.1" + "@commitlint/types" "^19.8.1" + tinyexec "^1.0.0" yargs "^17.0.0" -"@commitlint/config-conventional@^17.1.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-17.7.0.tgz#1bbf2bce7851db63c1a8aa8d924277ad4938247e" - integrity sha512-iicqh2o6et+9kWaqsQiEYZzfLbtoWv9uZl8kbI8EGfnc0HeGafQBF7AJ0ylN9D/2kj6txltsdyQs8+2fTMwWEw== +"@commitlint/config-conventional@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz#eab42df58cda44f18410ae0cbd6785ece00f214b" + integrity sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ== dependencies: - conventional-changelog-conventionalcommits "^6.1.0" + "@commitlint/types" "^19.8.1" + conventional-changelog-conventionalcommits "^7.0.2" -"@commitlint/config-validator@^17.6.7": - version "17.6.7" - resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-17.6.7.tgz#c664d42a1ecf5040a3bb0843845150f55734df41" - integrity sha512-vJSncmnzwMvpr3lIcm0I8YVVDJTzyjy7NZAeXbTXy+MPUdAr9pKyyg7Tx/ebOQ9kqzE6O9WT6jg2164br5UdsQ== +"@commitlint/config-validator@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-19.8.1.tgz#29e9bb1360fa41b9439b23d8e25deaaf097306b5" + integrity sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ== dependencies: - "@commitlint/types" "^17.4.4" + "@commitlint/types" "^19.8.1" ajv "^8.11.0" -"@commitlint/ensure@^17.6.7": - version "17.6.7" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-17.6.7.tgz#77a77a0c05e6a1c34589f59e82e6cb937101fc4b" - integrity sha512-mfDJOd1/O/eIb/h4qwXzUxkmskXDL9vNPnZ4AKYKiZALz4vHzwMxBSYtyL2mUIDeU9DRSpEUins8SeKtFkYHSw== +"@commitlint/ensure@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-19.8.1.tgz#938c54d6f586bda600b5c8e8e842edb281546e14" + integrity sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw== dependencies: - "@commitlint/types" "^17.4.4" + "@commitlint/types" "^19.8.1" lodash.camelcase "^4.3.0" lodash.kebabcase "^4.1.1" lodash.snakecase "^4.1.1" lodash.startcase "^4.4.0" lodash.upperfirst "^4.3.1" -"@commitlint/execute-rule@^17.4.0": - version "17.4.0" - resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz#4518e77958893d0a5835babe65bf87e2638f6939" - integrity sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA== - -"@commitlint/format@^17.4.4": - version "17.4.4" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-17.4.4.tgz#0f6e1b4d7a301c7b1dfd4b6334edd97fc050b9f5" - integrity sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ== - dependencies: - "@commitlint/types" "^17.4.4" - chalk "^4.1.0" - -"@commitlint/is-ignored@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz#df9b284420bdb1aed5fdb2be44f4e98cc4826014" - integrity sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw== - dependencies: - "@commitlint/types" "^17.4.4" - semver "7.5.4" - -"@commitlint/lint@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-17.7.0.tgz#33f831298dc43679e4de6b088aea63d1f884c7e7" - integrity sha512-TCQihm7/uszA5z1Ux1vw+Nf3yHTgicus/+9HiUQk+kRSQawByxZNESeQoX9ujfVd3r4Sa+3fn0JQAguG4xvvbA== - dependencies: - "@commitlint/is-ignored" "^17.7.0" - "@commitlint/parse" "^17.7.0" - "@commitlint/rules" "^17.7.0" - "@commitlint/types" "^17.4.4" - -"@commitlint/load@^17.7.1": - version "17.7.1" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-17.7.1.tgz#0723b11723a20043a304a74960602dead89b5cdd" - integrity sha512-S/QSOjE1ztdogYj61p6n3UbkUvweR17FQ0zDbNtoTLc+Hz7vvfS7ehoTMQ27hPSjVBpp7SzEcOQu081RLjKHJQ== - dependencies: - "@commitlint/config-validator" "^17.6.7" - "@commitlint/execute-rule" "^17.4.0" - "@commitlint/resolve-extends" "^17.6.7" - "@commitlint/types" "^17.4.4" - "@types/node" "20.4.7" - chalk "^4.1.0" - cosmiconfig "^8.0.0" - cosmiconfig-typescript-loader "^4.0.0" +"@commitlint/execute-rule@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz#53000363b737773e2d25e97c20f15eaa78742067" + integrity sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA== + +"@commitlint/format@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-19.8.1.tgz#3e09b1291b3e29092d7a86f0afbbcfc0d99d3ad4" + integrity sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw== + dependencies: + "@commitlint/types" "^19.8.1" + chalk "^5.3.0" + +"@commitlint/is-ignored@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz#fed0851360ea2d21799eaf8ec9ef6d98c15536e3" + integrity sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg== + dependencies: + "@commitlint/types" "^19.8.1" + semver "^7.6.0" + +"@commitlint/lint@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.8.1.tgz#c21bf9000ca54e41c5b0139c98aaf12473c03bb0" + integrity sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw== + dependencies: + "@commitlint/is-ignored" "^19.8.1" + "@commitlint/parse" "^19.8.1" + "@commitlint/rules" "^19.8.1" + "@commitlint/types" "^19.8.1" + +"@commitlint/load@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.8.1.tgz#b997b1f65a961bf0a47189f15f6dc8786ceb4576" + integrity sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A== + dependencies: + "@commitlint/config-validator" "^19.8.1" + "@commitlint/execute-rule" "^19.8.1" + "@commitlint/resolve-extends" "^19.8.1" + "@commitlint/types" "^19.8.1" + chalk "^5.3.0" + cosmiconfig "^9.0.0" + cosmiconfig-typescript-loader "^6.1.0" lodash.isplainobject "^4.0.6" lodash.merge "^4.6.2" lodash.uniq "^4.5.0" - resolve-from "^5.0.0" - ts-node "^10.8.1" - typescript "^4.6.4 || ^5.0.0" - -"@commitlint/message@^17.4.2": - version "17.4.2" - resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-17.4.2.tgz#f4753a79701ad6db6db21f69076e34de6580e22c" - integrity sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q== - -"@commitlint/parse@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-17.7.0.tgz#aacb2d189e50ab8454154b1df150aaf20478ae47" - integrity sha512-dIvFNUMCUHqq5Abv80mIEjLVfw8QNuA4DS7OWip4pcK/3h5wggmjVnlwGCDvDChkw2TjK1K6O+tAEV78oxjxag== - dependencies: - "@commitlint/types" "^17.4.4" - conventional-changelog-angular "^6.0.0" - conventional-commits-parser "^4.0.0" - -"@commitlint/read@^17.5.1": - version "17.5.1" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-17.5.1.tgz#fec903b766e2c41e3cefa80630040fcaba4f786c" - integrity sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg== - dependencies: - "@commitlint/top-level" "^17.4.0" - "@commitlint/types" "^17.4.4" - fs-extra "^11.0.0" - git-raw-commits "^2.0.11" - minimist "^1.2.6" -"@commitlint/resolve-extends@^17.6.7": - version "17.6.7" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-17.6.7.tgz#9c53a4601c96ab2dd20b90fb35c988639307735d" - integrity sha512-PfeoAwLHtbOaC9bGn/FADN156CqkFz6ZKiVDMjuC2N5N0740Ke56rKU7Wxdwya8R8xzLK9vZzHgNbuGhaOVKIg== - dependencies: - "@commitlint/config-validator" "^17.6.7" - "@commitlint/types" "^17.4.4" - import-fresh "^3.0.0" +"@commitlint/message@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-19.8.1.tgz#d5d0d87837483d9f9b4559ffa06e1aaa26d266d6" + integrity sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg== + +"@commitlint/parse@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-19.8.1.tgz#73125d04f07f11477cf563cbfe0cc9f6dc85a747" + integrity sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw== + dependencies: + "@commitlint/types" "^19.8.1" + conventional-changelog-angular "^7.0.0" + conventional-commits-parser "^5.0.0" + +"@commitlint/read@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-19.8.1.tgz#812930fd0f616e796e122751cb983346e5454ec8" + integrity sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ== + dependencies: + "@commitlint/top-level" "^19.8.1" + "@commitlint/types" "^19.8.1" + git-raw-commits "^4.0.0" + minimist "^1.2.8" + tinyexec "^1.0.0" + +"@commitlint/resolve-extends@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz#a44bb4c22e3e7d407cc9a3758fcf58f5c360b694" + integrity sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg== + dependencies: + "@commitlint/config-validator" "^19.8.1" + "@commitlint/types" "^19.8.1" + global-directory "^4.0.1" + import-meta-resolve "^4.0.0" lodash.mergewith "^4.6.2" resolve-from "^5.0.0" - resolve-global "^1.0.0" -"@commitlint/rules@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-17.7.0.tgz#b97a4933c5cba11a659a19ee467f6f000f31533e" - integrity sha512-J3qTh0+ilUE5folSaoK91ByOb8XeQjiGcdIdiB/8UT1/Rd1itKo0ju/eQVGyFzgTMYt8HrDJnGTmNWwcMR1rmA== +"@commitlint/rules@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-19.8.1.tgz#1cea53d5bf970ce56dc105e1da5e6655a2fe7a5f" + integrity sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw== dependencies: - "@commitlint/ensure" "^17.6.7" - "@commitlint/message" "^17.4.2" - "@commitlint/to-lines" "^17.4.0" - "@commitlint/types" "^17.4.4" - execa "^5.0.0" + "@commitlint/ensure" "^19.8.1" + "@commitlint/message" "^19.8.1" + "@commitlint/to-lines" "^19.8.1" + "@commitlint/types" "^19.8.1" -"@commitlint/to-lines@^17.4.0": - version "17.4.0" - resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-17.4.0.tgz#9bd02e911e7d4eab3fb4a50376c4c6d331e10d8d" - integrity sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg== +"@commitlint/to-lines@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-19.8.1.tgz#c1a28a84542c7ba321c1c11178b83ae024257b47" + integrity sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg== -"@commitlint/top-level@^17.4.0": - version "17.4.0" - resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-17.4.0.tgz#540cac8290044cf846fbdd99f5cc51e8ac5f27d6" - integrity sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g== +"@commitlint/top-level@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-19.8.1.tgz#2c942189d83a29b21ff7ba6e91607301efdf5916" + integrity sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw== dependencies: - find-up "^5.0.0" + find-up "^7.0.0" -"@commitlint/types@^17.4.4": - version "17.4.4" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-17.4.4.tgz#1416df936e9aad0d6a7bbc979ecc31e55dade662" - integrity sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ== +"@commitlint/types@^19.8.1": + version "19.8.1" + resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-19.8.1.tgz#7971fbd56b0cfb31692a4e1941b74ac8217c44e5" + integrity sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw== dependencies: - chalk "^4.1.0" + "@types/conventional-commits-parser" "^5.0.0" + chalk "^5.3.0" -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== +"@emnapi/core@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" + integrity sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q== dependencies: - "@jridgewell/trace-mapping" "0.3.9" + "@emnapi/wasi-threads" "1.0.4" + tslib "^2.4.0" -"@eslint-community/eslint-utils@^4.2.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== +"@emnapi/runtime@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9" + integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg== dependencies: - eslint-visitor-keys "^3.3.0" + tslib "^2.4.0" -"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": - version "4.6.2" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" - integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== +"@emnapi/wasi-threads@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz#703fc094d969e273b1b71c292523b2f792862bf4" + integrity sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g== + dependencies: + tslib "^2.4.0" + +"@esbuild/aix-ppc64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9" + integrity sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA== + +"@esbuild/android-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz#d2e70be7d51a529425422091e0dcb90374c1546c" + integrity sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg== + +"@esbuild/android-arm@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.9.tgz#d2a753fe2a4c73b79437d0ba1480e2d760097419" + integrity sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ== + +"@esbuild/android-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.9.tgz#5278836e3c7ae75761626962f902a0d55352e683" + integrity sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw== + +"@esbuild/darwin-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz#f1513eaf9ec8fa15dcaf4c341b0f005d3e8b47ae" + integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg== + +"@esbuild/darwin-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz#e27dbc3b507b3a1cea3b9280a04b8b6b725f82be" + integrity sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ== + +"@esbuild/freebsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz#364e3e5b7a1fd45d92be08c6cc5d890ca75908ca" + integrity sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q== + +"@esbuild/freebsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz#7c869b45faeb3df668e19ace07335a0711ec56ab" + integrity sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg== + +"@esbuild/linux-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz#48d42861758c940b61abea43ba9a29b186d6cb8b" + integrity sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw== + +"@esbuild/linux-arm@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz#6ce4b9cabf148274101701d112b89dc67cc52f37" + integrity sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw== + +"@esbuild/linux-ia32@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz#207e54899b79cac9c26c323fc1caa32e3143f1c4" + integrity sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A== + +"@esbuild/linux-loong64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz#0ba48a127159a8f6abb5827f21198b999ffd1fc0" + integrity sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ== + +"@esbuild/linux-mips64el@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz#a4d4cc693d185f66a6afde94f772b38ce5d64eb5" + integrity sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA== + +"@esbuild/linux-ppc64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz#0f5805c1c6d6435a1dafdc043cb07a19050357db" + integrity sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w== + +"@esbuild/linux-riscv64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz#6776edece0f8fca79f3386398b5183ff2a827547" + integrity sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg== + +"@esbuild/linux-s390x@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz#3f6f29ef036938447c2218d309dc875225861830" + integrity sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA== + +"@esbuild/linux-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz#831fe0b0e1a80a8b8391224ea2377d5520e1527f" + integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg== + +"@esbuild/netbsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz#06f99d7eebe035fbbe43de01c9d7e98d2a0aa548" + integrity sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q== + +"@esbuild/netbsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz#db99858e6bed6e73911f92a88e4edd3a8c429a52" + integrity sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g== + +"@esbuild/openbsd-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz#afb886c867e36f9d86bb21e878e1185f5d5a0935" + integrity sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ== + +"@esbuild/openbsd-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz#30855c9f8381fac6a0ef5b5f31ac6e7108a66ecf" + integrity sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA== + +"@esbuild/openharmony-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz#2f2144af31e67adc2a8e3705c20c2bd97bd88314" + integrity sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg== + +"@esbuild/sunos-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz#69b99a9b5bd226c9eb9c6a73f990fddd497d732e" + integrity sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw== + +"@esbuild/win32-arm64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz#d789330a712af916c88325f4ffe465f885719c6b" + integrity sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ== + +"@esbuild/win32-ia32@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz#52fc735406bd49688253e74e4e837ac2ba0789e3" + integrity sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww== + +"@esbuild/win32-x64@0.25.9": + version "0.25.9" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz#585624dc829cfb6e7c0aa6c3ca7d7e6daa87e34f" + integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -295,10 +370,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@^8.47.0": - version "8.47.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d" - integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og== +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== "@eth-optimism/contracts@^0.5.21": version "0.5.40" @@ -331,754 +406,384 @@ bufio "^1.0.7" chai "^4.3.4" -"@ethereumjs/rlp@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" - integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== - -"@ethereumjs/util@^8.0.0", "@ethereumjs/util@^8.0.6": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" - integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== - dependencies: - "@ethereumjs/rlp" "^4.0.1" - ethereum-cryptography "^2.0.0" - micro-ftch "^0.3.1" - -"@ethersproject/abi@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.4.0.tgz#a6d63bdb3672f738398846d4279fa6b6c9818242" - integrity sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw== - dependencies: - "@ethersproject/address" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/constants" "^5.4.0" - "@ethersproject/hash" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - -"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.4.0", "@ethersproject/abi@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" - integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/abstract-provider@5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.4.1.tgz#e404309a29f771bd4d28dbafadcaa184668c2a6e" - integrity sha512-3EedfKI3LVpjSKgAxoUaI+gB27frKsxzm+r21w9G60Ugk+3wVLQwhi1LsEJAKNV7WoZc8CIpNrATlL1QFABjtQ== - dependencies: - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/networks" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/transactions" "^5.4.0" - "@ethersproject/web" "^5.4.0" - -"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.4.0", "@ethersproject/abstract-provider@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" - integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - -"@ethersproject/abstract-signer@5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.4.1.tgz#e4e9abcf4dd4f1ba0db7dff9746a5f78f355ea81" - integrity sha512-SkkFL5HVq1k4/25dM+NWP9MILgohJCgGv5xT5AcRruGz4ILpfHeBtO/y6j+Z3UN/PAjDeb4P7E51Yh8wcGNLGA== - dependencies: - "@ethersproject/abstract-provider" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - -"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.4.0", "@ethersproject/abstract-signer@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" - integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/address@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.4.0.tgz#ba2d00a0f8c4c0854933b963b9a3a9f6eb4a37a3" - integrity sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q== - dependencies: - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/rlp" "^5.4.0" - -"@ethersproject/address@5.7.0", "@ethersproject/address@^5.4.0", "@ethersproject/address@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" - integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - -"@ethersproject/base64@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.4.0.tgz#7252bf65295954c9048c7ca5f43e5c86441b2a9a" - integrity sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ== - dependencies: - "@ethersproject/bytes" "^5.4.0" - -"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.4.0", "@ethersproject/base64@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" - integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - -"@ethersproject/basex@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.4.0.tgz#0a2da0f4e76c504a94f2b21d3161ed9438c7f8a6" - integrity sha512-J07+QCVJ7np2bcpxydFVf/CuYo9mZ7T73Pe7KQY4c1lRlrixMeblauMxHXD0MPwFmUHZIILDNViVkykFBZylbg== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - -"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.4.0", "@ethersproject/basex@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/bignumber@5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.4.1.tgz#64399d3b9ae80aa83d483e550ba57ea062c1042d" - integrity sha512-fJhdxqoQNuDOk6epfM7yD6J8Pol4NUCy1vkaGAkuujZm0+lNow//MKu1hLhRiYV4BsOHyBv5/lsTjF+7hWwhJg== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - bn.js "^4.11.9" - -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.4.0", "@ethersproject/bignumber@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" +"@ethersproject/abi@5.8.0", "@ethersproject/abi@^5.7.0", "@ethersproject/abi@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.8.0.tgz#e79bb51940ac35fe6f3262d7fe2cdb25ad5f07d9" + integrity sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== + dependencies: + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/abstract-provider@5.8.0", "@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz#7581f9be601afa1d02b95d26b9d9840926a35b0c" + integrity sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/networks" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/web" "^5.8.0" + +"@ethersproject/abstract-signer@5.8.0", "@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz#8d7417e95e4094c1797a9762e6789c7356db0754" + integrity sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + +"@ethersproject/address@5.8.0", "@ethersproject/address@^5.7.0", "@ethersproject/address@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.8.0.tgz#3007a2c352eee566ad745dca1dbbebdb50a6a983" + integrity sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + +"@ethersproject/base64@5.8.0", "@ethersproject/base64@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.8.0.tgz#61c669c648f6e6aad002c228465d52ac93ee83eb" + integrity sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== + dependencies: + "@ethersproject/bytes" "^5.8.0" + +"@ethersproject/basex@5.8.0", "@ethersproject/basex@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.8.0.tgz#1d279a90c4be84d1c1139114a1f844869e57d03a" + integrity sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + +"@ethersproject/bignumber@5.8.0", "@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.8.0.tgz#c381d178f9eeb370923d389284efa19f69efa5d7" + integrity sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" bn.js "^5.2.1" -"@ethersproject/bytes@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.4.0.tgz#56fa32ce3bf67153756dbaefda921d1d4774404e" - integrity sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA== - dependencies: - "@ethersproject/logger" "^5.4.0" - -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.4.0", "@ethersproject/bytes@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/constants@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.4.0.tgz#ee0bdcb30bf1b532d2353c977bf2ef1ee117958a" - integrity sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q== - dependencies: - "@ethersproject/bignumber" "^5.4.0" - -"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.4.0", "@ethersproject/constants@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - -"@ethersproject/contracts@5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.4.1.tgz#3eb4f35b7fe60a962a75804ada2746494df3e470" - integrity sha512-m+z2ZgPy4pyR15Je//dUaymRUZq5MtDajF6GwFbGAVmKz/RF+DNIPwF0k5qEcL3wPGVqUjFg2/krlCRVTU4T5w== - dependencies: - "@ethersproject/abi" "^5.4.0" - "@ethersproject/abstract-provider" "^5.4.0" - "@ethersproject/abstract-signer" "^5.4.0" - "@ethersproject/address" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/constants" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/transactions" "^5.4.0" - -"@ethersproject/contracts@5.7.0", "@ethersproject/contracts@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" - integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - -"@ethersproject/hash@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.4.0.tgz#d18a8e927e828e22860a011f39e429d388344ae0" - integrity sha512-xymAM9tmikKgbktOCjW60Z5sdouiIIurkZUr9oW5NOex5uwxrbsYG09kb5bMcNjlVeJD3yPivTNzViIs1GCbqA== - dependencies: - "@ethersproject/abstract-signer" "^5.4.0" - "@ethersproject/address" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - -"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.4.0", "@ethersproject/hash@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" - integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/hdnode@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.4.0.tgz#4bc9999b9a12eb5ce80c5faa83114a57e4107cac" - integrity sha512-pKxdS0KAaeVGfZPp1KOiDLB0jba11tG6OP1u11QnYfb7pXn6IZx0xceqWRr6ygke8+Kw74IpOoSi7/DwANhy8Q== - dependencies: - "@ethersproject/abstract-signer" "^5.4.0" - "@ethersproject/basex" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/pbkdf2" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/sha2" "^5.4.0" - "@ethersproject/signing-key" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - "@ethersproject/transactions" "^5.4.0" - "@ethersproject/wordlists" "^5.4.0" - -"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.4.0", "@ethersproject/hdnode@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/json-wallets@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.4.0.tgz#2583341cfe313fc9856642e8ace3080154145e95" - integrity sha512-igWcu3fx4aiczrzEHwG1xJZo9l1cFfQOWzTqwRw/xcvxTk58q4f9M7cjh51EKphMHvrJtcezJ1gf1q1AUOfEQQ== - dependencies: - "@ethersproject/abstract-signer" "^5.4.0" - "@ethersproject/address" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/hdnode" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/pbkdf2" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/random" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - "@ethersproject/transactions" "^5.4.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.4.0", "@ethersproject/json-wallets@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" +"@ethersproject/bytes@5.8.0", "@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.8.0.tgz#9074820e1cac7507a34372cadeb035461463be34" + integrity sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/constants@5.8.0", "@ethersproject/constants@^5.7.0", "@ethersproject/constants@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.8.0.tgz#12f31c2f4317b113a4c19de94e50933648c90704" + integrity sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + +"@ethersproject/contracts@5.8.0", "@ethersproject/contracts@^5.7.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.8.0.tgz#243a38a2e4aa3e757215ea64e276f8a8c9d8ed73" + integrity sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ== + dependencies: + "@ethersproject/abi" "^5.8.0" + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + +"@ethersproject/hash@5.8.0", "@ethersproject/hash@^5.7.0", "@ethersproject/hash@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.8.0.tgz#b8893d4629b7f8462a90102572f8cd65a0192b4c" + integrity sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/base64" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/hdnode@5.8.0", "@ethersproject/hdnode@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.8.0.tgz#a51ae2a50bcd48ef6fd108c64cbae5e6ff34a761" + integrity sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/basex" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/pbkdf2" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/wordlists" "^5.8.0" + +"@ethersproject/json-wallets@5.8.0", "@ethersproject/json-wallets@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz#d18de0a4cf0f185f232eb3c17d5e0744d97eb8c9" + integrity sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/hdnode" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/pbkdf2" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/random" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" aes-js "3.0.0" scrypt-js "3.0.1" -"@ethersproject/keccak256@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.4.0.tgz#7143b8eea4976080241d2bd92e3b1f1bf7025318" - integrity sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A== - dependencies: - "@ethersproject/bytes" "^5.4.0" - js-sha3 "0.5.7" - -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.4.0", "@ethersproject/keccak256@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" - integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== +"@ethersproject/keccak256@5.8.0", "@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.8.0.tgz#d2123a379567faf2d75d2aaea074ffd4df349e6a" + integrity sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== dependencies: - "@ethersproject/bytes" "^5.7.0" + "@ethersproject/bytes" "^5.8.0" js-sha3 "0.8.0" -"@ethersproject/logger@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.4.0.tgz#f39adadf62ad610c420bcd156fd41270e91b3ca9" - integrity sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ== - -"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.4.0", "@ethersproject/logger@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - -"@ethersproject/networks@5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.4.2.tgz#2247d977626e97e2c3b8ee73cd2457babde0ce35" - integrity sha512-eekOhvJyBnuibfJnhtK46b8HimBc5+4gqpvd1/H9LEl7Q7/qhsIhM81dI9Fcnjpk3jB1aTy6bj0hz3cifhNeYw== - dependencies: - "@ethersproject/logger" "^5.4.0" - -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.4.0", "@ethersproject/networks@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" - integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/pbkdf2@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.4.0.tgz#ed88782a67fda1594c22d60d0ca911a9d669641c" - integrity sha512-x94aIv6tiA04g6BnazZSLoRXqyusawRyZWlUhKip2jvoLpzJuLb//KtMM6PEovE47pMbW+Qe1uw+68ameJjB7g== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/sha2" "^5.4.0" - -"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.4.0", "@ethersproject/pbkdf2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - -"@ethersproject/properties@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.4.0.tgz#38ba20539b44dcc5d5f80c45ad902017dcdbefe7" - integrity sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A== - dependencies: - "@ethersproject/logger" "^5.4.0" - -"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.4.0", "@ethersproject/properties@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" - integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/providers@5.4.3": - version "5.4.3" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.4.3.tgz#4cd7ccd9e12bc3875b33df8b24abf735663958a5" - integrity sha512-VURwkaWPoUj7jq9NheNDT5Iyy64Qcyf6BOFDwVdHsmLmX/5prNjFrgSX3GHPE4z1BRrVerDxe2yayvXKFm/NNg== - dependencies: - "@ethersproject/abstract-provider" "^5.4.0" - "@ethersproject/abstract-signer" "^5.4.0" - "@ethersproject/address" "^5.4.0" - "@ethersproject/basex" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/constants" "^5.4.0" - "@ethersproject/hash" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/networks" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/random" "^5.4.0" - "@ethersproject/rlp" "^5.4.0" - "@ethersproject/sha2" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - "@ethersproject/transactions" "^5.4.0" - "@ethersproject/web" "^5.4.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.0.10", "@ethersproject/providers@^5.7.0", "@ethersproject/providers@^5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" +"@ethersproject/logger@5.8.0", "@ethersproject/logger@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.8.0.tgz#f0232968a4f87d29623a0481690a2732662713d6" + integrity sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== + +"@ethersproject/networks@5.8.0", "@ethersproject/networks@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.8.0.tgz#8b4517a3139380cba9fb00b63ffad0a979671fde" + integrity sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/pbkdf2@5.8.0", "@ethersproject/pbkdf2@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz#cd2621130e5dd51f6a0172e63a6e4a0c0a0ec37e" + integrity sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + +"@ethersproject/properties@5.8.0", "@ethersproject/properties@^5.7.0", "@ethersproject/properties@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.8.0.tgz#405a8affb6311a49a91dabd96aeeae24f477020e" + integrity sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/providers@5.8.0", "@ethersproject/providers@^5.0.10", "@ethersproject/providers@^5.7.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.8.0.tgz#6c2ae354f7f96ee150439f7de06236928bc04cb4" + integrity sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/base64" "^5.8.0" + "@ethersproject/basex" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/networks" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/random" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/web" "^5.8.0" bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.4.0.tgz#9cdde60e160d024be39cc16f8de3b9ce39191e16" - integrity sha512-pnpWNQlf0VAZDEOVp1rsYQosmv2o0ITS/PecNw+mS2/btF8eYdspkN0vIXrCMtkX09EAh9bdk8GoXmFXM1eAKw== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - -"@ethersproject/random@5.7.0", "@ethersproject/random@^5.4.0", "@ethersproject/random@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" + ws "8.18.0" -"@ethersproject/rlp@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.4.0.tgz#de61afda5ff979454e76d3b3310a6c32ad060931" - integrity sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg== +"@ethersproject/random@5.8.0", "@ethersproject/random@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.8.0.tgz#1bced04d49449f37c6437c701735a1a022f0057a" + integrity sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A== dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" -"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.4.0", "@ethersproject/rlp@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" - integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== +"@ethersproject/rlp@5.8.0", "@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.8.0.tgz#5a0d49f61bc53e051532a5179472779141451de5" + integrity sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" -"@ethersproject/sha2@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.4.0.tgz#c9a8db1037014cbc4e9482bd662f86c090440371" - integrity sha512-siheo36r1WD7Cy+bDdE1BJ8y0bDtqXCOxRMzPa4bV1TGt/eTUUt03BHoJNB6reWJD8A30E/pdJ8WFkq+/uz4Gg== +"@ethersproject/sha2@5.8.0", "@ethersproject/sha2@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.8.0.tgz#8954a613bb78dac9b46829c0a95de561ef74e5e1" + integrity sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A== dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - hash.js "1.1.7" - -"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.4.0", "@ethersproject/sha2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.4.0.tgz#2f05120984e81cf89a3d5f6dec5c68ee0894fbec" - integrity sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - bn.js "^4.11.9" - elliptic "6.5.4" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" hash.js "1.1.7" -"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.4.0", "@ethersproject/signing-key@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" - integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== +"@ethersproject/signing-key@5.8.0", "@ethersproject/signing-key@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.8.0.tgz#9797e02c717b68239c6349394ea85febf8893119" + integrity sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" bn.js "^5.2.1" - elliptic "6.5.4" + elliptic "6.6.1" hash.js "1.1.7" -"@ethersproject/solidity@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.4.0.tgz#1305e058ea02dc4891df18b33232b11a14ece9ec" - integrity sha512-XFQTZ7wFSHOhHcV1DpcWj7VXECEiSrBuv7JErJvB9Uo+KfCdc3QtUZV+Vjh/AAaYgezUEKbCtE6Khjm44seevQ== - dependencies: - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/sha2" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - -"@ethersproject/solidity@5.7.0", "@ethersproject/solidity@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" - integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/strings@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.4.0.tgz#fb12270132dd84b02906a8d895ae7e7fa3d07d9a" - integrity sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/constants" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - -"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.4.0", "@ethersproject/strings@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" - integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/transactions@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.4.0.tgz#a159d035179334bd92f340ce0f77e83e9e1522e0" - integrity sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ== - dependencies: - "@ethersproject/address" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/constants" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/rlp" "^5.4.0" - "@ethersproject/signing-key" "^5.4.0" - -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.4.0", "@ethersproject/transactions@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" - integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - -"@ethersproject/units@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.4.0.tgz#d57477a4498b14b88b10396062c8cbbaf20c79fe" - integrity sha512-Z88krX40KCp+JqPCP5oPv5p750g+uU6gopDYRTBGcDvOASh6qhiEYCRatuM/suC4S2XW9Zz90QI35MfSrTIaFg== - dependencies: - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/constants" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - -"@ethersproject/units@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/wallet@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.4.0.tgz#fa5b59830b42e9be56eadd45a16a2e0933ad9353" - integrity sha512-wU29majLjM6AjCjpat21mPPviG+EpK7wY1+jzKD0fg3ui5fgedf2zEu1RDgpfIMsfn8fJHJuzM4zXZ2+hSHaSQ== - dependencies: - "@ethersproject/abstract-provider" "^5.4.0" - "@ethersproject/abstract-signer" "^5.4.0" - "@ethersproject/address" "^5.4.0" - "@ethersproject/bignumber" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/hash" "^5.4.0" - "@ethersproject/hdnode" "^5.4.0" - "@ethersproject/json-wallets" "^5.4.0" - "@ethersproject/keccak256" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/random" "^5.4.0" - "@ethersproject/signing-key" "^5.4.0" - "@ethersproject/transactions" "^5.4.0" - "@ethersproject/wordlists" "^5.4.0" - -"@ethersproject/wallet@5.7.0", "@ethersproject/wallet@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/web@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.4.0.tgz#49fac173b96992334ed36a175538ba07a7413d1f" - integrity sha512-1bUusGmcoRLYgMn6c1BLk1tOKUIFuTg8j+6N8lYlbMpDesnle+i3pGSagGNvwjaiLo4Y5gBibwctpPRmjrh4Og== - dependencies: - "@ethersproject/base64" "^5.4.0" - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - -"@ethersproject/web@5.7.1", "@ethersproject/web@^5.4.0", "@ethersproject/web@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" - integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/wordlists@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.4.0.tgz#f34205ec3bbc9e2c49cadaee774cf0b07e7573d7" - integrity sha512-FemEkf6a+EBKEPxlzeVgUaVSodU7G0Na89jqKjmWMlDB0tomoU8RlEMgUvXyqtrg8N4cwpLh8nyRnm1Nay1isA== - dependencies: - "@ethersproject/bytes" "^5.4.0" - "@ethersproject/hash" "^5.4.0" - "@ethersproject/logger" "^5.4.0" - "@ethersproject/properties" "^5.4.0" - "@ethersproject/strings" "^5.4.0" - -"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.4.0", "@ethersproject/wordlists@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@gearbox-protocol/core-v2@1.19.0-base.10": - version "1.19.0-base.10" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/core-v2/-/core-v2-1.19.0-base.10.tgz#a21bce9eac4ca1783f5fcb4322b1c1257158d2de" - integrity sha512-S9reS5zGt+cKxEdQppVCU0cZEmnSqx8DaoloY6KXqCsAedVJvwNUoCHnLjh9s/oWyOHa37qExN1QohntNQyB2Q== - -"@gearbox-protocol/core-v3@^1.51.0": - version "1.51.0" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/core-v3/-/core-v3-1.51.0.tgz#c7e61bbaa7187648834ac03ae34b3337c567d5a9" - integrity sha512-DqY+3f/MWrtlIS+PlUMg0k4NdWPoVtjKmpyqAPO3GytZq4wqwTnJ3Xqni/IAyqxIPQBGIEvuiLeHkdVaQmpYyA== - -"@gearbox-protocol/eslint-config@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/eslint-config/-/eslint-config-1.6.1.tgz#315a5c0b19593e925db32de72c27964adc44d2f8" - integrity sha512-CNOjCt8fNESxnub1dXNEZWVxMQiau+fOSbRY5q7xPIv7H6iYQTxdPDefC7geStC8dzqvv2F9t/dFUzPJjbEzuQ== - dependencies: - "@typescript-eslint/eslint-plugin" "^5.33.0" - "@typescript-eslint/parser" "^5.33.0" - eslint-config-alloy "^4.6.2" - eslint-import-resolver-typescript "^3.4.1" - eslint-plugin-import "^2.26.0" - eslint-plugin-react "^7.30.1" +"@ethersproject/solidity@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.8.0.tgz#429bb9fcf5521307a9448d7358c26b93695379b9" + integrity sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/sha2" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/strings@5.8.0", "@ethersproject/strings@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.8.0.tgz#ad79fafbf0bd272d9765603215ac74fd7953908f" + integrity sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/transactions@5.8.0", "@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.8.0.tgz#1e518822403abc99def5a043d1c6f6fe0007e46b" + integrity sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== + dependencies: + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + +"@ethersproject/units@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.8.0.tgz#c12f34ba7c3a2de0e9fa0ed0ee32f3e46c5c2c6a" + integrity sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/wallet@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.8.0.tgz#49c300d10872e6986d953e8310dc33d440da8127" + integrity sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/hdnode" "^5.8.0" + "@ethersproject/json-wallets" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/random" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/wordlists" "^5.8.0" + +"@ethersproject/web@5.8.0", "@ethersproject/web@^5.7.0", "@ethersproject/web@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.8.0.tgz#3e54badc0013b7a801463a7008a87988efce8a37" + integrity sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== + dependencies: + "@ethersproject/base64" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/wordlists@5.8.0", "@ethersproject/wordlists@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.8.0.tgz#7a5654ee8d1bb1f4dbe43f91d217356d650ad821" + integrity sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@gearbox-protocol/eslint-config@^2.0.0-next.2": + version "2.0.0-next.2" + resolved "https://registry.yarnpkg.com/@gearbox-protocol/eslint-config/-/eslint-config-2.0.0-next.2.tgz#c3595959714c7da4daea822138d61e82238f5a29" + integrity sha512-DYG3i2WO11IGS+WgygdmMMAudJp5MfhzYmy1mbynH3nhNA2WjzdUyhRWn/wqdaUW060pB3uAnStwX5KIiDHpDQ== + dependencies: + "@typescript-eslint/eslint-plugin" "^6.7.2" + "@typescript-eslint/parser" "^6.7.2" + eslint-config-alloy "^5.1.2" + eslint-import-resolver-typescript "^3.6.0" + eslint-plugin-import "^2.28.1" + eslint-plugin-react "^7.33.2" eslint-plugin-react-hooks "^4.6.0" - eslint-plugin-simple-import-sort "^7.0.0" - eslint-plugin-unused-imports "^2.0.0" - -"@gearbox-protocol/oracles-v3@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/oracles-v3/-/oracles-v3-1.12.1.tgz#897623a71bbaa4e96f999d13342093a9d22f1d0c" - integrity sha512-B6ep1O53zmWXIzr+5mWHxLynSPnDRWbi/p/DADJor4ClkwhkjIqG8R+q06ooC2EbT74+KmwK8KNLRrDvfLT3Mw== - dependencies: - redstone-protocol "^1.0.5" + eslint-plugin-simple-import-sort "^10.0.0" + eslint-plugin-unused-imports "^3.0.0" -"@gearbox-protocol/prettier-config@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/prettier-config/-/prettier-config-1.5.0.tgz#4df8e9fd2305fee6ab8c1417a02e31343836932a" - integrity sha512-FUoprSsBdZyBjgxXCKL6mTkbeUJytaLzPJqIOoQpDmBRTX0seCc2o5I9PI9tySoRIlNnd/XXnKCXq1xHDEGbxw== +"@gearbox-protocol/prettier-config@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@gearbox-protocol/prettier-config/-/prettier-config-2.1.0.tgz#6b4de65b21b166a28f78309c056e0b5c3d137d7e" + integrity sha512-h+8hW69RQ9tJp+Hw5PnVxCGzNMSTi6xnERL+xikxBRBA6eFT7xqueaUbVRR/xBA82n4ue1LBNCdHPuIZj16OSg== -"@gearbox-protocol/sdk-gov@^2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/sdk-gov/-/sdk-gov-2.34.0.tgz#4240d0385f6b6ffd5f8886467b4827dc3c4d0c57" - integrity sha512-uvMIuf8snmlE2M9sHjUwlm7aMlpN9spO9SjdJzY22sciGFCbv1pGsC9waQKwiaHqoMhoOzp6BstSHHG/zgmRPg== +"@gearbox-protocol/sdk-gov@^2.37.0": + version "2.37.0" + resolved "https://registry.yarnpkg.com/@gearbox-protocol/sdk-gov/-/sdk-gov-2.37.0.tgz#bd546136fea833a8c6557401b43231b64cfed250" + integrity sha512-jQ8ObsXaxX8abeyvDnZ/79IdWYiwtB+C0lbDLsONaO0CSbyZG+NX5B+mD8fvytpVIxNR0vaOFXeWeQYNZyCL3g== dependencies: ethers "6.12.1" humanize-duration-ts "^2.1.1" zod "^3.22.2" -"@humanwhocodes/config-array@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -1086,59 +791,24 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@metamask/eth-sig-util@5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-5.0.2.tgz#c518279a6e17a88135a13d53a0b970f145ff8bce" - integrity sha512-RU6fG/H6/UlBol221uBkq5C7w3TwLK611nEZliO2u+kO0vHKGBXnIPlhI0tzKUigjhUeOd9mhCNbNvhh0LKt9Q== - dependencies: - "@ethereumjs/util" "^8.0.0" - bn.js "^4.11.8" - ethereum-cryptography "^1.1.2" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== -"@metamask/eth-sig-util@6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-6.0.0.tgz#083321dc7285a9aa6e066db7c49be6e94c5e03a3" - integrity sha512-M0ezVz8lirXG1P6rHPzx+9i4zfhebCgVHE8XQT8VWxy/eUWllHQGcBcE8QmOusC7su55M4CMr9AyMIu0lx452g== +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== dependencies: - "@ethereumjs/util" "^8.0.6" - bn.js "^4.12.0" - ethereum-cryptography "^2.0.0" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" -"@noble/curves@1.1.0", "@noble/curves@~1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" - integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== - dependencies: - "@noble/hashes" "1.3.1" +"@noble/ciphers@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.3.0.tgz#f64b8ff886c240e644e5573c097f86e5b43676dc" + integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== "@noble/curves@1.2.0": version "1.2.0" @@ -1147,30 +817,29 @@ dependencies: "@noble/hashes" "1.3.2" -"@noble/hashes@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" - integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== - -"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" - integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/curves@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.2.tgz#73388356ce733922396214a933ff7c95afcef911" + integrity sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g== + dependencies: + "@noble/hashes" "1.8.0" -"@noble/hashes@1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" - integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== +"@noble/curves@^1.9.1", "@noble/curves@~1.9.0": + version "1.9.6" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.6.tgz#b45ebedca85bb75782f6be7e7f120f0c423c99e0" + integrity sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA== + dependencies: + "@noble/hashes" "1.8.0" "@noble/hashes@1.3.2": version "1.3.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" - integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== +"@noble/hashes@1.8.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1193,50 +862,25 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/hardhat-ethers@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.3.tgz#e25072198e0f1c7d2fd895e78cd4917d261a7369" - integrity sha512-asTxUs6vg586UqL9Bi5sMvB7IrYebbgm3FkpxacbGsnb8Vr+8BB2k07nB0HNEPG3GLhTTFzalsbl0raGiPTUYg== - dependencies: - debug "^4.1.1" - lodash.isequal "^4.5.0" - -"@nomicfoundation/hardhat-network-helpers@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.8.tgz#e4fe1be93e8a65508c46d73c41fa26c7e9f84931" - integrity sha512-MNqQbzUJZnCMIYvlniC3U+kcavz/PhhQSsY90tbEtUyMj/IQqsLwIRZa4ctjABh3Bz0KCh9OXUZ7Yk/d9hr45Q== - dependencies: - ethereumjs-util "^7.1.4" - -"@nomiclabs/hardhat-ethers@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.2.tgz#812d48929c3bf8fe840ec29eab4b613693467679" - integrity sha512-NLDlDFL2us07C0jB/9wzvR0kuLivChJWCXTKcj3yqjZqMoYp7g7wwS157F70VHx/+9gHIBGzak5pKDwG8gEefA== +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== "@openzeppelin/contracts-upgradeable@^4.7.3": - version "4.9.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.3.tgz#ff17a80fb945f5102571f8efecb5ce5915cc4811" - integrity sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A== + version "4.9.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.6.tgz#38b21708a719da647de4bb0e4802ee235a0d24df" + integrity sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA== "@openzeppelin/contracts-v0.7@npm:@openzeppelin/contracts@v3.4.2": version "3.4.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== -"@openzeppelin/contracts@4.8.2": - version "4.8.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.8.2.tgz#d815ade0027b50beb9bcca67143c6bcc3e3923d6" - integrity sha512-kEUOgPQszC0fSYWpbh2kT94ltOJwj1qfT2DWo+zVttmGmf97JZ99LspePNaeeaLhCImaHVeBbjaQFZQn7+Zc5g== - -"@openzeppelin/contracts@4.9.2": - version "4.9.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.2.tgz#1cb2d5e4d3360141a17dbc45094a8cad6aac16c1" - integrity sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg== - -"@openzeppelin/contracts@4.9.3", "@openzeppelin/contracts@^4.7.3": - version "4.9.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" - integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== +"@openzeppelin/contracts@^4.7.3": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677" + integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA== "@openzeppelin/contracts@~4.3.3": version "4.3.3" @@ -1255,235 +899,285 @@ redstone-protocol "^1.0.5" redstone-sdk "^1.6.1" -"@scure/base@~1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" - integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== - -"@scure/bip32@1.1.5": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" - integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== - dependencies: - "@noble/hashes" "~1.2.0" - "@noble/secp256k1" "~1.7.0" - "@scure/base" "~1.1.0" - -"@scure/bip32@1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.1.tgz#7248aea723667f98160f593d621c47e208ccbb10" - integrity sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A== - dependencies: - "@noble/curves" "~1.1.0" - "@noble/hashes" "~1.3.1" - "@scure/base" "~1.1.0" - -"@scure/bip39@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" - integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== - dependencies: - "@noble/hashes" "~1.2.0" - "@scure/base" "~1.1.0" - -"@scure/bip39@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" - integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg== - dependencies: - "@noble/hashes" "~1.3.0" - "@scure/base" "~1.1.0" - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - -"@typechain/ethers-v5@^10.1.0": - version "10.2.1" - resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz#50241e6957683281ecfa03fb5a6724d8a3ce2391" - integrity sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A== - dependencies: - lodash "^4.17.15" - ts-essentials "^7.0.1" - -"@types/bn.js@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" - integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== - dependencies: - "@types/node" "*" - -"@types/json-schema@^7.0.9": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - -"@types/minimist@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@types/node@*": - version "20.5.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.1.tgz#178d58ee7e4834152b0e8b4d30cbfab578b9bb30" - integrity sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg== +"@scure/base@~1.2.5": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== -"@types/node@18.15.13": - version "18.15.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" - integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== +"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" + integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== + dependencies: + "@noble/curves" "~1.9.0" + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" -"@types/node@20.4.7": - version "20.4.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab" - integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g== +"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" + integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== + dependencies: + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" -"@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== +"@tybys/wasm-util@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" + integrity sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ== + dependencies: + tslib "^2.4.0" -"@types/pbkdf2@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" - integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== +"@types/conventional-commits-parser@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz#8cb81cf170853496cbc501a3b32dcf5e46ffb61a" + integrity sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ== dependencies: "@types/node" "*" -"@types/prettier@^2.1.1": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" - integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/qs@^6.9.7": - version "6.9.8" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.8.tgz#f2a7de3c107b89b441e071d5472e6b726b4adf45" - integrity sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/secp256k1@^4.0.1": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" - integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== +"@types/node@*", "@types/node@^24.2.1": + version "24.2.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.2.1.tgz#83e41543f0a518e006594bb394e2cd961de56727" + integrity sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ== dependencies: - "@types/node" "*" + undici-types "~7.10.0" -"@types/semver@^7.3.12": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" - integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== -"@typescript-eslint/eslint-plugin@^5.33.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" - integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== - dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/type-utils" "5.62.0" - "@typescript-eslint/utils" "5.62.0" +"@types/semver@^7.5.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.7.0.tgz#64c441bdae033b378b6eef7d0c3d77c329b9378e" + integrity sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA== + +"@typescript-eslint/eslint-plugin@^6.7.2": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" + integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/type-utils" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" graphemer "^1.4.0" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.33.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" - integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== - dependencies: - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^6.7.2": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" - integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/type-utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" - integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== +"@typescript-eslint/type-utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" + integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== dependencies: - "@typescript-eslint/typescript-estree" "5.62.0" - "@typescript-eslint/utils" "5.62.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/utils" "6.21.0" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.0.1" -"@typescript-eslint/types@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" - integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/typescript-estree@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" - integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" + integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" -"@typescript-eslint/utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" - integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - eslint-scope "^5.1.1" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" - integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== - dependencies: - "@typescript-eslint/types" "5.62.0" - eslint-visitor-keys "^3.3.0" - -"@uniswap/permit2-sdk@1.2.0", "@uniswap/permit2-sdk@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@uniswap/permit2-sdk/-/permit2-sdk-1.2.0.tgz#ed86440a87a6c318169c8e6f161fc263ad040891" - integrity sha512-Ietv3FxN7+RCXcPSED/i/8b0a2GUZrMdyX05k3FsSztvYKyPFAMS/hBXojF0NZqYB1bHecqYc7Ej+7tV/rdYXg== - dependencies: - ethers "^5.3.1" - tiny-invariant "^1.3.1" +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz#36fb318eebdd690f6da32ac5e0499a76fa881935" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + +"@unrs/resolver-binding-win32-x64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== + +"@wagmi/cli@^2.3.2": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@wagmi/cli/-/cli-2.4.0.tgz#7af36e29d22969ee48c2a68fb7717d2324b66d65" + integrity sha512-SVaUbq+M6XDCVR7IdFFxILqxYax+CsUmqqmTiO9XJJcM8fDgTXFZF318l+n7bodgoCMlmcJvpl3eED5Pbws9bg== + dependencies: + abitype "^1.0.4" + bundle-require "^5.1.0" + cac "^6.7.14" + change-case "^5.4.4" + chokidar "4.0.1" + dedent "^0.7.0" + dotenv "^16.3.1" + dotenv-expand "^10.0.0" + esbuild "~0.25.4" + escalade "3.2.0" + fdir "^6.1.1" + nanospinner "1.2.2" + pathe "^1.1.2" + picocolors "^1.0.0" + picomatch "^3.0.0" + prettier "^3.0.3" + viem "2.x" + zod "^3.22.2" JSONStream@^1.3.5: version "1.3.5" @@ -1493,20 +1187,20 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" +abitype@1.0.8, abitype@^1.0.4, abitype@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba" + integrity sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.4.1, acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn@^8.9.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== aes-js@3.0.0: version "3.0.0" @@ -1529,26 +1223,21 @@ ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.11.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: - fast-deep-equal "^3.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.2.2" -ansi-colors@^4.1.1: - version "4.1.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - -ansi-escapes@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6" - integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== dependencies: - type-fest "^1.0.2" + environment "^1.0.0" ansi-regex@^5.0.1: version "5.0.1" @@ -1556,16 +1245,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" @@ -1574,155 +1256,138 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^6.0.0, ansi-styles@^6.1.0: +ansi-styles@^6.0.0, ansi-styles@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-back@^3.0.1, array-back@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" - integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== - -array-back@^4.0.1, array-back@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" - integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== - -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" + call-bound "^1.0.3" + is-array-buffer "^3.0.5" array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== +array-includes@^3.1.6, array-includes@^3.1.8, array-includes@^3.1.9: + version "3.1.9" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a" + integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - is-string "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.0" + es-object-atoms "^1.1.1" + get-intrinsic "^1.3.0" + is-string "^1.1.1" + math-intrinsics "^1.1.0" array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz#bc229aef98f6bd0533a2bc61ff95209875526c9b" - integrity sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" - -array.prototype.flat@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.tosorted@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" - integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== +array.prototype.findlastindex@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564" + integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-shim-unscopables "^1.1.0" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" -arraybuffer.prototype.slice@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" - integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -asynciterator.prototype@^1.0.0: +async-function@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" - integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== - dependencies: - has-symbols "^1.0.3" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== dependencies: - follow-redirects "^1.14.0" + possible-typed-array-names "^1.0.0" axios@^0.27.2: version "0.27.2" @@ -1732,22 +1397,13 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axios@^1.1.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" - integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axios@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" - integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== +axios@^1.1.3, axios@^1.5.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.11.0.tgz#c2ec219e35e414c025b2095e8b8280278478fdb6" + integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA== dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" + follow-redirects "^1.15.6" + form-data "^4.0.4" proxy-from-env "^1.1.0" balanced-match@^1.0.0: @@ -1755,151 +1411,110 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - bech32@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -blakejs@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" - integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== - -bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +bn.js@^4.11.9: + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== -bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +bn.js@^5.2.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== -browserify-aes@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" +bufio@^1.0.7: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.2.3.tgz#25049c13f05e7cf56c88aa00f2503202b4bf2799" + integrity sha512-5Tt66bRzYUSlVZatc0E92uDenreJ+DpTBmSAUwL4VSxJn3e6cUyYwx+PoqML0GRZatgA/VX8ybhxItF8InZgqA== -bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== +bundle-require@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.1.0.tgz#8db66f41950da3d77af1ef3322f4c3e04009faee" + integrity sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA== dependencies: - base-x "^3.0.2" + load-tsconfig "^0.2.3" -bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" -bufio@^1.0.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.2.0.tgz#b9ad1c06b0d9010363c387c39d2810a7086d143f" - integrity sha512-UlFk8z/PwdhYQTXSQQagwGAdtRI83gib2n4uy4rQnenxUM2yQi8lBDzF230BNk+3wAoZDxYRoBwVVUPgHa9MCA== +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - chai@^4.3.4: - version "4.3.7" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" - integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== dependencies: assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^4.1.2" - get-func-name "^2.0.0" - loupe "^2.3.1" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" pathval "^1.1.1" - type-detect "^4.0.5" - -chalk@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + type-detect "^4.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1907,48 +1522,44 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== - -chokidar@^3.5.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" +chalk@^5.3.0, chalk@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.5.0.tgz#67ada1df5ca809dc84c9b819d76418ddcf128428" + integrity sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg== -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== +change-case@^5.4.4: + version "5.4.4" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02" + integrity sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w== + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + get-func-name "^2.0.2" -cli-cursor@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" - integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== +chokidar@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41" + integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA== dependencies: - restore-cursor "^4.0.0" + readdirp "^4.0.1" -cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== dependencies: slice-ansi "^5.0.0" - string-width "^5.0.0" + string-width "^7.0.0" cliui@^8.0.1: version "8.0.1" @@ -1959,13 +1570,6 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1973,11 +1577,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -1995,30 +1594,10 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -command-line-args@^5.1.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" - integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== - dependencies: - array-back "^3.1.0" - find-replace "^3.0.0" - lodash.camelcase "^4.3.0" - typical "^4.0.0" - -command-line-usage@^6.1.0: - version "6.1.3" - resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" - integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== - dependencies: - array-back "^4.0.2" - chalk "^2.4.2" - table-layout "^1.0.2" - typical "^5.2.0" - -commander@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" - integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== +commander@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.0.tgz#f244fc74a92343514e56229f16ef5c5e22ced5e9" + integrity sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA== compare-func@^2.0.0: version "2.0.0" @@ -2033,93 +1612,87 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -conventional-changelog-angular@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz#a9a9494c28b7165889144fd5b91573c4aa9ca541" - integrity sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg== +conventional-changelog-angular@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" + integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ== dependencies: compare-func "^2.0.0" -conventional-changelog-conventionalcommits@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz#3bad05f4eea64e423d3d90fc50c17d2c8cf17652" - integrity sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw== +conventional-changelog-conventionalcommits@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz#aa5da0f1b2543094889e8cf7616ebe1a8f5c70d5" + integrity sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w== dependencies: compare-func "^2.0.0" -conventional-commits-parser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz#02ae1178a381304839bce7cea9da5f1b549ae505" - integrity sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg== +conventional-commits-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#57f3594b81ad54d40c1b4280f04554df28627d9a" + integrity sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA== dependencies: JSONStream "^1.3.5" - is-text-path "^1.0.1" - meow "^8.1.2" - split2 "^3.2.2" - -cosmiconfig-typescript-loader@^4.0.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.4.0.tgz#f3feae459ea090f131df5474ce4b1222912319f9" - integrity sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw== - -cosmiconfig@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" - integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== - dependencies: - import-fresh "^3.2.1" - js-yaml "^4.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" + is-text-path "^2.0.0" + meow "^12.0.1" + split2 "^4.0.0" -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== +cosmiconfig-typescript-loader@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz#7f644503e1c2bff90aed2d29a637008f279646bb" + integrity sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g== dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" + jiti "^2.4.1" -create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== +dargs@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-8.1.0.tgz#a34859ea509cbce45485e5aa356fef70bfcc7272" + integrity sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw== -debug@4.3.4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== dependencies: - ms "2.1.2" + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" debug@^3.2.7: version "3.2.7" @@ -2128,46 +1701,50 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -decamelize-keys@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" - integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + ms "^2.1.3" decimal.js@^10.4.3: - version "10.4.3" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" - integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== -deep-eql@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" - integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== dependencies: type-detect "^4.0.0" -deep-extend@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" @@ -2176,11 +1753,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -2209,20 +1781,29 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" -dotenv@^16.0.3: - version "16.3.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" - integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +dotenv@^16.3.1: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" -elliptic@6.5.4, elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== +elliptic@6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== dependencies: bn.js "^4.11.9" brorand "^1.1.0" @@ -2232,36 +1813,25 @@ elliptic@6.5.4, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emoji-regex@^10.3.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -encode-utf8@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" - integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== - -enhanced-resolve@^5.12.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -enquirer@^2.3.6: - version "2.4.1" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" - integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== - dependencies: - ansi-colors "^4.1.1" - strip-ansi "^6.0.1" +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== error-ex@^1.3.1: version "1.3.2" @@ -2270,117 +1840,179 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2, es-abstract@^1.21.3: - version "1.22.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" - integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.1" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.2.1" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0: + version "1.24.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" + integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.3" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.0" - safe-array-concat "^1.0.0" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.10" - -es-iterator-helpers@^1.0.12: - version "1.0.13" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.13.tgz#72101046ffc19baf9996adc70e6177a26e6e8084" - integrity sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA== - dependencies: - asynciterator.prototype "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.21.3" - es-set-tostringtag "^2.0.1" - function-bind "^1.1.1" - get-intrinsic "^1.2.1" - globalthis "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - iterator.prototype "^1.1.0" - safe-array-concat "^1.0.0" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-iterator-helpers@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75" + integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.6" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + iterator.prototype "^1.1.4" + safe-array-concat "^1.1.3" + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" + es-errors "^1.3.0" -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== +es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== dependencies: - has "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== +es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" + hasown "^2.0.2" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +esbuild@~0.25.4: + version "0.25.9" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.9.tgz#15ab8e39ae6cdc64c24ff8a2c0aef5b3fd9fa976" + integrity sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.9" + "@esbuild/android-arm" "0.25.9" + "@esbuild/android-arm64" "0.25.9" + "@esbuild/android-x64" "0.25.9" + "@esbuild/darwin-arm64" "0.25.9" + "@esbuild/darwin-x64" "0.25.9" + "@esbuild/freebsd-arm64" "0.25.9" + "@esbuild/freebsd-x64" "0.25.9" + "@esbuild/linux-arm" "0.25.9" + "@esbuild/linux-arm64" "0.25.9" + "@esbuild/linux-ia32" "0.25.9" + "@esbuild/linux-loong64" "0.25.9" + "@esbuild/linux-mips64el" "0.25.9" + "@esbuild/linux-ppc64" "0.25.9" + "@esbuild/linux-riscv64" "0.25.9" + "@esbuild/linux-s390x" "0.25.9" + "@esbuild/linux-x64" "0.25.9" + "@esbuild/netbsd-arm64" "0.25.9" + "@esbuild/netbsd-x64" "0.25.9" + "@esbuild/openbsd-arm64" "0.25.9" + "@esbuild/openbsd-x64" "0.25.9" + "@esbuild/openharmony-arm64" "0.25.9" + "@esbuild/sunos-x64" "0.25.9" + "@esbuild/win32-arm64" "0.25.9" + "@esbuild/win32-ia32" "0.25.9" + "@esbuild/win32-x64" "0.25.9" + +escalade@3.2.0, escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-alloy@^4.6.2: - version "4.9.0" - resolved "https://registry.yarnpkg.com/eslint-config-alloy/-/eslint-config-alloy-4.9.0.tgz#44ed777e8eb0ee595baabeb5d6cb568c2e6461c2" - integrity sha512-4DfiN0sXByf5WuXioZrrZJdfzZw+lgdoQfFTuQyFenJ2XeIKrsXYctArLiZAoAsTxyZnmUFYqrgwUIXx26q0gg== +eslint-config-alloy@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/eslint-config-alloy/-/eslint-config-alloy-5.1.2.tgz#e9950fc8006f1daffc26f82beb57e4f92a578e6b" + integrity sha512-jppzCxNqlhvMYPgfUzvPq4f9fEu070+m3CRIjWdUx/GJLZ6dXHARzMIrIhFuIvzYI5Qo40ht1gunguLnRhIB7A== -eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -2389,85 +2021,89 @@ eslint-import-resolver-node@^0.3.7: is-core-module "^2.13.0" resolve "^1.22.4" -eslint-import-resolver-typescript@^3.4.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.0.tgz#36f93e1eb65a635e688e16cae4bead54552e3bbd" - integrity sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg== +eslint-import-resolver-typescript@^3.6.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz#23dac32efa86a88e2b8232eb244ac499ad636db2" + integrity sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ== dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - fast-glob "^3.3.1" - get-tsconfig "^4.5.0" - is-core-module "^2.11.0" - is-glob "^4.0.3" + "@nolyfill/is-core-module" "1.0.39" + debug "^4.4.0" + get-tsconfig "^4.10.0" + is-bun-module "^2.0.0" + stable-hash "^0.0.5" + tinyglobby "^0.2.13" + unrs-resolver "^1.6.2" -eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== +eslint-module-utils@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz#f76d3220bfb83c057651359295ab5854eaad75ff" + integrity sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw== dependencies: debug "^3.2.7" -eslint-plugin-import@^2.26.0: - version "2.28.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== +eslint-plugin-import@^2.28.1: + version "2.32.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980" + integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA== dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.9" + array.prototype.findlastindex "^1.2.6" + array.prototype.flat "^1.3.3" + array.prototype.flatmap "^1.3.3" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.1" + hasown "^2.0.2" + is-core-module "^2.16.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.1" semver "^6.3.1" - tsconfig-paths "^3.14.2" + string.prototype.trimend "^1.0.9" + tsconfig-paths "^3.15.0" eslint-plugin-react-hooks@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" - integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== - -eslint-plugin-react@^7.30.1: - version "7.33.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" - integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== - dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" + version "4.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== + +eslint-plugin-react@^7.33.2: + version "7.37.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.3" + array.prototype.tosorted "^1.1.4" doctrine "^2.1.0" - es-iterator-helpers "^1.0.12" + es-iterator-helpers "^1.2.1" estraverse "^5.3.0" + hasown "^2.0.2" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" + object.entries "^1.1.9" + object.fromentries "^2.0.8" + object.values "^1.2.1" prop-types "^15.8.1" - resolve "^2.0.0-next.4" + resolve "^2.0.0-next.5" semver "^6.3.1" - string.prototype.matchall "^4.0.8" + string.prototype.matchall "^4.0.12" + string.prototype.repeat "^1.0.0" -eslint-plugin-simple-import-sort@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-7.0.0.tgz#a1dad262f46d2184a90095a60c66fef74727f0f8" - integrity sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw== +eslint-plugin-simple-import-sort@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz#cc4ceaa81ba73252427062705b64321946f61351" + integrity sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw== -eslint-plugin-unused-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520" - integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A== +eslint-plugin-unused-imports@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz#63a98c9ad5f622cd9f830f70bc77739f25ccfe0d" + integrity sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ== dependencies: eslint-rule-composer "^0.3.0" @@ -2476,14 +2112,6 @@ eslint-rule-composer@^0.3.0: resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - eslint-scope@^7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" @@ -2492,23 +2120,24 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.25.0: - version "8.47.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806" - integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q== +eslint@^8.57.1: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "^8.47.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2550,9 +2179,9 @@ espree@^9.6.0, espree@^9.6.1: eslint-visitor-keys "^3.4.1" esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -2563,11 +2192,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -2578,138 +2202,14 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -ethereum-cryptography@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" - integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - -ethereum-cryptography@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" - integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== - dependencies: - "@noble/hashes" "1.2.0" - "@noble/secp256k1" "1.7.1" - "@scure/bip32" "1.1.5" - "@scure/bip39" "1.1.1" - -ethereum-cryptography@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz#18fa7108622e56481157a5cb7c01c0c6a672eb67" - integrity sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug== - dependencies: - "@noble/curves" "1.1.0" - "@noble/hashes" "1.3.1" - "@scure/bip32" "1.3.1" - "@scure/bip39" "1.2.1" - ethereum-multicall@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/ethereum-multicall/-/ethereum-multicall-2.19.0.tgz#28462bf48792bf7bb0b2db1ca546f439b2adab96" - integrity sha512-ECMxdf1ffxBWTCLeAzEGGWUYNdlNq4zXPj/ZPXdaixbx/qZ/gw4ongwpuR5UGy6D5epWDftvFvIAEzmkwGZ1lQ== + version "2.26.0" + resolved "https://registry.yarnpkg.com/ethereum-multicall/-/ethereum-multicall-2.26.0.tgz#92fe9efb6ed1cbccc2baa757a91e4d2287d56ccb" + integrity sha512-7PslfFiHPUrA0zQpMgZdftUBNyVWuHVBwnRtDOr6Eam8O/OwucqP+OHZZDE7qdrWzi4Jrji8IMw2ZUFv/wbs8Q== dependencies: "@ethersproject/providers" "^5.0.10" ethers "^5.0.15" -ethereumjs-util@7.1.5, ethereumjs-util@^7.1.4: - version "7.1.5" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" - integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - -ethers@5.4.4: - version "5.4.4" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.4.4.tgz#35cce530505b84c699da944162195cfb3f894947" - integrity sha512-zaTs8yaDjfb0Zyj8tT6a+/hEkC+kWAA350MWRp6yP5W7NdGcURRPMOpOU+6GtkfxV9wyJEShWesqhE/TjdqpMA== - dependencies: - "@ethersproject/abi" "5.4.0" - "@ethersproject/abstract-provider" "5.4.1" - "@ethersproject/abstract-signer" "5.4.1" - "@ethersproject/address" "5.4.0" - "@ethersproject/base64" "5.4.0" - "@ethersproject/basex" "5.4.0" - "@ethersproject/bignumber" "5.4.1" - "@ethersproject/bytes" "5.4.0" - "@ethersproject/constants" "5.4.0" - "@ethersproject/contracts" "5.4.1" - "@ethersproject/hash" "5.4.0" - "@ethersproject/hdnode" "5.4.0" - "@ethersproject/json-wallets" "5.4.0" - "@ethersproject/keccak256" "5.4.0" - "@ethersproject/logger" "5.4.0" - "@ethersproject/networks" "5.4.2" - "@ethersproject/pbkdf2" "5.4.0" - "@ethersproject/properties" "5.4.0" - "@ethersproject/providers" "5.4.3" - "@ethersproject/random" "5.4.0" - "@ethersproject/rlp" "5.4.0" - "@ethersproject/sha2" "5.4.0" - "@ethersproject/signing-key" "5.4.0" - "@ethersproject/solidity" "5.4.0" - "@ethersproject/strings" "5.4.0" - "@ethersproject/transactions" "5.4.0" - "@ethersproject/units" "5.4.0" - "@ethersproject/wallet" "5.4.0" - "@ethersproject/web" "5.4.0" - "@ethersproject/wordlists" "5.4.0" - -ethers@5.7.2, ethers@^5.0.15, ethers@^5.3.1, ethers@^5.5.3, ethers@^5.6.8, ethers@^5.7.2: - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - ethers@6.12.1: version "6.12.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.1.tgz#517ff6d66d4fd5433e38e903051da3e57c87ff37" @@ -2723,85 +2223,62 @@ ethers@6.12.1: tslib "2.4.0" ws "8.5.0" -ethers@6.6.3: - version "6.6.3" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.6.3.tgz#9bf11d1bd0f18c7c55087d1a52fdc8f3c33c8bab" - integrity sha512-g8wLXeRWSGDD0T+wsL3pvyc3aYnmxEEAwH8LSoDTDRhRsmJeNs9YMXlNU7ax2caO+zHkeI9MkHiz6rwxEjN4Mw== - dependencies: - "@adraffy/ens-normalize" "1.9.2" - "@noble/hashes" "1.1.2" - "@noble/secp256k1" "1.7.1" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.5.0" - -ethjs-util@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -eventemitter3@^5.0.1: +ethers@^5.0.15, ethers@^5.6.8, ethers@^5.7.2: + version "5.8.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.8.0.tgz#97858dc4d4c74afce83ea7562fe9493cedb4d377" + integrity sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg== + dependencies: + "@ethersproject/abi" "5.8.0" + "@ethersproject/abstract-provider" "5.8.0" + "@ethersproject/abstract-signer" "5.8.0" + "@ethersproject/address" "5.8.0" + "@ethersproject/base64" "5.8.0" + "@ethersproject/basex" "5.8.0" + "@ethersproject/bignumber" "5.8.0" + "@ethersproject/bytes" "5.8.0" + "@ethersproject/constants" "5.8.0" + "@ethersproject/contracts" "5.8.0" + "@ethersproject/hash" "5.8.0" + "@ethersproject/hdnode" "5.8.0" + "@ethersproject/json-wallets" "5.8.0" + "@ethersproject/keccak256" "5.8.0" + "@ethersproject/logger" "5.8.0" + "@ethersproject/networks" "5.8.0" + "@ethersproject/pbkdf2" "5.8.0" + "@ethersproject/properties" "5.8.0" + "@ethersproject/providers" "5.8.0" + "@ethersproject/random" "5.8.0" + "@ethersproject/rlp" "5.8.0" + "@ethersproject/sha2" "5.8.0" + "@ethersproject/signing-key" "5.8.0" + "@ethersproject/solidity" "5.8.0" + "@ethersproject/strings" "5.8.0" + "@ethersproject/transactions" "5.8.0" + "@ethersproject/units" "5.8.0" + "@ethersproject/wallet" "5.8.0" + "@ethersproject/web" "5.8.0" + "@ethersproject/wordlists" "5.8.0" + +eventemitter3@5.0.1, eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" - integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== - -evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -execa@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9, fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== +fast-glob@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-stable-stringify@^2.0.0: version "2.1.0" @@ -2813,13 +2290,23 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== dependencies: reusify "^1.0.4" +fdir@^6.1.1, fdir@^6.4.4: + version "6.4.6" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281" + integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -2827,28 +2314,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -find-replace@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" - integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== - dependencies: - array-back "^3.0.1" - -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -2857,105 +2329,75 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +find-up@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-7.0.0.tgz#e8dec1455f74f78d888ad65bf7ca13dd2b4e66fb" + integrity sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g== dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + locate-path "^7.2.0" + path-exists "^5.0.0" + unicorn-magic "^0.1.0" -fmix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/fmix/-/fmix-0.1.0.tgz#c7bbf124dec42c9d191cfb947d0a9778dd986c0c" - integrity sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w== +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - imul "^1.0.0" + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" -follow-redirects@^1.14.0: - version "1.15.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" - integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== -follow-redirects@^1.14.9, follow-redirects@^1.15.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.14.9, follow-redirects@^1.15.6: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== dependencies: - is-callable "^1.1.3" + is-callable "^1.2.7" -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +form-data@^4.0.0, form-data@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" -fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^11.0.0: - version "11.1.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" -functions-have-names@^1.2.2, functions-have-names@^1.2.3: +functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -2965,53 +2407,66 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== +get-east-asian-width@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389" + integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-stream@^6.0.0, get-stream@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" -get-tsconfig@^4.5.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.0.tgz#06ce112a1463e93196aa90320c35df5039147e34" - integrity sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw== +get-tsconfig@^4.10.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.1.tgz#d34c1c01f47d65a606c37aa7a177bc3e56ab4b2e" + integrity sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ== dependencies: resolve-pkg-maps "^1.0.0" -git-raw-commits@^2.0.11: - version "2.0.11" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz#bc3576638071d18655e1cc60d7f524920008d723" - integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== +git-raw-commits@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285" + integrity sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ== dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" + dargs "^8.0.0" + meow "^12.0.1" + split2 "^4.0.0" -glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -3025,18 +2480,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^7.1.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -3049,26 +2492,27 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg== +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== dependencies: - ini "^1.3.4" + ini "4.1.1" globals@^13.19.0: - version "13.21.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -3082,114 +2526,53 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - -hardhat-deploy@0.11.34: - version "0.11.34" - resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.11.34.tgz#61252ebf5dfdda7b0b31298dd5580b0735c05910" - integrity sha512-N6xcwD8LSMV/IyfEr8TfR2YRbOh9Q4QvitR9MKZRTXQmgQiiMGjX+2efMjKgNMxwCVlmpfnE1tyDxOJOOUseLQ== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/contracts" "^5.7.0" - "@ethersproject/providers" "^5.7.2" - "@ethersproject/solidity" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wallet" "^5.7.0" - "@types/qs" "^6.9.7" - axios "^0.21.1" - chalk "^4.1.2" - chokidar "^3.5.2" - debug "^4.3.2" - enquirer "^2.3.6" - ethers "^5.5.3" - form-data "^4.0.0" - fs-extra "^10.0.0" - match-all "^1.2.6" - murmur-128 "^0.2.1" - qs "^6.9.4" - zksync-web3 "^0.14.3" - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - get-intrinsic "^1.1.1" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + es-define-property "^1.0.0" -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== dependencies: - has-symbols "^1.0.2" + dunder-proto "^1.0.0" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" + has-symbols "^1.0.3" -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== @@ -3197,6 +2580,13 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3206,66 +2596,39 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hosted-git-info@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" - integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== - dependencies: - lru-cache "^6.0.0" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== - humanize-duration-ts@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/humanize-duration-ts/-/humanize-duration-ts-2.1.1.tgz#5382b2789f851005a67229eaf031931d71f37ee9" integrity sha512-TibNF2/fkypjAfHdGpWL/dmWUS0G6Qi+3mKyiB6LDCowbMy+PtzbgPTnFMNTOVAJXDau01jYrJ3tFoz5AJSqhA== -husky@^8.0.1: - version "8.0.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" - integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== +husky@^9.1.7: + version "9.1.7" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" + integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== -ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== +import-fresh@^3.2.1, import-fresh@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" -imul@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/imul/-/imul-1.0.1.tgz#9d5867161e8b3de96c2c38d5dc7cb102f35e2ac9" - integrity sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA== +import-meta-resolve@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706" + integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw== imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3274,33 +2637,33 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.4: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== -internal-slot@^1.0.3, internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" - side-channel "^1.0.4" + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" is-arrayish@^0.2.1: version "0.2.1" @@ -3308,64 +2671,78 @@ is-arrayish@^0.2.1: integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-async-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" - integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== dependencies: - has-tostringtag "^1.0.0" + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== dependencies: - has-bigints "^1.0.1" + has-bigints "^1.0.2" -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== dependencies: - binary-extensions "^2.0.0" + call-bound "^1.0.3" + has-tostringtag "^1.0.2" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== +is-bun-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-2.0.0.tgz#4d7859a87c0fcac950c95e666730e745eae8bddd" + integrity sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + semver "^7.7.1" -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: +is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.9.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.13.0, is-core-module@^2.16.0, is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: - has "^1.0.3" + hasown "^2.0.2" -is-date-object@^1.0.1, is-date-object@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-finalizationregistry@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" - integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== dependencies: - call-bind "^1.0.2" + call-bound "^1.0.3" is-fullwidth-code-point@^3.0.0: version "3.0.0" @@ -3377,41 +2754,47 @@ is-fullwidth-code-point@^4.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== +is-fullwidth-code-point@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704" + integrity sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA== + dependencies: + get-east-asian-width "^1.0.0" + is-generator-function@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== - -is-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + has-tostringtag "^1.0.2" is-number@^7.0.0: version "7.0.0" @@ -3428,88 +2811,78 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" -is-set@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== dependencies: - call-bind "^1.0.2" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + call-bound "^1.0.3" -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + has-tostringtag "^1.0.2" -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== dependencies: - has-symbols "^1.0.2" + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== +is-text-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636" + integrity sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw== dependencies: - text-extensions "^1.0.0" + text-extensions "^2.0.0" -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== dependencies: - which-typed-array "^1.1.11" + which-typed-array "^1.1.16" -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== +is-weakref@^1.0.2, is-weakref@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== dependencies: - call-bind "^1.0.2" + call-bound "^1.0.3" -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" isarray@^2.0.5: version "2.0.5" @@ -3521,23 +2894,29 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -iterator.prototype@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.0.tgz#690c88b043d821f783843aaf725d7ac3b62e3b46" - integrity sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw== +isows@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + +iterator.prototype@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" + integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== dependencies: - define-properties "^1.1.4" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - has-tostringtag "^1.0.0" - reflect.getprototypeof "^1.0.3" + define-data-property "^1.1.4" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + get-proto "^1.0.0" + has-symbols "^1.1.0" + set-function-name "^2.0.2" -js-sha3@0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== +jiti@^2.4.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.5.1.tgz#bd099c1c2be1c59bbea4e5adcd127363446759d0" + integrity sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w== -js-sha3@0.8.0, js-sha3@^0.8.0: +js-sha3@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== @@ -3554,6 +2933,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -3581,22 +2965,6 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -3612,19 +2980,12 @@ jsonparse@^1.2.0: object.assign "^4.1.4" object.values "^1.1.6" -keccak@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276" - integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ== +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - readable-stream "^3.6.0" - -kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + json-buffer "3.0.1" levn@^0.4.1: version "0.4.1" @@ -3634,50 +2995,48 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lilconfig@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== +lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@^13.0.3: - version "13.3.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.3.0.tgz#7965d72a8d6a6c932f85e9c13ccf3596782d28a5" - integrity sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ== - dependencies: - chalk "5.3.0" - commander "11.0.0" - debug "4.3.4" - execa "7.2.0" - lilconfig "2.1.0" - listr2 "6.6.1" - micromatch "4.0.5" - pidtree "0.6.0" - string-argv "0.3.2" - yaml "2.3.1" - -listr2@6.6.1: - version "6.6.1" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-6.6.1.tgz#08b2329e7e8ba6298481464937099f4a2cd7f95d" - integrity sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg== - dependencies: - cli-truncate "^3.1.0" +lint-staged@^16.1.5: + version "16.1.5" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-16.1.5.tgz#e102066b2c98157bad03afffb491d2329553e86b" + integrity sha512-uAeQQwByI6dfV7wpt/gVqg+jAPaSp8WwOA8kKC/dv1qw14oGpnpAisY65ibGHUGDUv0rYaZ8CAJZ/1U8hUvC2A== + dependencies: + chalk "^5.5.0" + commander "^14.0.0" + debug "^4.4.1" + lilconfig "^3.1.3" + listr2 "^9.0.1" + micromatch "^4.0.8" + nano-spawn "^1.0.2" + pidtree "^0.6.0" + string-argv "^0.3.2" + yaml "^2.8.1" + +listr2@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-9.0.1.tgz#3cad12d81d998f8024621d9b35c969dba5da4103" + integrity sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g== + dependencies: + cli-truncate "^4.0.0" colorette "^2.0.20" eventemitter3 "^5.0.1" - log-update "^5.0.1" - rfdc "^1.3.0" - wrap-ansi "^8.1.0" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== locate-path@^6.0.0: version "6.0.0" @@ -3686,21 +3045,18 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +locate-path@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" + integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== + dependencies: + p-locate "^6.0.0" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - -lodash.isfunction@^3.0.9: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" - integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== - lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -3741,21 +3097,16 @@ lodash.upperfirst@^4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== -lodash@^4.17.15: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-update@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09" - integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== dependencies: - ansi-escapes "^5.0.0" - cli-cursor "^4.0.0" - slice-ansi "^5.0.0" - strip-ansi "^7.0.1" - wrap-ansi "^8.0.1" + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" loose-envify@^1.4.0: version "1.4.0" @@ -3764,87 +3115,34 @@ loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" - integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: - get-func-name "^2.0.0" + get-func-name "^2.0.1" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== - -map-obj@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - -match-all@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/match-all/-/match-all-1.2.6.tgz#66d276ad6b49655551e63d3a6ee53e8be0566f8d" - integrity sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ== +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -meow@^8.0.0, meow@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +meow@^12.0.1: + version "12.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6" + integrity sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw== merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micro-ftch@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" - integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== - -micromatch@4.0.5, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -3859,20 +3157,10 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== - -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" @@ -3884,179 +3172,117 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -murmur-128@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/murmur-128/-/murmur-128-0.2.1.tgz#a9f6568781d2350ecb1bf80c14968cadbeaa4b4d" - integrity sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg== - dependencies: - encode-utf8 "^1.0.2" - fmix "^0.1.0" - imul "^1.0.0" - -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-gyp-build@^4.2.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" - integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== - -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +nano-spawn@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.2.tgz#9853795681f0e96ef6f39104c2e4347b6ba79bf6" + integrity sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg== -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== +nanospinner@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/nanospinner/-/nanospinner-1.2.2.tgz#5a38f4410b5bf7a41585964bee74d32eab3e040b" + integrity sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA== dependencies: - path-key "^3.0.0" + picocolors "^1.1.1" -npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== - dependencies: - path-key "^4.0.0" +napi-postinstall@^0.3.0: + version "0.3.3" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.3.tgz#93d045c6b576803ead126711d3093995198c6eb9" + integrity sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== +object.assign@^4.1.4, object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" object-keys "^1.1.1" -object.entries@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" - integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== +object.entries@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-object-atoms "^1.1.1" -object.fromentries@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.groupby@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.0.tgz#cb29259cf90f37e7bac6437686c1ea8c916d12a9" - integrity sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.21.2" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.hasown@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" - integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== +object.values@^1.1.6, object.values@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" once@^1.3.0: version "1.4.0" @@ -4065,38 +3291,47 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== dependencies: - mimic-fn "^4.0.0" + mimic-function "^5.0.0" optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" + word-wrap "^1.2.5" -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== dependencies: - p-try "^2.0.0" + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" + +ox@0.8.6: + version "0.8.6" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.8.6.tgz#7dd666216ee8cda2eb2e5fef3fe4cb20dec3dcad" + integrity sha512-eiKcgiVVEGDtEpEdFi1EGoVVI48j6icXHce9nFwCNM7CKG3uoCXKdr4TPhS00Iy1TR2aWSF1ltPD0x/YgqIL9w== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "^1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.0.8" + eventemitter3 "5.0.1" p-limit@^3.0.2: version "3.1.0" @@ -4105,12 +3340,12 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== dependencies: - p-limit "^2.2.0" + yocto-queue "^1.0.0" p-locate@^5.0.0: version "5.0.0" @@ -4119,10 +3354,12 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +p-locate@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" + integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== + dependencies: + p-limit "^4.0.0" parent-module@^1.0.0: version "1.0.1" @@ -4131,7 +3368,7 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^5.0.0: +parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -4146,21 +3383,21 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.0.0, path-key@^3.1.0: +path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -4171,41 +3408,55 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -pbkdf2@^3.0.17: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: +picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pidtree@0.6.0: +picomatch@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-3.0.1.tgz#817033161def55ec9638567a2f3bbc876b3e7516" + integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== + +picomatch@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +pidtree@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.3.1, prettier@^2.7.1: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.0.3, prettier@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== prop-types@^15.8.1: version "15.8.1" @@ -4222,81 +3473,24 @@ proxy-from-env@^1.1.0: integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== - -qs@^6.9.4: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== - dependencies: - side-channel "^1.0.4" + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== redstone-oracles-smartweave-contracts@*: version "1.0.6" @@ -4311,9 +3505,9 @@ redstone-protocol@*, redstone-protocol@^1.0.5: ethers "^5.6.8" redstone-sdk@^1.6.1: - version "1.8.0" - resolved "https://registry.yarnpkg.com/redstone-sdk/-/redstone-sdk-1.8.0.tgz#1a95f7d3f520684422df7c6324d7cd18b140a395" - integrity sha512-665xtGaUZP0/pJr+Akq8jOW+RcSRdWro6tO/jTUf+s+1ctEryWrnGt9+T6l3vVbLHRRvCgh/u9/Mks61SLGRLA== + version "1.8.2" + resolved "https://registry.yarnpkg.com/redstone-sdk/-/redstone-sdk-1.8.2.tgz#39abf332b0bd2b3e935fd58f385f8e2c70d2e2e5" + integrity sha512-kcNt7HwcKLBI3X5EMnB8V1HODiLNVsFEqoVfwToBRFtgTPV8yTcPG7XfUkYiybE8MYSzoM49HNePBwp1liqDbg== dependencies: axios "^0.27.2" ethers "^5.7.2" @@ -4330,31 +3524,31 @@ redstone-utils@^0.1.0: decimal.js "^10.4.3" ethereum-multicall "^2.19.0" -reduce-flatten@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" - integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== - -reflect.getprototypeof@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz#2738fd896fcc3477ffbd4190b40c2458026b6928" - integrity sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.1" - globalthis "^1.0.3" - which-builtin-type "^1.1.3" - -regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - functions-have-names "^1.2.3" +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" require-directory@^2.1.1: version "2.1.1" @@ -4366,63 +3560,56 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-global@1.0.0, resolve-global@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" - integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== - dependencies: - global-dirs "^0.1.1" +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@^1.10.0, resolve@^1.22.4: - version "1.22.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== +resolve@^1.22.4: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== dependencies: - is-core-module "^2.13.0" + is-core-module "^2.16.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -restore-cursor@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" - integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" + onetime "^7.0.0" + signal-exit "^4.1.0" reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== rimraf@^3.0.2: version "3.0.2" @@ -4431,21 +3618,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rlp@^2.2.4: - version "2.2.7" - resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" - integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== - dependencies: - bn.js "^5.2.0" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -4453,73 +3625,79 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-array-concat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060" - integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - has-symbols "^1.0.3" + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex-test@^1.0.0: +safe-push-apply@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" -scrypt-js@3.0.1, scrypt-js@^3.0.0: +scrypt-js@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -"semver@2 || 3 || 4 || 5": - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.5.4, semver@^7.3.4, semver@^7.3.7: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== +semver@^7.5.4, semver@^7.6.0, semver@^7.7.1: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" shebang-command@^2.0.0: version "2.0.0" @@ -4533,19 +3711,50 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== slash@^3.0.0: version "3.0.0" @@ -4560,49 +3769,37 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== +slice-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" + integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== -spdx-license-ids@^3.0.0: - version "3.0.13" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" - integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== +stable-hash@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.5.tgz#94e8837aaeac5b4d0f631d2972adef2924b40269" + integrity sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA== -split2@^3.0.0, split2@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== dependencies: - readable-stream "^3.0.0" + es-errors "^1.3.0" + internal-slot "^1.1.0" -string-argv@0.3.2: +string-argv@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -string-format@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" - integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== - string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -4612,62 +3809,73 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.0, string-width@^5.0.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -string.prototype.matchall@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" - integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" - -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== + dependencies: + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + +string.prototype.matchall@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" + integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + regexp.prototype.flags "^1.5.3" + set-function-name "^2.0.2" + side-channel "^1.1.0" + +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - safe-buffer "~5.2.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" @@ -4676,7 +3884,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: +strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== @@ -4688,42 +3896,11 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - -strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== - dependencies: - is-hex-prefixed "1.0.0" - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -4736,47 +3913,33 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -table-layout@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" - integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== - dependencies: - array-back "^4.0.1" - deep-extend "~0.6.0" - typical "^5.2.0" - wordwrapjs "^4.0.0" - -tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== +text-extensions@^2.0.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34" + integrity sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g== text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -through2@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - "through@>=2.2.7 <3": version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tiny-invariant@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== +tinyexec@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" + integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw== + +tinyglobby@^0.2.13: + version "0.2.14" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" to-regex-range@^5.0.1: version "5.0.1" @@ -4785,49 +3948,15 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +ts-api-utils@^1.0.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== -ts-command-line-args@^2.2.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" - integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== - dependencies: - chalk "^4.1.0" - command-line-args "^5.1.1" - command-line-usage "^6.1.0" - string-format "^2.0.0" - -ts-essentials@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" - integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== - -ts-node@^10.8.1, ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tsconfig-paths@^3.14.2: - version "3.14.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.2" @@ -4839,27 +3968,10 @@ tslib@2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - -tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== +tslib@^2.4.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -4868,130 +3980,112 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-fest@^1.0.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" - integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== - -typechain@^8.1.0: - version "8.3.1" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.3.1.tgz#dccbc839b94877997536c356380eff7325395cfb" - integrity sha512-fA7clol2IP/56yq6vkMTR+4URF1nGjV82Wx6Rf09EsqD4tkzMAvEaqYxVFCavJm/1xaRga/oD55K+4FtuXwQOQ== - dependencies: - "@types/prettier" "^2.1.1" - debug "^4.3.1" - fs-extra "^7.0.0" - glob "7.1.7" - js-sha3 "^0.8.0" - lodash "^4.17.15" - mkdirp "^1.0.4" - prettier "^2.3.1" - ts-command-line-args "^2.2.0" - ts-essentials "^7.0.1" - -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.8" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" - -"typescript@^4.6.4 || ^5.0.0": - version "5.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" - integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== - -typescript@^4.8.2: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - -typical@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" - integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" -typical@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" - integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== +typescript@^5.9.2: + version "5.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" + integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== dependencies: - call-bind "^1.0.2" + call-bound "^1.0.3" has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +undici-types@~7.10.0: + version "7.10.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350" + integrity sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag== -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== + +unrs-resolver@^1.6.2: + version "1.11.1" + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9" + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== + dependencies: + napi-postinstall "^0.3.0" + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" + "@unrs/resolver-binding-android-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-x64" "1.11.1" + "@unrs/resolver-binding-freebsd-x64" "1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" uri-js@^4.2.2: version "4.4.1" @@ -5000,73 +4094,72 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== +viem@2.x: + version "2.33.3" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.33.3.tgz#b69d7ff9edf649d1b7d9218e0225bcadc83a8caa" + integrity sha512-aWDr6i6r3OfNCs0h9IieHFhn7xQJJ8YsuA49+9T5JRyGGAkWhLgcbLq2YMecgwM7HdUZpx1vPugZjsShqNi7Gw== + dependencies: + "@noble/curves" "1.9.2" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + abitype "1.0.8" + isows "1.0.7" + ox "0.8.6" + ws "8.18.2" + +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" -which-builtin-type@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" - integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== dependencies: - function.prototype.name "^1.1.5" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" is-async-function "^2.0.0" - is-date-object "^1.0.5" - is-finalizationregistry "^1.0.2" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" is-generator-function "^1.0.10" - is-regex "^1.1.4" + is-regex "^1.2.1" is-weakref "^1.0.2" isarray "^2.0.5" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" -which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" which@^2.0.1: version "2.0.2" @@ -5075,13 +4168,10 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wordwrapjs@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" - integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== - dependencies: - reduce-flatten "^2.0.0" - typical "^5.2.0" +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== wrap-ansi@^7.0.0: version "7.0.0" @@ -5092,24 +4182,29 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== +wrap-ansi@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e" + integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + +ws@8.18.2: + version "8.18.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" + integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== ws@8.5.0: version "8.5.0" @@ -5121,20 +4216,10 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== - -yargs-parser@^20.2.3: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yaml@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== yargs-parser@^21.1.1: version "21.1.1" @@ -5154,22 +4239,17 @@ yargs@^17.0.0: y18n "^5.0.5" yargs-parser "^21.1.1" -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zksync-web3@^0.14.3: - version "0.14.3" - resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.14.3.tgz#64ac2a16d597464c3fc4ae07447a8007631c57c9" - integrity sha512-hT72th4AnqyLW1d5Jlv8N2B/qhEnl2NePK2A3org7tAa24niem/UAaHMkEvmWI3SF9waYUPtqAtjpf+yvQ9zvQ== +yocto-queue@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.1.tgz#36d7c4739f775b3cbc28e6136e21aa057adec418" + integrity sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg== zod@^3.22.2: - version "3.22.4" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" - integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==