diff --git a/contracts/interfaces/balancer/IBalancerStablePool.sol b/contracts/interfaces/balancer/IBalancerStablePool.sol index 4ed77f8..9b39483 100644 --- a/contracts/interfaces/balancer/IBalancerStablePool.sol +++ b/contracts/interfaces/balancer/IBalancerStablePool.sol @@ -3,6 +3,14 @@ // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; -interface IBalancerStablePool { +interface IBalancerRateProvider { function getRate() external view returns (uint256); } + +interface IBalancerStablePool is IBalancerRateProvider { + function getPoolId() external view returns (bytes32); + + function getVault() external view returns (address); + + function getRateProviders() external view returns (address[] memory); +} diff --git a/contracts/interfaces/balancer/IBalancerWeightedPool.sol b/contracts/interfaces/balancer/IBalancerWeightedPool.sol index 84aa2e1..a5cf77c 100644 --- a/contracts/interfaces/balancer/IBalancerWeightedPool.sol +++ b/contracts/interfaces/balancer/IBalancerWeightedPool.sol @@ -13,4 +13,6 @@ interface IBalancerWeightedPool { function getActualSupply() external view returns (uint256); function getPoolId() external view returns (bytes32); + + function getVault() external view returns (address); } diff --git a/contracts/oracles/balancer/BPTStablePriceFeed.sol b/contracts/oracles/balancer/BPTStablePriceFeed.sol index 4dac73b..6fb318c 100644 --- a/contracts/oracles/balancer/BPTStablePriceFeed.sol +++ b/contracts/oracles/balancer/BPTStablePriceFeed.sol @@ -7,7 +7,8 @@ import {LPPriceFeed} from "../LPPriceFeed.sol"; import {PriceFeedParams} from "../PriceFeedParams.sol"; import {WAD} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol"; import {PriceFeedType} from "@gearbox-protocol/sdk-gov/contracts/PriceFeedType.sol"; -import {IBalancerStablePool} from "../../interfaces/balancer/IBalancerStablePool.sol"; +import {IBalancerStablePool, IBalancerRateProvider} from "../../interfaces/balancer/IBalancerStablePool.sol"; +import {IBalancerVault} from "../../interfaces/balancer/IBalancerVault.sol"; /// @title Balancer stable pool token price feed /// @dev Similarly to Curve stableswap, aggregate function is minimum of underlying tokens prices @@ -15,24 +16,31 @@ contract BPTStablePriceFeed is LPPriceFeed { uint256 public constant override version = 3_00; PriceFeedType public constant override priceFeedType = PriceFeedType.BALANCER_STABLE_LP_ORACLE; + int256 constant TOKEN_RATE_NUMERATOR = 1e18; + uint8 public immutable numAssets; + address public immutable rateProvider0; address public immutable priceFeed0; uint32 public immutable stalenessPeriod0; bool public immutable skipCheck0; + address public immutable rateProvider1; address public immutable priceFeed1; uint32 public immutable stalenessPeriod1; bool public immutable skipCheck1; + address public immutable rateProvider2; address public immutable priceFeed2; uint32 public immutable stalenessPeriod2; bool public immutable skipCheck2; + address public immutable rateProvider3; address public immutable priceFeed3; uint32 public immutable stalenessPeriod3; bool public immutable skipCheck3; + address public immutable rateProvider4; address public immutable priceFeed4; uint32 public immutable stalenessPeriod4; bool public immutable skipCheck4; @@ -47,6 +55,14 @@ contract BPTStablePriceFeed is LPPriceFeed { nonZeroAddress(priceFeeds[0].priceFeed) // U:[BAL-S-2] nonZeroAddress(priceFeeds[1].priceFeed) // U:[BAL-S-2] { + address[5] memory rateProviders = _getRateProviders(_balancerPool); + + rateProvider0 = rateProviders[0]; + rateProvider1 = rateProviders[1]; + rateProvider2 = rateProviders[2]; + rateProvider3 = rateProviders[3]; + rateProvider4 = rateProviders[4]; + priceFeed0 = priceFeeds[0].priceFeed; priceFeed1 = priceFeeds[1].priceFeed; priceFeed2 = priceFeeds[2].priceFeed; @@ -70,28 +86,65 @@ contract BPTStablePriceFeed is LPPriceFeed { _setLimiter(lowerBound); // U:[BAL-S-1] } + function _getRateProviders(address _balancerPool) internal view returns (address[5] memory rateProviders) { + address vault = IBalancerStablePool(_balancerPool).getVault(); + bytes32 poolId = IBalancerStablePool(_balancerPool).getPoolId(); + + (address[] memory tokens,,) = IBalancerVault(vault).getPoolTokens(poolId); + address[] memory _rateProviders = IBalancerStablePool(_balancerPool).getRateProviders(); + + uint256 len = tokens.length; + uint256 k = 0; + for (uint256 i; i < len;) { + if (tokens[i] != _balancerPool) { + rateProviders[k] = _rateProviders[i]; + unchecked { + ++k; + } + } + + unchecked { + ++i; + } + } + } + function getAggregatePrice() public view override returns (int256 answer) { - answer = _getValidatedPrice(priceFeed0, stalenessPeriod0, skipCheck0); // U:[BAL-S-2] + answer = _getAnswerOverTokenRate(rateProvider0, priceFeed0, stalenessPeriod0, skipCheck0); // U:[BAL-S-2] - int256 answerA = _getValidatedPrice(priceFeed1, stalenessPeriod1, skipCheck1); + int256 answerA = _getAnswerOverTokenRate(rateProvider1, priceFeed1, stalenessPeriod1, skipCheck1); if (answerA < answer) answer = answerA; // U:[BAL-S-2] if (numAssets > 2) { - answerA = _getValidatedPrice(priceFeed2, stalenessPeriod2, skipCheck2); + answerA = _getAnswerOverTokenRate(rateProvider2, priceFeed2, stalenessPeriod2, skipCheck2); if (answerA < answer) answer = answerA; // U:[BAL-S-2] if (numAssets > 3) { - answerA = _getValidatedPrice(priceFeed3, stalenessPeriod3, skipCheck3); + answerA = _getAnswerOverTokenRate(rateProvider3, priceFeed3, stalenessPeriod3, skipCheck3); if (answerA < answer) answer = answerA; // U:[BAL-S-2] if (numAssets > 4) { - answerA = _getValidatedPrice(priceFeed4, stalenessPeriod4, skipCheck4); + answerA = _getAnswerOverTokenRate(rateProvider4, priceFeed4, stalenessPeriod4, skipCheck4); if (answerA < answer) answer = answerA; // U:[BAL-S-2] } } } } + function _getAnswerOverTokenRate(address rateProvider, address priceFeed, uint32 stalenessPeriod, bool skipCheck) + internal + view + returns (int256 answer) + { + answer = _getValidatedPrice(priceFeed, stalenessPeriod, skipCheck); + + if (rateProvider != address(0)) { + answer = answer * TOKEN_RATE_NUMERATOR / int256(IBalancerRateProvider(rateProvider).getRate()); + } + + return answer; + } + function getLPExchangeRate() public view override returns (uint256) { return IBalancerStablePool(lpToken).getRate(); // U:[BAL-S-1] } diff --git a/contracts/test/live/balancer/BPTStablePriceFeed.eq.t.sol b/contracts/test/live/balancer/BPTStablePriceFeed.eq.t.sol new file mode 100644 index 0000000..5e1da46 --- /dev/null +++ b/contracts/test/live/balancer/BPTStablePriceFeed.eq.t.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: UNLICENSED +// 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 "@openzeppelin/contracts/utils/Strings.sol"; +import {IPriceFeed} from "@gearbox-protocol/core-v2/contracts/interfaces/IPriceFeed.sol"; +import {IBalancerWeightedPool} from "../../../interfaces/balancer/IBalancerWeightedPool.sol"; +import {IBalancerVault} from "../../../interfaces/balancer/IBalancerVault.sol"; + +import {AddressProviderV3ACLMock} from + "@gearbox-protocol/core-v3/contracts/test/mocks/core/AddressProviderV3ACLMock.sol"; +import {SupportedContracts} from "@gearbox-protocol/sdk-gov/contracts/SupportedContracts.sol"; +import {TokenType} from "@gearbox-protocol/sdk-gov/contracts/Tokens.sol"; +import {Tokens, TokensTestSuite} from "@gearbox-protocol/core-v3/contracts/test/suites/TokensTestSuite.sol"; +import {NetworkDetector} from "@gearbox-protocol/sdk-gov/contracts/NetworkDetector.sol"; +import {PriceFeedType} from "@gearbox-protocol/sdk-gov/contracts/PriceFeedType.sol"; +import {PriceFeedConfig} from "@gearbox-protocol/core-v3/contracts/test/interfaces/ICreditConfig.sol"; +import {PriceFeedDeployer} from "../../suites/PriceFeedDeployer.sol"; + +import {Test} from "forge-std/Test.sol"; + +contract BPTStablePriceFeed is Test { + PriceFeedDeployer public pfd; + uint256 chainId; + + modifier liveTestOnly() { + if (chainId != 1337 && chainId != 31337) { + _; + } + } + + function setUp() public { + NetworkDetector nd = new NetworkDetector(); + chainId = nd.chainId(); + + if (chainId != 1337 && chainId != 31337) { + TokensTestSuite tokenTestSuite = new TokensTestSuite(); + + AddressProviderV3ACLMock addressProvider = new AddressProviderV3ACLMock(); + SupportedContracts sc = new SupportedContracts(chainId); + + pfd = new PriceFeedDeployer(chainId, address(addressProvider), tokenTestSuite, sc); + } + } + + function test_live_BAL_EQ_01_Balancer_BPT_stable_pf_returns_price_equal_or_lower() public liveTestOnly { + uint256 len = pfd.priceFeedConfigLength(); + + for (uint256 i; i < len; ++i) { + (address token, address priceFeed,,) = pfd.priceFeedConfig(i); + + PriceFeedType pft; + + try IPriceFeed(priceFeed).priceFeedType() returns (PriceFeedType _pft) { + pft = _pft; + } catch { + pft = PriceFeedType.CHAINLINK_ORACLE; + } + + if ( + pft != PriceFeedType.BALANCER_STABLE_LP_ORACLE + || pfd.tokenTestSuite().tokenTypes(pfd.tokenTestSuite().tokenIndexes(token)) + != TokenType.BALANCER_LP_TOKEN + ) continue; + + (, int256 pfPrice,,,) = IPriceFeed(priceFeed).latestRoundData(); + + bytes32 poolId = IBalancerWeightedPool(token).getPoolId(); + address vault = IBalancerWeightedPool(token).getVault(); + + (address[] memory tokens, uint256[] memory balances,) = IBalancerVault(vault).getPoolTokens(poolId); + + int256 computedPrice = 0; + + for (uint256 j = 0; j < tokens.length; ++j) { + if (tokens[j] == token) continue; + + (, int256 assetPrice,,,) = IPriceFeed(pfd.priceFeeds(tokens[j])).latestRoundData(); + + computedPrice += assetPrice * int256(balances[j]) / int256(10 ** ERC20(tokens[j]).decimals()); + } + + uint256 supply; + + try IBalancerWeightedPool(token).getActualSupply() returns (uint256 _supply) { + supply = _supply; + } catch { + supply = ERC20(token).totalSupply(); + } + + computedPrice = computedPrice * 1e18 / int256(supply); + + assertLe(pfPrice, computedPrice, "PF price higher than computed based on value of pool assets"); + } + } +} diff --git a/contracts/test/mocks/balancer/BalancerRateProviderMock.sol b/contracts/test/mocks/balancer/BalancerRateProviderMock.sol new file mode 100644 index 0000000..6b8abb4 --- /dev/null +++ b/contracts/test/mocks/balancer/BalancerRateProviderMock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +// Gearbox Protocol. Generalized leverage for DeFi protocols +// (c) Gearbox Foundation, 2023. +pragma solidity ^0.8.17; + +import {IBalancerRateProvider} from "../../../interfaces/balancer/IBalancerStablePool.sol"; + +contract BalancerRateProviderMock is IBalancerRateProvider { + uint256 public override getRate; + + constructor(uint256 rate) { + getRate = rate; + } +} diff --git a/contracts/test/mocks/balancer/BalancerStablePoolMock.sol b/contracts/test/mocks/balancer/BalancerStablePoolMock.sol index 96e2ca2..2e1ce36 100644 --- a/contracts/test/mocks/balancer/BalancerStablePoolMock.sol +++ b/contracts/test/mocks/balancer/BalancerStablePoolMock.sol @@ -3,12 +3,38 @@ // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; +import {BalancerRateProviderMock} from "./BalancerRateProviderMock.sol"; import {IBalancerStablePool} from "../../../interfaces/balancer/IBalancerStablePool.sol"; contract BalancerStablePoolMock is IBalancerStablePool { uint256 public override getRate; + mapping(address => uint256) public getTokenRate; + + address[] public rateProviders; + + address public getVault; + bytes32 public getPoolId; + + constructor(address balancerVault, bytes32 poolId) { + getVault = balancerVault; + getPoolId = poolId; + } + function hackRate(uint256 newRate) external { getRate = newRate; } + + function getRateProviders() external view returns (address[] memory) { + return rateProviders; + } + + function hackRateProviders(uint256[] memory rates) external { + rateProviders = new address[](0); + + for (uint256 i = 0; i < rates.length; ++i) { + address rateProvider = address(new BalancerRateProviderMock(rates[i])); + rateProviders.push(rateProvider); + } + } } diff --git a/contracts/test/mocks/balancer/BalancerWeightedPoolMock.sol b/contracts/test/mocks/balancer/BalancerWeightedPoolMock.sol index 3fc5151..4216dbe 100644 --- a/contracts/test/mocks/balancer/BalancerWeightedPoolMock.sol +++ b/contracts/test/mocks/balancer/BalancerWeightedPoolMock.sol @@ -11,12 +11,14 @@ contract BalancerWeightedPoolMock is IBalancerWeightedPool { uint256 public immutable override totalSupply; bool public immutable actualSupplyEnabled; uint256[] _weights; + address public getVault; - constructor(bytes32 poolId, uint256 supply, bool enableActualSupply, uint256[] memory weights) { + constructor(bytes32 poolId, uint256 supply, bool enableActualSupply, uint256[] memory weights, address vault) { getPoolId = poolId; totalSupply = supply; _weights = weights; actualSupplyEnabled = enableActualSupply; + getVault = vault; } function getNormalizedWeights() external view override returns (uint256[] memory) { diff --git a/contracts/test/unit/balancer/BPTStablePriceFeed.unit.t.sol b/contracts/test/unit/balancer/BPTStablePriceFeed.unit.t.sol index 15a96fc..c5b714a 100644 --- a/contracts/test/unit/balancer/BPTStablePriceFeed.unit.t.sol +++ b/contracts/test/unit/balancer/BPTStablePriceFeed.unit.t.sol @@ -6,9 +6,10 @@ pragma solidity ^0.8.17; import {PriceFeedUnitTestHelper} from "../PriceFeedUnitTestHelper.sol"; import {BalancerStablePoolMock} from "../../mocks/balancer/BalancerStablePoolMock.sol"; +import {BalancerVaultMock, PoolToken} from "../../mocks/balancer/BalancerVaultMock.sol"; import {PriceFeedMock} from "@gearbox-protocol/core-v3/contracts/test/mocks/oracles/PriceFeedMock.sol"; -import {IBalancerStablePool} from "../../../interfaces/balancer/IBalancerStablePool.sol"; +import {IBalancerStablePool, IBalancerRateProvider} from "../../../interfaces/balancer/IBalancerStablePool.sol"; import {PriceFeedParams} from "../../../oracles/PriceFeedParams.sol"; import {BPTStablePriceFeed} from "../../../oracles/balancer/BPTStablePriceFeed.sol"; @@ -17,29 +18,31 @@ import {ZeroAddressException} from "@gearbox-protocol/core-v3/contracts/interfac contract BPTStablePriceFeedUnitTest is PriceFeedUnitTestHelper { BPTStablePriceFeed priceFeed; BalancerStablePoolMock balancerPool; + BalancerVaultMock balancerVault; PriceFeedMock[5] underlyingPriceFeeds; function setUp() public { _setUp(); - balancerPool = new BalancerStablePoolMock(); + balancerVault = new BalancerVaultMock(); + balancerPool = new BalancerStablePoolMock(address(balancerVault), bytes32(uint256(1))); balancerPool.hackRate(1.03 ether); + uint256[] memory rates = new uint256[](5); + for (uint256 i; i < 5; ++i) { underlyingPriceFeeds[i] = new PriceFeedMock(int256(1e6 * (100 - i)), 8); + rates[i] = 1e18 * (100 + i) / 100; } + + balancerPool.hackRateProviders(rates); } /// @notice U:[BAL-S-1]: LP-related functionality works as expected function test_U_BAL_S_01_lp_related_functiontionality_works_as_expected() public { vm.expectRevert(ZeroAddressException.selector); - new BPTStablePriceFeed( - address(addressProvider), - 1.02 ether, - address(0), - _getUnderlyingPriceFeeds(5) - ); + new BPTStablePriceFeed(address(addressProvider), 1.02 ether, address(0), _getUnderlyingPriceFeeds(5)); priceFeed = _newBalancerPriceFeed(5, 1.02 ether); @@ -47,7 +50,7 @@ contract BPTStablePriceFeedUnitTest is PriceFeedUnitTestHelper { assertEq(priceFeed.lpContract(), address(balancerPool), "Incorrect lpToken"); assertEq(priceFeed.lowerBound(), 1.02 ether, "Incorrect lower bound"); - vm.expectCall(address(balancerPool), abi.encodeCall(IBalancerStablePool.getRate, ())); + vm.expectCall(address(balancerPool), abi.encodeCall(IBalancerRateProvider.getRate, ())); assertEq(priceFeed.getLPExchangeRate(), 1.03 ether, "Incorrect getLPExchangeRate"); assertEq(priceFeed.getScale(), 1 ether, "Incorrect getScale"); } @@ -57,7 +60,9 @@ contract BPTStablePriceFeedUnitTest is PriceFeedUnitTestHelper { for (uint256 numFeeds; numFeeds <= 5; ++numFeeds) { if (numFeeds < 2) { vm.expectRevert(ZeroAddressException.selector); - _newBalancerPriceFeed(numFeeds, 1.02 ether); + new BPTStablePriceFeed( + address(addressProvider), 1.02 ether, address(balancerPool), _getUnderlyingPriceFeeds(numFeeds) + ); continue; } @@ -65,7 +70,7 @@ contract BPTStablePriceFeedUnitTest is PriceFeedUnitTestHelper { assertEq(priceFeed.numAssets(), numFeeds, "Incorrect numAssets"); int256 answer = priceFeed.getAggregatePrice(); - assertEq(answer, int256(1e6 * (101 - numFeeds)), "Incorrect answer"); + assertEq(answer, int256(1e8 * (101 - numFeeds) / (99 + numFeeds)), "Incorrect answer"); } } @@ -74,11 +79,19 @@ contract BPTStablePriceFeedUnitTest is PriceFeedUnitTestHelper { // ------- // function _newBalancerPriceFeed(uint256 numFeeds, uint256 lowerBound) internal returns (BPTStablePriceFeed) { + uint256[] memory rates = new uint256[](numFeeds); + PoolToken[] memory poolTokens = new PoolToken[](numFeeds); + + for (uint256 i = 0; i < numFeeds; ++i) { + rates[i] = 1e18 * (100 + i) / 100; + poolTokens[i] = PoolToken({token: makeAddr(string(abi.encodePacked("TOKEN", i))), balance: 1e18}); + } + + balancerPool.hackRateProviders(rates); + balancerVault.hackPoolTokens(bytes32(uint256(1)), poolTokens); + return new BPTStablePriceFeed( - address(addressProvider), - lowerBound, - address(balancerPool), - _getUnderlyingPriceFeeds(numFeeds) + address(addressProvider), lowerBound, address(balancerPool), _getUnderlyingPriceFeeds(numFeeds) ); } diff --git a/contracts/test/unit/balancer/BPTWeightedPriceFeed.unit.t.sol b/contracts/test/unit/balancer/BPTWeightedPriceFeed.unit.t.sol index 3ddb199..e1ff9a7 100644 --- a/contracts/test/unit/balancer/BPTWeightedPriceFeed.unit.t.sol +++ b/contracts/test/unit/balancer/BPTWeightedPriceFeed.unit.t.sol @@ -29,9 +29,7 @@ contract BPTWeightedPriceFeedUnitTest is PriceFeedUnitTestHelper { _setUp(); for (uint256 i; i < 8; ++i) { underlyings[i] = new ERC20Mock( - string.concat("Test Token ", vm.toString(i)), - string.concat("TEST", vm.toString(i)), - uint8(18 - i) + string.concat("Test Token ", vm.toString(i)), string.concat("TEST", vm.toString(i)), uint8(18 - i) ); underlyingPriceFeeds[i] = new PriceFeedMock(int256(1e8 * 4 ** i), 8); } @@ -43,20 +41,12 @@ contract BPTWeightedPriceFeedUnitTest is PriceFeedUnitTestHelper { vm.expectRevert(ZeroAddressException.selector); new BPTWeightedPriceFeedHarness( - address(addressProvider), - 1.02 ether, - address(0), - address(balancerPool), - _getUnderlyingPriceFeeds(8) + address(addressProvider), 1.02 ether, address(0), address(balancerPool), _getUnderlyingPriceFeeds(8) ); vm.expectRevert(ZeroAddressException.selector); new BPTWeightedPriceFeedHarness( - address(addressProvider), - 1.02 ether, - address(balancerVault), - address(0), - _getUnderlyingPriceFeeds(8) + address(addressProvider), 1.02 ether, address(balancerVault), address(0), _getUnderlyingPriceFeeds(8) ); priceFeed = _newBalancerPriceFeed(8, 1.02 ether); @@ -99,7 +89,7 @@ contract BPTWeightedPriceFeedUnitTest is PriceFeedUnitTestHelper { weights[2] = 0.5 ether; // total supply of the pool is 1 - balancerPool = new BalancerWeightedPoolMock("TEST_POOL", 1 ether, false, weights); + balancerPool = new BalancerWeightedPoolMock("TEST_POOL", 1 ether, false, weights, address(0)); // token balances are 1, 0.5 and 0.25 PoolToken[] memory poolTokens = new PoolToken[](3); @@ -137,7 +127,7 @@ contract BPTWeightedPriceFeedUnitTest is PriceFeedUnitTestHelper { weights[2] = 0.2 ether; // total supply of the pool is 1 - balancerPool = new BalancerWeightedPoolMock("TEST_POOL", 1 ether, false, weights); + balancerPool = new BalancerWeightedPoolMock("TEST_POOL", 1 ether, false, weights, address(0)); // token balances are 1, 0.5 and 0.25 PoolToken[] memory poolTokens = new PoolToken[](3); @@ -177,7 +167,9 @@ contract BPTWeightedPriceFeedUnitTest is PriceFeedUnitTestHelper { function _setupBalancerMocks(uint256 numAssets, uint256 scaledBalance) internal { balancerVault = new BalancerVaultMock(); - balancerPool = new BalancerWeightedPoolMock("TEST_POOL", 1 ether, false, _getNormalizedWeights(numAssets)); + balancerPool = new BalancerWeightedPoolMock( + "TEST_POOL", 1 ether, false, _getNormalizedWeights(numAssets), address(balancerVault) + ); balancerVault.hackPoolTokens("TEST_POOL", _getPoolTokens(numAssets, scaledBalance)); } diff --git a/package.json b/package.json index 4cc6370..15124eb 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@gearbox-protocol/core-v3": "^1.47.1", "@gearbox-protocol/eslint-config": "^1.6.1", "@gearbox-protocol/prettier-config": "^1.5.0", - "@gearbox-protocol/sdk-gov": "^1.31.0", + "@gearbox-protocol/sdk-gov": "^1.37.4", "@openzeppelin/contracts": "4.9.3", "@redstone-finance/evm-connector": "0.2.5", "@typechain/ethers-v5": "^10.1.0", diff --git a/yarn.lock b/yarn.lock index 89232eb..adc27ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1329,10 +1329,10 @@ resolved "https://registry.yarnpkg.com/@gearbox-protocol/prettier-config/-/prettier-config-1.5.0.tgz#4df8e9fd2305fee6ab8c1417a02e31343836932a" integrity sha512-FUoprSsBdZyBjgxXCKL6mTkbeUJytaLzPJqIOoQpDmBRTX0seCc2o5I9PI9tySoRIlNnd/XXnKCXq1xHDEGbxw== -"@gearbox-protocol/sdk-gov@^1.31.0": - version "1.31.0" - resolved "https://registry.yarnpkg.com/@gearbox-protocol/sdk-gov/-/sdk-gov-1.31.0.tgz#1cc83ee35f9ed2da832ca1c95aa8307ed44aa7c8" - integrity sha512-tDEwSx+bW8Bi1tj93Ujw0ZUuTi6Cw/dHF1dFlbLTtFwsdG2hDuCPGOYdLLJUsirHbY69p3ztUXmjm22492W2VA== +"@gearbox-protocol/sdk-gov@^1.37.4": + version "1.37.4" + resolved "https://registry.yarnpkg.com/@gearbox-protocol/sdk-gov/-/sdk-gov-1.37.4.tgz#fc214f109bf034b762abae8b3789dfaed7de32ba" + integrity sha512-IiJvP/F8Hlqi5sOH38Dm/9nSAiJ8WwnpZVc58IWLSXX7zRsCpBQ8r2Os6jXnB4+x48N6d5ml8Jcbmz+rJTd4Wg== dependencies: "@types/yaml" "^1.9.7" add "^2.0.6"