diff --git a/contracts/Importer.sol b/contracts/Importer.sol index 2b7880155..d0fbe65d7 100644 --- a/contracts/Importer.sol +++ b/contracts/Importer.sol @@ -43,6 +43,7 @@ import "@yield-protocol/yieldspace-tv/src/oracle/PoolOracle.sol"; import "@yield-protocol/utils-v2/src/utils/Timelock.sol"; import "@yield-protocol/utils-v2/src/utils/EmergencyBrake.sol"; import "@yield-protocol/utils-v2/src/utils/Assert.sol"; +import "@yield-protocol/utils-v2/src/token/ERC20RewardsWrapper.sol"; import "@yield-protocol/strategy-v2/src/Strategy.sol"; import "@yield-protocol/yvarb/contracts/YieldStEthLever.sol"; import "@yield-protocol/yvarb/contracts/YieldNotionalLever.sol"; \ No newline at end of file diff --git a/package.json b/package.json index 3234a18ac..aa38f6742 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@typechain/hardhat": "^6.0.0", "@types/mocha": "^8.0.0", "@yield-protocol/strategy-v2": "2.0.3", - "@yield-protocol/utils-v2": "2.6.11", + "@yield-protocol/utils-v2": "2.6.15", "@yield-protocol/vault-v2": "0.18.12", "@yield-protocol/yieldspace-tv": "0.1.10", "chai": "4.2.0", diff --git a/scripts/fragments/emergency/sendTokensProposal.ts b/scripts/fragments/emergency/sendTokensProposal.ts deleted file mode 100644 index a687c5af1..000000000 --- a/scripts/fragments/emergency/sendTokensProposal.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @dev This script transfers specified tokens from the timelock to destination - */ - -import { BigNumber } from 'ethers' -import { ERC20, ERC20__factory, Timelock } from '../../../typechain' -import { indent } from '../../../shared/helpers' - -export const sendTokensProposal = async ( - timelock: Timelock, - data: Array<[string, string, BigNumber]>, // [token address, destination address, amount] - nesting: number = 0 -): Promise> => { - console.log() - console.log(indent(nesting, `SEND_TOKENS`)) - // Build the proposal - const proposal: Array<{ target: string; data: string }> = [] - - let token: ERC20 | undefined - - for (const [tokenAddr, destAddr, amount] of data) { - if (tokenAddr !== token?.address) { - token = ERC20__factory.connect(tokenAddr, timelock.signer) - } - - proposal.push({ - target: token.address, - data: token.interface.encodeFunctionData('transfer', [destAddr, amount]), - }) - - console.log(indent(nesting, `Transferring ${amount.toString()} of ${token.address} to ${destAddr}`)) - } - - return proposal -} diff --git a/scripts/fragments/strategies/addEthRewards.ts b/scripts/fragments/strategies/addEthRewards.ts deleted file mode 100644 index 74ffa01d3..000000000 --- a/scripts/fragments/strategies/addEthRewards.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @dev This script calls setRewards and setRewardsToken on strategies - * create addEthRewards.ts for each strategy in which we iterate through the strategiesData: - * - get strategy address from strategies map (maybe?) - * - create proposal to setRewards and setRewardsToken - */ - -import { Strategy__factory } from '../../../typechain' -import { indent } from '../../../shared/helpers' - -export const addEthRewards = async ( - ownerAcc: any, - strategies: Map, - strategiesData: Array<[string, string, string, number, number, number]>, - nesting: number = 0 -): Promise> => { - console.log() - console.log(indent(nesting, `ADD_ETH_REWARDS`)) - const proposal: Array<{ target: string; data: string }> = [] - - for (let [strategyId, rewardsAddress, start, stop, rate] of strategiesData) { - const strategy = Strategy__factory.connect(strategies.getOrThrow(strategyId)!, ownerAcc) - - proposal.push({ - target: strategy.address, - data: strategy.interface.encodeFunctionData('setRewardsToken', [rewardsAddress]), - }) - console.log(indent(nesting, `strategy(${strategyId}).setRewardsAddress(${rewardsAddress})`)) - proposal.push({ - target: strategy.address, - data: strategy.interface.encodeFunctionData('setRewards', [start, stop, rate]), - }) - console.log(indent(nesting, `strategy(${strategyId}).setRewards(${start}, ${stop}, ${rate})`)) - } - - return proposal -} diff --git a/scripts/fragments/strategies/addRewardsPlan.ts b/scripts/fragments/strategies/addRewardsPlan.ts new file mode 100644 index 000000000..1a71adeaf --- /dev/null +++ b/scripts/fragments/strategies/addRewardsPlan.ts @@ -0,0 +1,30 @@ +/** + * @dev This script adds a rewards plan to a strategy + */ + +import { Strategy } from '../../../typechain' +import { indent } from '../../../shared/helpers' +import { RewardsPlan } from '../../governance/confTypes' + +export const addRewardsPlan = async ( + strategy: Strategy, + rewardsPlan: RewardsPlan, + nesting: number = 0 +): Promise> => { + console.log() + console.log(indent(nesting, `ADD_REWARDS_PLAN`)) + const proposal: Array<{ target: string; data: string }> = [] + + proposal.push({ + target: strategy.address, + data: strategy.interface.encodeFunctionData('setRewards', [rewardsPlan.start, rewardsPlan.stop, rewardsPlan.rate]), + }) + console.log( + indent( + nesting, + `strategy(${await strategy.symbol()}).setRewards(${rewardsPlan.start}, ${rewardsPlan.stop}, ${rewardsPlan.rate})` + ) + ) + + return proposal +} diff --git a/scripts/fragments/strategies/mintRewardsToken.ts b/scripts/fragments/strategies/mintRewardsToken.ts new file mode 100644 index 000000000..f903360fe --- /dev/null +++ b/scripts/fragments/strategies/mintRewardsToken.ts @@ -0,0 +1,29 @@ +/** + * @dev This script mints rewards tokens on strategies using the rewards wrapper. + */ + +import { BigNumber } from 'ethers' +import { Strategy, ERC20RewardsWrapper__factory } from '../../../typechain' +import { indent } from '../../../shared/helpers' + +export const mintRewardsToken = async ( + strategy: Strategy, + amount: BigNumber, + nesting: number = 0 +): Promise> => { + console.log() + console.log(indent(nesting, `MINT_REWARDS_TOKEN`)) + const proposal: Array<{ target: string; data: string }> = [] + + const wrapper = ERC20RewardsWrapper__factory.connect(await strategy.rewardsToken(), strategy.signer) + + proposal.push({ + target: wrapper.address, + data: wrapper.interface.encodeFunctionData('mint', [strategy.address, amount]), + }) + console.log( + indent(nesting, `wrapper(${await wrapper.symbol()}).mint(${await strategy.symbol()}, ${amount.toString()})`) + ) + + return proposal +} diff --git a/scripts/fragments/strategies/orchestrateRewardsWrapper.ts b/scripts/fragments/strategies/orchestrateRewardsWrapper.ts new file mode 100644 index 000000000..e5164fa1f --- /dev/null +++ b/scripts/fragments/strategies/orchestrateRewardsWrapper.ts @@ -0,0 +1,38 @@ +/** + * @dev This script orchestrates a rewards wrapper. + */ + +import { Timelock, ERC20RewardsWrapper, AccessControl__factory } from '../../../typechain' +import { revokeRoot } from '../permissions/revokeRoot' +import { indent, id } from '../../../shared/helpers' + +export const orchestrateRewardsWrapper = async ( + deployer: string, + timelock: Timelock, + wrapper: ERC20RewardsWrapper, + nesting: number = 0 +): Promise> => { + console.log() + console.log(indent(nesting, `ORCHESTRATE_REWARDS_WRAPPER`)) + let proposal: Array<{ target: string; data: string }> = [] + + proposal.push({ + target: wrapper.address, + data: wrapper.interface.encodeFunctionData('grantRoles', [ + [ + id(wrapper.interface, 'set(address)'), + id(wrapper.interface, 'skim(address,uint256)'), + id(wrapper.interface, 'mint(address,uint256)'), + ], + timelock.address, + ]), + }) + console.log(indent(nesting, `rewards(${await wrapper.symbol()}).grantRoles(gov, timelock)`)) + + // Revoke ROOT from the deployer + proposal = proposal.concat( + await revokeRoot(AccessControl__factory.connect(wrapper.address, wrapper.signer), deployer, nesting + 1) + ) + + return proposal +} diff --git a/scripts/fragments/strategies/setRewardsToken.ts b/scripts/fragments/strategies/setRewardsToken.ts new file mode 100644 index 000000000..a4e63f9f6 --- /dev/null +++ b/scripts/fragments/strategies/setRewardsToken.ts @@ -0,0 +1,24 @@ +/** + * @dev This script sets the rewards token on strategies. It can only be called once per strategy. + */ + +import { Strategy } from '../../../typechain' +import { indent } from '../../../shared/helpers' + +export const setRewardsToken = async ( + strategy: Strategy, + rewardsTokenAddress: string, + nesting: number = 0 +): Promise> => { + console.log() + console.log(indent(nesting, `SET_REWARDS_TOKEN`)) + const proposal: Array<{ target: string; data: string }> = [] + + proposal.push({ + target: strategy.address, + data: strategy.interface.encodeFunctionData('setRewardsToken', [rewardsTokenAddress]), + }) + console.log(indent(nesting, `strategy(${await strategy.symbol()}).setRewardsAddress(${rewardsTokenAddress})`)) + + return proposal +} diff --git a/scripts/fragments/strategies/setRewardsUnderlying.ts b/scripts/fragments/strategies/setRewardsUnderlying.ts new file mode 100644 index 000000000..2ce3ccb28 --- /dev/null +++ b/scripts/fragments/strategies/setRewardsUnderlying.ts @@ -0,0 +1,24 @@ +/** + * @dev This script sets the underlying token on rewards wrappers. + */ + +import { ERC20RewardsWrapper } from '../../../typechain' +import { indent } from '../../../shared/helpers' + +export const setRewardsUnderlying = async ( + wrapper: ERC20RewardsWrapper, + underlyingAddress: string, + nesting: number = 0 +): Promise> => { + console.log() + console.log(indent(nesting, `SET_REWARDS_UNDERLYING`)) + const proposal: Array<{ target: string; data: string }> = [] + + proposal.push({ + target: wrapper.address, + data: wrapper.interface.encodeFunctionData('set', [underlyingAddress]), + }) + console.log(indent(nesting, `wrapper(${await wrapper.symbol()}).set(${underlyingAddress})`)) + + return proposal +} diff --git a/scripts/fragments/utils/sendTokens.ts b/scripts/fragments/utils/sendTokens.ts new file mode 100644 index 000000000..5dab61dff --- /dev/null +++ b/scripts/fragments/utils/sendTokens.ts @@ -0,0 +1,31 @@ +/** + * @dev This script transfers specified tokens from the timelock to destination + */ + +import { ERC20, ERC20__factory, Timelock } from '../../../typechain' +import { indent } from '../../../shared/helpers' +import { Transfer } from '../../governance/confTypes' + +export const sendTokens = async ( + timelock: Timelock, + transfer: Transfer, + nesting: number = 0 +): Promise> => { + console.log() + console.log(indent(nesting, `SEND_TOKENS`)) + // Build the proposal + const proposal: Array<{ target: string; data: string }> = [] + + let token: ERC20 | undefined + + token = ERC20__factory.connect(transfer.token.address, timelock.signer) + + proposal.push({ + target: token.address, + data: token.interface.encodeFunctionData('transfer', [transfer.receiver, transfer.amount]), + }) + + console.log(indent(nesting, `Transferring ${transfer.amount} of ${token.address} to ${token.receiver}`)) + + return proposal +} diff --git a/scripts/governance/add/addRewards/addEthRewards/addEthRewards.mainnet.config.ts b/scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.mainnet.config.ts similarity index 100% rename from scripts/governance/add/addRewards/addEthRewards/addEthRewards.mainnet.config.ts rename to scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.mainnet.config.ts diff --git a/scripts/governance/add/addRewards/addEthRewards/addEthRewards.sh b/scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.sh similarity index 100% rename from scripts/governance/add/addRewards/addEthRewards/addEthRewards.sh rename to scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.sh diff --git a/scripts/governance/add/addRewards/addEthRewards/addEthRewards.ts b/scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.ts similarity index 97% rename from scripts/governance/add/addRewards/addEthRewards/addEthRewards.ts rename to scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.ts index 2ea2322c2..54725abb4 100644 --- a/scripts/governance/add/addRewards/addEthRewards/addEthRewards.ts +++ b/scripts/governance/add/addRewards/addEthRewardsV1/addEthRewards.ts @@ -1,5 +1,5 @@ import { getOwnerOrImpersonate, propose } from '../../../../../shared/helpers' -import { addEthRewardsProposal } from '../../../../fragments/strategies/addEthRewards' +import { addEthRewardsProposal } from '../../../../fragments/strategies/addRewardsPlan' import { Timelock__factory } from '../../../../../typechain' import { TIMELOCK } from '../../../../../shared/constants' diff --git a/scripts/governance/add/addRewards/addEthRewards/proposal.txt b/scripts/governance/add/addRewards/addEthRewardsV1/proposal.txt similarity index 100% rename from scripts/governance/add/addRewards/addEthRewards/proposal.txt rename to scripts/governance/add/addRewards/addEthRewardsV1/proposal.txt diff --git a/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.config.ts b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.config.ts new file mode 100644 index 000000000..3ac0b164d --- /dev/null +++ b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.config.ts @@ -0,0 +1,55 @@ +import { USDT } from '../../../../shared/constants' +import { ACCUMULATOR } from '../../../../shared/constants' +import { ONEUSDC } from '../../../../shared/constants' +import { FYUSDT2309, YSUSDT6MMS } from '../../../../shared/constants' + +import * as base_config from '../../base.mainnet.config' + +export const chainId: number = base_config.chainId +export const developer: string = '0xC7aE076086623ecEA2450e364C838916a043F9a8' +export const deployers: Map = base_config.deployers +export const whales: Map = base_config.whales + +export const governance: Map = base_config.governance +export const protocol: Map = base_config.protocol +export const assets: Map = base_config.assets +export const joins: Map = base_config.joins +export const fyTokens: Map = base_config.fyTokens +export const pools: Map = base_config.pools +export const strategyAddresses: Map = base_config.strategyAddresses + +export const series: Map = base_config.series +export const strategies: Map = base_config.strategies + +import { Series, Strategy } from '../../confTypes' + +export const ONEUSDT = ONEUSDC + +const usdt = base_config.bases.get(USDT)! +const usdtIlks = base_config.ilks.get(USDT)! + +const fyUSDT2309: Series = { + seriesId: FYUSDT2309, + base: usdt, + fyToken: { + assetId: FYUSDT2309, + address: fyTokens.getOrThrow(FYUSDT2309)!, + }, + chiOracle: protocol.getOrThrow(ACCUMULATOR)!, + pool: { + assetId: FYUSDT2309, + address: pools.getOrThrow(FYUSDT2309)!, + }, + ilks: usdtIlks, +} + +export const newSeries: Series[] = [fyUSDT2309] + +const ysUSDT6MMS: Strategy = { + assetId: YSUSDT6MMS, + address: strategyAddresses.getOrThrow(YSUSDT6MMS)!, + base: usdt, + seriesToInvest: fyUSDT2309, +} + +export const rollStrategies: Strategy[] = [ysUSDT6MMS] diff --git a/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.deployments.ts b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.deployments.ts new file mode 100644 index 000000000..cdb4856d0 --- /dev/null +++ b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.deployments.ts @@ -0,0 +1,37 @@ +import { BigNumber } from 'ethers' +import { ONE64, secondsInOneYear } from '../../../../../shared/constants' +import { YSETH6MJD, RWETH6MJD } from '../../../../../shared/constants' +import { SAFE_ERC20_NAMER, YIELDMATH, ACCUMULATOR } from '../../../../../shared/constants' + +import { ContractDeployment } from '../../../confTypes' // Note we use the series id as the asset id + +import { readAddressMappingIfExists } from '../../../../../shared/helpers' + +import * as base_config from '../../../base.mainnet.config' + +export const chainId: number = base_config.chainId +export const developer: string = '0xC7aE076086623ecEA2450e364C838916a043F9a8' +export const whales: Map = base_config.whales + +export const governance: Map = base_config.governance +export const external: Map = base_config.external +export const assets: Map = base_config.assets +export const protocol = () => readAddressMappingIfExists('protocol.json') +export const joins = () => readAddressMappingIfExists('joins.json') +export const fyTokens = () => readAddressMappingIfExists('fyTokens.json') +export const pools = () => readAddressMappingIfExists('pools.json') +export const strategies = () => readAddressMappingIfExists('strsategies.json') + +// ----- deployment parameters ----- +export const contractDeployments: ContractDeployment[] = [ + /// @notice Deploy rewards wrapper + /// @param name + /// @param symbol + /// @param decimals + { + addressFile: 'strategies.json', + name: RWETH6MJD, + contract: 'ERC20RewardsWrapper', + args: [() => 'RWETH6MJD', () => 'RWETH6MJD', () => 18], + }, +] diff --git a/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.sh b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.sh new file mode 100755 index 000000000..edc68fab7 --- /dev/null +++ b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.mainnet.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -eux +export HERE=$(dirname $0) +RUN="npx hardhat run --network localhost" + +# Phase 1: Deploy Contracts +export CONF=$PWD/$HERE/rollSep23Series.mainnet.deployments +$RUN $HERE/../../../../shared/deploy.ts + +# Phase 2: Proposal +export CONF=$PWD/$HERE/rollSep23Series.mainnet.config +# $RUN $HERE/../../../../tools/poolRollBalances.ts +# $RUN $HERE/../../../../tools/joinLoan.ts + +$RUN $HERE/../../../../tools/advanceTimeToMaturity.ts +$RUN $HERE/../rollSeries.ts +$RUN $HERE/../../../../shared/approve.ts +$RUN $HERE/../../../../shared/execute.ts diff --git a/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.ts b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.ts new file mode 100644 index 000000000..c1bc24fb5 --- /dev/null +++ b/scripts/governance/add/addRewards/addInitialRewards/addInitialRewards.ts @@ -0,0 +1,75 @@ +import { getOwnerOrImpersonate, propose } from '../../../../../shared/helpers' +import { BigNumber } from 'ethers' +import { + Timelock__factory, + EmergencyBrake__factory, + Cauldron__factory, + Ladle__factory, + Witch__factory, + Strategy__factory, + ERC20__factory, + ERC20RewardsWrapper__factory, +} from '../../../../../typechain' + +import { TIMELOCK, CLOAK, CAULDRON, LADLE, WITCH } from '../../../../../shared/constants' + +import { orchestrateRewardsWrapper } from '../../../../fragments/strategies/orchestrateRewardsWrapper' +import { setRewardsToken } from '../../../../fragments/strategies/setRewardsToken' +import { setRewardsUnderlying } from '../../../../fragments/strategies/setRewardsUnderlying' +import { sendTokens } from '../../../../fragments/utils/sendTokens' +import { mintRewardsToken } from '../../../../fragments/strategies/mintRewardsToken' +import { addRewardsPlan } from '../../../../fragments/strategies/addRewardsPlan' + +import { Transfer } from '../../../../governance/confTypes' + +const { developer, deployers, governance, protocol, strategies, newRewards } = require(process.env.CONF as string) + +/** + * @dev This script sets the rewards wrappers for the strategies + */ +;(async () => { + let ownerAcc = await getOwnerOrImpersonate(developer) + + const timelock = Timelock__factory.connect(governance.getOrThrow(TIMELOCK)!, ownerAcc) + const cloak = EmergencyBrake__factory.connect(governance.getOrThrow(CLOAK)!, ownerAcc) + const cauldron = Cauldron__factory.connect(protocol.getOrThrow(CAULDRON)!, ownerAcc) + const ladle = Ladle__factory.connect(protocol.getOrThrow(LADLE)!, ownerAcc) + const witch = Witch__factory.connect(protocol.getOrThrow(WITCH)!, ownerAcc) + + // Build the proposal + let proposal: Array<{ target: string; data: string }> = [] + + for (let rewards of newRewards) { + const strategy = Strategy__factory.connect(strategies.getOrThrow(rewards.strategy.address)!, ownerAcc) + const wrapper = ERC20RewardsWrapper__factory.connect(strategies.getOrThrow(rewards.wrapper.address)!, ownerAcc) + const underlying = ERC20__factory.connect(strategies.getOrThrow(rewards.wrapper.underlying.address)!, ownerAcc) + + // Orchestrate new rewards wrappers + proposal = proposal.concat( + await orchestrateRewardsWrapper(deployers.getOrThrow('rewardsWrapper')!, timelock, wrapper) + ) + + // Set the wrappers as rewards for the strategies + proposal = proposal.concat(await setRewardsToken(strategy, wrapper.address)) + + // Set the underlying token for the wrappers + proposal = proposal.concat(await setRewardsUnderlying(wrapper, underlying.address)) + + // Transfer the underlying to the rewards wrapper + const amount: BigNumber = BigNumber.from(rewards.current.rate * (rewards.current.stop - rewards.current.start)) + const transfer: Transfer = { + token: rewards.wrapper.underlying, + receiver: rewards.wrapper.address, + amount: amount, + } + proposal = proposal.concat(await sendTokens(timelock, transfer)) + + // Mint the rewards + proposal = proposal.concat(await mintRewardsToken(strategy, amount)) + + // Add the rewards plan for the strategies + proposal = proposal.concat(await addRewardsPlan(strategy, rewards.current)) + } + + await propose(timelock, proposal, developer) +})() diff --git a/scripts/governance/confTypes.ts b/scripts/governance/confTypes.ts index cd2f6e2a0..8bf02441f 100644 --- a/scripts/governance/confTypes.ts +++ b/scripts/governance/confTypes.ts @@ -14,6 +14,12 @@ export interface Permission { user: string } +export interface Transfer { + token: Asset + receiver: string + amount: BigNumber +} + export interface Asset { assetId: string address: string @@ -86,10 +92,21 @@ export interface Series { ilks: Ilk[] } +export interface RewardsWrapper extends Asset { + underlying: Asset +} + +export interface RewardsPlan { + start: number + stop: number + rate: number +} + export interface Strategy extends Asset { base: Base initAmount?: BigNumber seriesToInvest?: Series + rewards?: RewardsWrapper } // Temporary interface for the v1 to v2 strategy migration diff --git a/scripts/governance/emergency/restoreStrategies/sendTokens.ts b/scripts/governance/emergency/restoreStrategies/sendTokens.ts index 80126c534..da5918a3c 100644 --- a/scripts/governance/emergency/restoreStrategies/sendTokens.ts +++ b/scripts/governance/emergency/restoreStrategies/sendTokens.ts @@ -1,7 +1,7 @@ import { ethers } from 'hardhat' import { getOwnerOrImpersonate, proposeApproveExecute } from '../../../../shared/helpers' -import { sendTokensProposal } from '../../../fragments/emergency/sendTokensProposal' +import { sendTokensProposal } from '../../../fragments/utils/sendTokens' const { governance, developer, sendData } = require(process.env.CONF as string) diff --git a/yarn.lock b/yarn.lock index b748d2928..9193d2f85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3111,10 +3111,10 @@ resolved "https://registry.yarnpkg.com/@yield-protocol/strategy-v2/-/strategy-v2-2.0.3.tgz#74f678812b04ea630784cbff30c26916d816cd54" integrity sha512-P6HY8tqHVwnXUkF59SYB16F8YNYUbVeQ1wjA/ziRu/wlLbnf7MXDqP+XD1SU5HTSgC0BSReVfsq9aHliamnOLg== -"@yield-protocol/utils-v2@2.6.11": - version "2.6.11" - resolved "https://registry.yarnpkg.com/@yield-protocol/utils-v2/-/utils-v2-2.6.11.tgz#974c42779c89a5a57cbaeeef8f8fba390d63d116" - integrity sha512-0yPI/XaSQ1Y4g0nF3zG1QgumieM1lOGCur4NWf2Vs5BhbgA+6PMTOUsaaqWTYkkeAiK6heEY80C0YPj7kMx9ew== +"@yield-protocol/utils-v2@2.6.15": + version "2.6.15" + resolved "https://registry.yarnpkg.com/@yield-protocol/utils-v2/-/utils-v2-2.6.15.tgz#ebaf3ef925224f4f9c464cc6fbe572eca5b447f8" + integrity sha512-bda/rK780uYlm1s2wed3veajyvg7iMwPcILtFKDZy8wJAZf47R9figRUgxosItu5nBU9Dy5aPfpSV8cmm705NQ== "@yield-protocol/utils-v2@^2.4.2": version "2.6.8"