Activate the ETH, DAI, USDC and FRAX June 2023 series. Migrate the funds in June-December 6M strategies from v1 to v2. Invest the June-December 6M strategies in the June 2023 series. Enable fCash as collateral for the ETH, DAI and USDC June 2023 series.
The Strategy v2 contracts simplify the rolling process and include emergency mechanisms to exit an investment before maturity. The rest of the rolling operation is as usual.
The steps are: 1. Deploy new FYTokens, Euler pools and Non-tv pools. 2. Deploy new Strategies. 3. Deploy new FCash Joins. 4. Governance proposal i. Orchestrate contracts ii. Update Notional Oracle iii. Add new series iv. Add the new FCash tenors as ilks v. Add all ilks to the new series vi. Migrate the funds from v1 strategies to v2 strategies vii. Invest the funds in the v2 strategies in the June 2023 series.
Scripts for deployment and activation along with config.
import { BigNumber } from 'ethers'
import { ONE64, secondsInOneYear } from '../../../../../shared/constants'
import { ETH, DAI, USDC } from '../../../../../shared/constants'
import { EOJUN23 } from '../../../../../shared/constants'
import { FYETH2306, FYDAI2306, FYUSDC2306 } from '../../../../../shared/constants'
import { YSETH6MJD, YSDAI6MJD, YSUSDC6MJD } 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.arb_mainnet.config'
export const chainId: number = base_config.chainId
export const developer: string = '0xC7aE076086623ecEA2450e364C838916a043F9a8'
export const deployer: string = '0xC7aE076086623ecEA2450e364C838916a043F9a8'
export const whales: Map<string, string> = base_config.whales
export const governance: Map<string, string> = base_config.governance
export const protocol = () => readAddressMappingIfExists('protocol.json')
export const assets: Map<string, string> = base_config.assets
export const joins: Map<string, string> = base_config.joins
export const fyTokens: Map<string, string> = base_config.fyTokens
export const pools: Map<string, string> = base_config.pools
export const strategies: Map<string, string> = base_config.strategies
export const newFYTokens = () => readAddressMappingIfExists('newFYTokens.json')
export const newPools = () => readAddressMappingIfExists('newPools.json')
export const newStrategies = () => readAddressMappingIfExists('newStrategies.json')
/// @notice Time stretch to be set in the PoolFactory prior to pool deployment
/// @param series identifier (bytes6 tag)
/// @param time stretch (64.64)
export const timeStretch: Map<string, BigNumber> = new Map([
[FYETH2306, ONE64.div(secondsInOneYear.mul(25))],
[FYDAI2306, ONE64.div(secondsInOneYear.mul(45))],
[FYUSDC2306, ONE64.div(secondsInOneYear.mul(55))],
])
/// @notice Sell base to the pool fee, as fp4
export const g1: number = 9000
// ----- deployment parameters -----
export const contractDeployments: ContractDeployment[] = [
/// @notice Deploy fyToken series
/// @param underlying identifier (bytes6 tag)
/// @param Address for the chi oracle
/// @param Address for the related Join
/// @param Maturity in unix time (seconds since Jan 1, 1970)
/// @param Name for the series
/// @param Symbol for the series
{
addressFile: 'newFYTokens.json',
name: FYETH2306,
contract: 'FYToken',
args: [
() => ETH,
() => protocol().getOrThrow(ACCUMULATOR),
() => joins.getOrThrow(ETH),
() => EOJUN23,
() => 'FYETH2306',
() => 'FYETH2306',
],
libs: {
SafeERC20Namer: protocol().getOrThrow(SAFE_ERC20_NAMER)!,
},
},
{
addressFile: 'newFYTokens.json',
name: FYDAI2306,
contract: 'FYToken',
args: [
() => DAI,
() => protocol().getOrThrow(ACCUMULATOR),
() => joins.getOrThrow(DAI),
() => EOJUN23,
() => 'FYDAI2306',
() => 'FYDAI2306',
],
libs: {
SafeERC20Namer: protocol().getOrThrow(SAFE_ERC20_NAMER)!,
},
},
{
addressFile: 'newFYTokens.json',
name: FYUSDC2306,
contract: 'FYToken',
args: [
() => USDC,
() => protocol().getOrThrow(ACCUMULATOR),
() => joins.getOrThrow(USDC),
() => EOJUN23,
() => 'FYUSDC2306',
() => 'FYUSDC2306',
],
libs: {
SafeERC20Namer: protocol().getOrThrow(SAFE_ERC20_NAMER)!,
},
},
/// @notice Deploy plain YieldSpace pools
/// @param pool identifier, usually matching the series (bytes6 tag)
/// @param base address
/// @param fyToken address
/// @param time stretch, in 64.64
/// @param g1, in 64.64
{
addressFile: 'newPools.json',
name: FYETH2306,
contract: 'PoolNonTv',
args: [
() => assets.get(ETH)!,
() => newFYTokens().getOrThrow(FYETH2306)!,
() => timeStretch.get(FYETH2306)!.toString(),
() => g1.toString(),
],
libs: {
YieldMath: protocol().getOrThrow(YIELDMATH)!,
},
},
{
addressFile: 'newPools.json',
name: FYDAI2306,
contract: 'PoolNonTv',
args: [
() => assets.get(DAI)!,
() => newFYTokens().getOrThrow(FYDAI2306)!,
() => timeStretch.get(FYDAI2306)!.toString(),
() => g1.toString(),
],
libs: {
YieldMath: protocol().getOrThrow(YIELDMATH)!,
},
},
{
addressFile: 'newPools.json',
name: FYUSDC2306,
contract: 'PoolNonTv',
args: [
() => assets.get(USDC)!,
() => newFYTokens().getOrThrow(FYUSDC2306)!,
() => timeStretch.get(FYUSDC2306)!.toString(),
() => g1.toString(),
],
libs: {
YieldMath: protocol().getOrThrow(YIELDMATH)!,
},
},
/// @notice Deploy strategies
/// @param strategy name
/// @param strategy identifier (bytes6 tag)
/// @param Address for the Ladle
/// @param Address for the underlying asset
/// @param Underlying asset identifier (bytes6 tag)
/// @param Address for the underlying asset join
{
addressFile: 'newStrategies.json',
name: YSETH6MJD,
contract: 'Strategy',
args: [() => 'Yield Strategy ETH 6M Jun Dec', () => YSETH6MJD, () => newFYTokens().getOrThrow(FYETH2306)!],
libs: {
SafeERC20Namer: protocol().getOrThrow(SAFE_ERC20_NAMER)!,
},
},
{
addressFile: 'newStrategies.json',
name: YSDAI6MJD,
contract: 'Strategy',
args: [() => 'Yield Strategy DAI 6M Jun Dec', () => YSDAI6MJD, () => newFYTokens().getOrThrow(FYDAI2306)!],
libs: {
SafeERC20Namer: protocol().getOrThrow(SAFE_ERC20_NAMER)!,
},
},
{
addressFile: 'newStrategies.json',
name: YSUSDC6MJD,
contract: 'Strategy',
args: [() => 'Yield Strategy USDC 6M Jun Dec', () => YSUSDC6MJD, () => newFYTokens().getOrThrow(FYUSDC2306)!],
libs: {
SafeERC20Namer: protocol().getOrThrow(SAFE_ERC20_NAMER)!,
},
},
]
import { BigNumber } from 'ethers'
import { WAD } from '../../../../../shared/constants'
import { ETH, DAI, USDC, WBTC, WSTETH, LINK, ENS, UNI, FRAX, YVUSDC } from '../../../../../shared/constants'
import { FYETH2306, FYDAI2306, FYUSDC2306, FYFRAX2306 } from '../../../../../shared/constants'
import {
YSETH6MJD,
YSDAI6MJD,
YSUSDC6MJD,
YSFRAX6MJD,
YSETH6MJD_V1,
YSDAI6MJD_V1,
YSUSDC6MJD_V1,
YSFRAX6MJD_V1,
} from '../../../../../shared/constants'
import { FCASH, FETH2306, FDAI2306, FUSDC2306 } from '../../../../../shared/constants'
import { AuctionLineAndLimit } from '../../../confTypes' // Note we use the series id as the asset id
import * as base_config from '../../../base.mainnet.config'
export const chainId: number = base_config.chainId
export const developer: string = '0xC7aE076086623ecEA2450e364C838916a043F9a8'
export const deployer: string = '0xC7aE076086623ecEA2450e364C838916a043F9a8'
export const whales: Map<string, string> = base_config.whales
export const governance: Map<string, string> = base_config.governance
export const external: Map<string, string> = base_config.external
export const protocol: Map<string, string> = base_config.protocol
export const assets: Map<string, string> = base_config.assets
export const joins: Map<string, string> = base_config.joins
export const strategies: Map<string, string> = base_config.strategies
export const newFYTokens: Map<string, string> = base_config.newFYTokens
export const newJoins: Map<string, string> = base_config.newJoins
export const newPools: Map<string, string> = base_config.newPools
export const newStrategies: Map<string, string> = base_config.newStrategies
/// @notice Ilks to accept for series
/// @param series identifier (bytes6 tag)
/// @param newly accepted ilks (array of bytes6 tags)
export const seriesIlks: Array<[string, string[]]> = [
[FYETH2306, [ETH, DAI, USDC, WBTC, WSTETH, LINK, ENS, UNI, FRAX, FETH2306]],
[FYDAI2306, [ETH, DAI, USDC, WBTC, WSTETH, LINK, ENS, UNI, FRAX, FDAI2306]],
[FYUSDC2306, [ETH, DAI, USDC, WBTC, WSTETH, LINK, ENS, UNI, FRAX, YVUSDC, FUSDC2306]],
[FYFRAX2306, [ETH, DAI, USDC, WBTC, WSTETH, LINK, ENS, UNI, FRAX]],
]
/// Parameters to roll each strategy
/// @param source strategy
/// @param seriesId(poolId) on the destination strategy
/// @param destination strategy
/// @param pool to invest in
export const migrateData: Array<[string, string, string, string]> = [
[
strategies.getOrThrow(YSETH6MJD_V1)!,
FYETH2306,
newStrategies.getOrThrow(YSETH6MJD)!,
newPools.getOrThrow(FYETH2306)!,
],
[
strategies.getOrThrow(YSDAI6MJD_V1)!,
FYDAI2306,
newStrategies.getOrThrow(YSDAI6MJD)!,
newPools.getOrThrow(FYDAI2306)!,
],
[
strategies.getOrThrow(YSUSDC6MJD_V1)!,
FYUSDC2306,
newStrategies.getOrThrow(YSUSDC6MJD)!,
newPools.getOrThrow(FYUSDC2306)!,
],
[
strategies.getOrThrow(YSFRAX6MJD_V1)!,
FYFRAX2306,
newStrategies.getOrThrow(YSFRAX6MJD)!,
newPools.getOrThrow(FYFRAX2306)!,
],
]
/// @dev The Notional Oracle is fed with Yield Protocol asset pairs to register.
/// Since we are valuing the fCash at face value, we don't need the Notional fCash ids.
/// Note: notionalId (FDAI2203) is the id of an fCash tenor in the Yield Protocol,
/// while fCashId (FDAI2203ID) is the id of that same tenor in Notional Finance
/// @param fcash: address of the fCash contract
/// @param notionalId: asset id of an fCash tenor in the Yield Protocol
/// @param underlyingId: asset id of a borrowable asset in the Yield Protocol
/// @param underlying: contract address matching underlyingId
export const notionalSources: Array<[string, string, string, string]> = [
[external.getOrThrow(FCASH)!, FETH2306, ETH, assets.get(ETH) as string],
[external.getOrThrow(FCASH)!, FDAI2306, DAI, assets.get(DAI) as string],
[external.getOrThrow(FCASH)!, FUSDC2306, USDC, assets.get(USDC) as string],
]
/// @dev Collateralization ratio, debt ceiling, and debt dust
/// @param baseId: asset id of a borrowable asset
/// @param ilkId: asset id of a collateral asset
/// @param ratio: collateralization ratio for the base/ilk pair, with 1000000 == 100%
/// @param line: maximum debt across the protocol for the pair, with added dec
/// @param dust: minimum debt in any given vault for the pair, with added dec
/// @param dec: number of zeros to append to line and dust
export const notionalDebtLimits: Array<[string, string, number, number, number, number]> = [
[ETH, FETH2306, 1100000, 400, 1, 18],
[DAI, FDAI2306, 1100000, 500000, 1000, 18],
[USDC, FUSDC2306, 1100000, 500000, 1000, 6],
]
/// @dev Parameters to govern liquidations
export const auctionLineAndLimits: AuctionLineAndLimit[] = []
/// Strategies to print redeemable and available funds for.
export const rollData: Array<[string]> = [[YSETH6MJD], [YSDAI6MJD], [YSUSDC6MJD], [YSFRAX6MJD]]
// Amount to be donated to the Joins in forks
export const joinLoans: Map<string, BigNumber> = new Map([[FRAX, WAD.mul(5000)]])
The testing includes the NotionalJoin test harness, strategy and ERC20Rewards test harnesses and web-based manual testing on a mainnet fork
The Strategy v2 contracts were internally audited by @devtooligan