diff --git a/.gitignore b/.gitignore index 55e83b0ad..06cd23427 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ dist/ .idea/ .DS_Store addresses/localhost/ +addresses/tenderly/ tmp/ # Foundry diff --git a/addresses/mainnet/assets.json b/addresses/mainnet/assets.json index 091159d6e..b151d1bfa 100644 --- a/addresses/mainnet/assets.json +++ b/addresses/mainnet/assets.json @@ -1,113 +1,34 @@ { - "dataType": "Map", - "value": [ - [ - "0x303000000000", - "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - ], - [ - "0x303100000000", - "0x6B175474E89094C44Da98b954EedeAC495271d0F" - ], - [ - "0x303200000000", - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" - ], - [ - "0x303300000000", - "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" - ], - [ - "0x303400000000", - "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" - ], - [ - "0x303500000000", - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" - ], - [ - "0x303600000000", - "0x514910771AF9Ca656af840dff83E8264EcF986CA" - ], - [ - "0x303700000000", - "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72" - ], - [ - "0x303800000000", - "0xdA816459F1AB5631232FE5e97a05BBBb94970c95" - ], - [ - "0x303900000000", - "0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE" - ], - [ - "0x313000000000", - "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], - [ - "0x313200000000", - "0x1344A36A1B56144C3Bc62E7757377D288fDE0369" - ], - [ - "0x313300000000", - "0x1344A36A1B56144C3Bc62E7757377D288fDE0369" - ], - [ - "0x313400000000", - "0x1344A36A1B56144C3Bc62E7757377D288fDE0369" - ], - [ - "0x313500000000", - "0x1344A36A1B56144C3Bc62E7757377D288fDE0369" - ], - [ - "0x313600000000", - "0x1344A36A1B56144C3Bc62E7757377D288fDE0369" - ], - [ - "0x313700000000", - "0x1344A36A1B56144C3Bc62E7757377D288fDE0369" - ], - [ - "0x313800000000", - "0x853d955aCEf822Db058eb8505911ED77F175b99e" - ], - [ - "0x313900000000", - "" - ], - [ - "0x323000000000", - "0x1b808F49ADD4b8C6b5117d9681cF7312Fcf0dC1D" - ], - [ - "0x323100000000", - "0xe025E3ca2bE02316033184551D4d3Aa22024D9DC" - ], - [ - "0x323200000000", - "0xEb91861f8A4e1C12333F42DCE8fB0Ecdc28dA716" - ], - [ - "0x323300000000", - "0x853d955acef822db058eb8505911ed77f175b99e" - ], - [ - "0x333800000000", - "0x3B960E47784150F5a63777201ee2B15253D713e8" - ], - [ - "0x333900000000", - "0xf1B99e3E573A1a9C5E6B2Ce818b617F0E664E86B" - ], - [ - "0x30A000000000", - "0xdAC17F958D2ee523a2206206994597C13D831ec7" - ], - [ - "0xE0A014000000", - "0x4d19F33948b99800B6113Ff3e83beC9b537C85d2" - ] - ] - } \ No newline at end of file + "dataType": "Map", + "value": [ + ["0x303000000000", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"], + ["0x303100000000", "0x6B175474E89094C44Da98b954EedeAC495271d0F"], + ["0x303200000000", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], + ["0x303300000000", "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"], + ["0x303400000000", "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"], + ["0x303500000000", "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84"], + ["0x303600000000", "0x514910771AF9Ca656af840dff83E8264EcF986CA"], + ["0x303700000000", "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72"], + ["0x303800000000", "0xdA816459F1AB5631232FE5e97a05BBBb94970c95"], + ["0x303900000000", "0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE"], + ["0x313000000000", "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + ["0x313200000000", "0x1344A36A1B56144C3Bc62E7757377D288fDE0369"], + ["0x313300000000", "0x1344A36A1B56144C3Bc62E7757377D288fDE0369"], + ["0x313400000000", "0x1344A36A1B56144C3Bc62E7757377D288fDE0369"], + ["0x313500000000", "0x1344A36A1B56144C3Bc62E7757377D288fDE0369"], + ["0x313600000000", "0x1344A36A1B56144C3Bc62E7757377D288fDE0369"], + ["0x313700000000", "0x1344A36A1B56144C3Bc62E7757377D288fDE0369"], + ["0x313800000000", "0x853d955aCEf822Db058eb8505911ED77F175b99e"], + ["0x313900000000", ""], + ["0x323000000000", "0x1b808F49ADD4b8C6b5117d9681cF7312Fcf0dC1D"], + ["0x323100000000", "0xe025E3ca2bE02316033184551D4d3Aa22024D9DC"], + ["0x323200000000", "0xEb91861f8A4e1C12333F42DCE8fB0Ecdc28dA716"], + ["0x323300000000", "0x853d955acef822db058eb8505911ed77f175b99e"], + ["0x333800000000", "0x3B960E47784150F5a63777201ee2B15253D713e8"], + ["0x333900000000", "0xf1B99e3E573A1a9C5E6B2Ce818b617F0E664E86B"], + ["0x30A000000000", "0xdAC17F958D2ee523a2206206994597C13D831ec7"], + ["0xE0A014000000", "0x4d19F33948b99800B6113Ff3e83beC9b537C85d2"], + ["0xE03016000000", "0xae78736Cd615f374D3085123A210448E74Fc6393"], + ["0xE03017000000", "0xb46Fb07b0c80DBC3F97cae3BFe168AcaD46dF507"] + ] +} diff --git a/contracts/Importer.sol b/contracts/Importer.sol index 13e9d110b..9f61337a9 100644 --- a/contracts/Importer.sol +++ b/contracts/Importer.sol @@ -15,8 +15,10 @@ import "@yield-protocol/vault-v2/contracts/oracles/lido/LidoOracle.sol"; import "@yield-protocol/vault-v2/contracts/oracles/lido/IWstETH.sol"; import "@yield-protocol/vault-v2/contracts/oracles/yearn/YearnVaultMultiOracle.sol"; import "@yield-protocol/vault-v2/contracts/oracles/yearn/IYvToken.sol"; -import "@yield-protocol/vault-v2/contracts/oracles/crab/CrabOracle.sol"; +// import "@yield-protocol/vault-v2/contracts/oracles/crab/CrabOracle.sol"; +import "@yield-protocol/vault-v2/contracts/oracles/opyn/ZenBullOracle.sol"; import "@yield-protocol/vault-v2/contracts/oracles/yieldspace/YieldSpaceMultiOracle.sol"; +import "@yield-protocol/vault-v2/contracts/oracles/rocket/RETHOracle.sol"; import "@yield-protocol/vault-v2/contracts/other/notional/NotionalJoin.sol"; import "@yield-protocol/vault-v2/contracts/other/notional/NotionalMultiOracle.sol"; import "@yield-protocol/vault-v2/contracts/other/notional/Transfer1155Module.sol"; diff --git a/scripts/fragments/assetsAndSeries/makeIlk.ts b/scripts/fragments/assetsAndSeries/makeIlk.ts index 84403d021..19ea52d4f 100644 --- a/scripts/fragments/assetsAndSeries/makeIlk.ts +++ b/scripts/fragments/assetsAndSeries/makeIlk.ts @@ -19,7 +19,6 @@ export const makeIlk = async ( joins: Map // assetId, joinAddress ): Promise> => { let proposal: Array<{ target: string; data: string }> = [] - const join = Join__factory.connect(joins.get(ilk.ilkId)!, ownerAcc) proposal = proposal.concat(await updateCollateralization(cauldron, ilk)) diff --git a/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.config.ts b/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.config.ts new file mode 100644 index 000000000..62510d137 --- /dev/null +++ b/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.config.ts @@ -0,0 +1,203 @@ +import { parseUnits } from 'ethers/lib/utils' +import { + COMPOSITE, + DAI, + ETH, + FYDAI2303, + FYDAI2306, + FYETH2303, + FYETH2306, + FYUSDC2303, + FYUSDC2306, + RETH, + RETH_ORACLE, + USDC, +} from '../../../../../../shared/constants' +import { readAddressMappingIfExists } from '../../../../../../shared/helpers' +import * as base_config from '../../../../base.mainnet.config' +import { Asset, ContractDeployment, Ilk, OraclePath, OracleSource, Series } from '../../../../confTypes' + +const fyTokens = readAddressMappingIfExists('fyTokens.json') +export const whales = base_config.whales +export const developer = '0xC7aE076086623ecEA2450e364C838916a043F9a8' +export const deployer = '0xC7aE076086623ecEA2450e364C838916a043F9a8' +export const deployers = readAddressMappingIfExists('deployers.json') +export const protocol = () => readAddressMappingIfExists('protocol.json') +export const governance = readAddressMappingIfExists('governance.json') +export const joins = readAddressMappingIfExists('joins.json') +export const assets: Map = base_config.assets +export const reth: Asset = { assetId: RETH, address: assets.getOrThrow(RETH)! } + +export const contractDeployments: ContractDeployment[] = [ + { + addressFile: 'protocol.json', + name: RETH_ORACLE, + contract: 'RETHOracle', + args: [() => ETH, () => RETH, () => assets.getOrThrow(RETH)!], + }, + { + addressFile: 'joins.json', + name: RETH, + contract: 'Join', + args: [() => assets.getOrThrow(RETH)!], + }, +] + +export const ilkToETH: Ilk = { + baseId: ETH, + ilkId: reth.assetId, + asset: reth, + collateralization: { + baseId: ETH, + ilkId: reth.assetId, + oracle: protocol().getOrThrow(RETH_ORACLE)!, + ratio: 1330000, + }, + debtLimits: { + baseId: ETH, + ilkId: reth.assetId, + line: 100, + dust: 1, + dec: 18, + }, + auctionLineAndLimit: { + baseId: ETH, + ilkId: reth.assetId, + duration: 3600, + vaultProportion: parseUnits('0.5'), + collateralProportion: parseUnits('0.84'), // 105 / 125 + max: parseUnits('1000'), + }, +} + +export const ilkToDAI: Ilk = { + baseId: DAI, + ilkId: reth.assetId, + asset: reth, + collateralization: { + baseId: DAI, + ilkId: reth.assetId, + oracle: protocol().getOrThrow(COMPOSITE)!, + ratio: 1670000, + }, + debtLimits: { + baseId: DAI, + ilkId: reth.assetId, + line: 250000, + dust: 1000, + dec: 18, + }, + auctionLineAndLimit: { + baseId: DAI, + ilkId: reth.assetId, + duration: 3600, + vaultProportion: parseUnits('0.5'), + collateralProportion: parseUnits('0.75'), // 105 / 140 + max: parseUnits('1000'), + }, +} + +export const ilkToUSDC: Ilk = { + baseId: USDC, + ilkId: reth.assetId, + asset: reth, + collateralization: { + baseId: USDC, + ilkId: reth.assetId, + oracle: protocol().getOrThrow(COMPOSITE)!, + ratio: 1670000, + }, + debtLimits: { + baseId: USDC, + ilkId: reth.assetId, + line: 250000, + dust: 1000, + dec: 6, + }, + auctionLineAndLimit: { + baseId: USDC, + ilkId: reth.assetId, + duration: 3600, + vaultProportion: parseUnits('0.5'), + collateralProportion: parseUnits('0.75'), // 105 / 140 + max: parseUnits('1000'), + }, +} + +export const ilks: Ilk[] = [ilkToETH, ilkToDAI, ilkToUSDC] + +export const oracleSources: OracleSource[] = [ + { + baseId: ETH, + baseAddress: assets.getOrThrow(ETH)!, + quoteId: RETH, + quoteAddress: assets.getOrThrow(RETH)!, + sourceAddress: protocol().getOrThrow(RETH_ORACLE)!, + }, +] + +export const oraclePaths: OraclePath[] = [ + { + baseId: RETH, + quoteId: DAI, + path: [ETH], + }, + { + baseId: RETH, + quoteId: USDC, + path: [ETH], + }, +] + +export const ethSeries: Series[] = [ + { + seriesId: FYETH2303, + fyToken: { assetId: FYETH2303, address: fyTokens.getOrThrow(FYETH2303)! }, + chiOracle: '', + pool: reth, + ilks: [ilkToETH], + }, + { + seriesId: FYETH2306, + fyToken: { assetId: FYETH2306, address: fyTokens.getOrThrow(FYETH2306)! }, + chiOracle: '', + pool: reth, + ilks: [ilkToETH], + }, +] + +export const daiSeries: Series[] = [ + { + seriesId: FYDAI2303, + fyToken: { assetId: FYDAI2303, address: fyTokens.getOrThrow(FYDAI2303)! }, + chiOracle: '', + pool: reth, + ilks: [ilkToDAI], + }, + { + seriesId: FYDAI2306, + fyToken: { assetId: FYDAI2306, address: fyTokens.getOrThrow(FYDAI2306)! }, + chiOracle: '', + pool: reth, + ilks: [ilkToDAI], + }, +] + +export const usdcSeries: Series[] = [ + { + seriesId: FYUSDC2303, + fyToken: { assetId: FYUSDC2303, address: fyTokens.getOrThrow(FYUSDC2303)! }, + chiOracle: '', + pool: reth, + ilks: [ilkToUSDC], + }, + { + seriesId: FYUSDC2306, + fyToken: { assetId: FYUSDC2306, address: fyTokens.getOrThrow(FYUSDC2306)! }, + chiOracle: '', + pool: reth, + ilks: [ilkToUSDC], + }, +] + +export const newSeries: Series[] = [...ethSeries, ...daiSeries, ...usdcSeries] diff --git a/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.sh b/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.sh new file mode 100755 index 000000000..453eccb4c --- /dev/null +++ b/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -eux +export HERE=$(dirname $0) +export CONF=$PWD/$HERE/addRETH.config +RUN="npx hardhat run --network localhost" + +$RUN $HERE/../../../../../../shared/deploy.ts +$RUN $HERE/addRETH.ts +$RUN $HERE/../../../../../../shared/approve.ts +$RUN $HERE/../../../../../../shared/execute.ts +$RUN $HERE/../../../../../../shared/standardBorrowingTest.ts \ No newline at end of file diff --git a/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.ts b/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.ts new file mode 100644 index 000000000..4812da7af --- /dev/null +++ b/scripts/governance/add/addCollateral/addCompositeCollateral/rocket/addRETH.ts @@ -0,0 +1,53 @@ +import { CAULDRON, CLOAK, COMPOSITE, LADLE, TIMELOCK, WITCH } from '../../../../../../shared/constants' +import { getOwnerOrImpersonate, propose } from '../../../../../../shared/helpers' +import { + Cauldron__factory, + Ladle__factory, + Timelock__factory, + EmergencyBrake__factory, + Witch__factory, + CompositeMultiOracle__factory, + AccessControl__factory, + Join__factory, +} from '../../../../../../typechain' +import { addAsset } from '../../../../../fragments/assetsAndSeries/addAsset' +import { addIlkToSeries } from '../../../../../fragments/assetsAndSeries/addIlkToSeries' +import { makeIlk } from '../../../../../fragments/assetsAndSeries/makeIlk' +import { orchestrateJoin } from '../../../../../fragments/assetsAndSeries/orchestrateJoin' +import { updateCompositePaths } from '../../../../../fragments/oracles/updateCompositePaths' +import { updateCompositeSources } from '../../../../../fragments/oracles/updateCompositeSources' + +const { developer, ilks, reth, protocol, governance, joins, newSeries, oraclePaths, oracleSources } = require(process + .env.CONF!) + +;(async () => { + const ownerAcc = await getOwnerOrImpersonate(developer) + const cauldron = Cauldron__factory.connect(protocol().getOrThrow(CAULDRON)!, ownerAcc) + const ladle = Ladle__factory.connect(protocol().getOrThrow(LADLE)!, ownerAcc) + const timelock = Timelock__factory.connect(governance.getOrThrow(TIMELOCK)!, ownerAcc) + const cloak = EmergencyBrake__factory.connect(governance.getOrThrow(CLOAK)!, ownerAcc) + let witch = Witch__factory.connect(protocol().getOrThrow(WITCH)!, ownerAcc) + const compositeOracle = CompositeMultiOracle__factory.connect(protocol().getOrThrow(COMPOSITE)!, ownerAcc) + witch = Object.assign(witch, { ilksAdded: [] }) + // Build the proposal + let proposal: Array<{ target: string; data: string }> = [] + // Update oracles + proposal = proposal.concat(await updateCompositeSources(compositeOracle, oracleSources)) + proposal = proposal.concat(await updateCompositePaths(compositeOracle, oraclePaths)) + // Permissions + proposal = proposal.concat( + await orchestrateJoin(timelock, cloak, Join__factory.connect(joins.getOrThrow(reth.assetId), ownerAcc)) + ) + // Asset + proposal = proposal.concat(await addAsset(ownerAcc, cloak, cauldron, ladle, reth, joins)) + for (let ilk of ilks) { + proposal = proposal.concat(await makeIlk(ownerAcc, cloak, cauldron, witch, ilk, joins)) + } + // Add ilk to series Series + for (let series of newSeries) { + for (let ilk of series.ilks) { + proposal = proposal.concat(await addIlkToSeries(cauldron, series, ilk)) + } + } + if (proposal.length > 0) await propose(timelock, proposal, developer) +})() diff --git a/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/addZenBull.sh b/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/addZenBull.sh new file mode 100755 index 000000000..3357f24d6 --- /dev/null +++ b/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/addZenBull.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -eux +HERE=$(dirname $0) +export CONF=$PWD/$HERE/zenBull.config +RUN="npx hardhat run --network tenderly" + +# $RUN $HERE/../../../../../../shared/deploy.ts +# $RUN $HERE/addZenBull.ts +# $RUN $HERE/../../../../../../shared/approve.ts +# $RUN $HERE/../../../../../../shared/execute.ts +$RUN $HERE/../../../../../../shared/standardBorrowingTest.ts \ No newline at end of file diff --git a/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/addZenBull.ts b/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/addZenBull.ts new file mode 100644 index 000000000..65499b834 --- /dev/null +++ b/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/addZenBull.ts @@ -0,0 +1,50 @@ +import { CAULDRON, CLOAK, COMPOSITE, LADLE, TIMELOCK, WITCH } from '../../../../../../shared/constants' +import { getOwnerOrImpersonate, propose } from '../../../../../../shared/helpers' +import { + Cauldron__factory, + Ladle__factory, + Timelock__factory, + EmergencyBrake__factory, + Witch__factory, + CompositeMultiOracle__factory, + Join__factory, +} from '../../../../../../typechain' +import { addAsset } from '../../../../../fragments/assetsAndSeries/addAsset' +import { addIlkToSeries } from '../../../../../fragments/assetsAndSeries/addIlkToSeries' +import { makeIlk } from '../../../../../fragments/assetsAndSeries/makeIlk' +import { orchestrateJoin } from '../../../../../fragments/assetsAndSeries/orchestrateJoin' +import { updateCompositePaths } from '../../../../../fragments/oracles/updateCompositePaths' +import { updateCompositeSources } from '../../../../../fragments/oracles/updateCompositeSources' + +const { developer, ilks, zenbull, protocol, governance, joins, newSeries, oraclePaths, oracleSources } = require(process + .env.CONF!) + +;(async () => { + const ownerAcc = await getOwnerOrImpersonate(developer) + const cauldron = Cauldron__factory.connect(protocol().getOrThrow(CAULDRON)!, ownerAcc) + const ladle = Ladle__factory.connect(protocol().getOrThrow(LADLE)!, ownerAcc) + const timelock = Timelock__factory.connect(governance.getOrThrow(TIMELOCK)!, ownerAcc) + const cloak = EmergencyBrake__factory.connect(governance.getOrThrow(CLOAK)!, ownerAcc) + const witch = Witch__factory.connect(protocol().getOrThrow(WITCH)!, ownerAcc) + const compositeOracle = CompositeMultiOracle__factory.connect(protocol().getOrThrow(COMPOSITE)!, ownerAcc) + // Build the proposal + let proposal: Array<{ target: string; data: string }> = [] + + proposal = proposal.concat(await updateCompositeSources(compositeOracle, oracleSources)) + proposal = proposal.concat(await updateCompositePaths(compositeOracle, oraclePaths)) + proposal = proposal.concat( + await orchestrateJoin(timelock, cloak, Join__factory.connect(joins.getOrThrow(zenbull.assetId), ownerAcc)) + ) + // Asset + proposal = proposal.concat(await addAsset(ownerAcc, cloak, cauldron, ladle, zenbull, joins)) + for (let ilk of ilks) { + proposal = proposal.concat(await makeIlk(ownerAcc, cloak, cauldron, witch, ilk, joins)) + } + // Add ilk to series Series + for (let series of newSeries) { + for (let ilk of series.ilks) { + proposal = proposal.concat(await addIlkToSeries(cauldron, series, ilk)) + } + } + if (proposal.length > 0) await propose(timelock, proposal, developer) +})() diff --git a/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/zenBull.config.ts b/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/zenBull.config.ts new file mode 100644 index 000000000..96ff1177a --- /dev/null +++ b/scripts/governance/add/addCollateral/addOpynCollateral/addZenBullCollateral/zenBull.config.ts @@ -0,0 +1,217 @@ +import { parseUnits } from 'ethers/lib/utils' +import { + COMPOSITE, + DAI, + ETH, + FYDAI2303, + FYDAI2306, + FYETH2303, + FYETH2306, + FYUSDC2303, + FYUSDC2306, + ZENBULL, + ZENBULL_ORACLE, + USDC, + CRAB, +} from '../../../../../../shared/constants' +import { readAddressMappingIfExists } from '../../../../../../shared/helpers' +import * as base_config from '../../../../base.mainnet.config' +import { Asset, ContractDeployment, Ilk, OraclePath, OracleSource, Series } from '../../../../confTypes' + +const fyTokens = readAddressMappingIfExists('fyTokens.json') +export const whales = base_config.whales +export const developer = '0xC7aE076086623ecEA2450e364C838916a043F9a8' +export const deployer = '0xC7aE076086623ecEA2450e364C838916a043F9a8' +export const protocol = () => readAddressMappingIfExists('protocol.json') +export const governance = readAddressMappingIfExists('governance.json') +export const joins = readAddressMappingIfExists('newJoins.json') +export const assets: Map = base_config.assets +export const zenbull: Asset = { assetId: ZENBULL, address: assets.getOrThrow(ZENBULL) as string } + +const osqthWethPool = '0x82c427AdFDf2d245Ec51D8046b41c4ee87F0d29C' +const wethUsdcPool = '0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8' +const eulerDToken = '0x84721A3dB22EB852233AEAE74f9bC8477F8bcc42' +const eulerEToken = '0x1b808F49ADD4b8C6b5117d9681cF7312Fcf0dC1D' + +export const contractDeployments: ContractDeployment[] = [ + { + addressFile: 'protocol.json', + name: ZENBULL_ORACLE, + contract: 'ZenBullOracle', + args: [ + () => assets.getOrThrow(CRAB)!, + () => assets.getOrThrow(ZENBULL)!, + () => osqthWethPool, + () => wethUsdcPool, + () => eulerDToken, + () => eulerEToken, + () => USDC, + () => ZENBULL, + ], + }, + { + addressFile: 'newJoins.json', + name: ZENBULL, + contract: 'Join', + args: [() => assets.getOrThrow(ZENBULL)], + }, +] + +export const ilkToETH: Ilk = { + baseId: ETH, + ilkId: zenbull.assetId, + asset: zenbull, + collateralization: { + baseId: ETH, + ilkId: zenbull.assetId, + oracle: protocol().getOrThrow(COMPOSITE)! as string, + ratio: 1250000, + }, + debtLimits: { + baseId: ETH, + ilkId: zenbull.assetId, + line: 100, + dust: 1, + dec: 18, + }, + auctionLineAndLimit: { + baseId: ETH, + ilkId: zenbull.assetId, + duration: 600, + vaultProportion: parseUnits('0.5'), + collateralProportion: parseUnits('0.84'), // 105 / 125 + max: parseUnits('1000'), + }, +} + +export const ilkToDAI: Ilk = { + baseId: DAI, + ilkId: zenbull.assetId, + asset: zenbull, + collateralization: { + baseId: DAI, + ilkId: zenbull.assetId, + oracle: protocol().getOrThrow(COMPOSITE)! as string, + ratio: 1400000, + }, + debtLimits: { + baseId: DAI, + ilkId: zenbull.assetId, + line: 250000, + dust: 1000, + dec: 18, + }, + auctionLineAndLimit: { + baseId: DAI, + ilkId: zenbull.assetId, + duration: 600, + vaultProportion: parseUnits('0.5'), + collateralProportion: parseUnits('0.75'), // 105 / 140 + max: parseUnits('1000'), + }, +} + +export const ilkToUSDC: Ilk = { + baseId: USDC, + ilkId: zenbull.assetId, + asset: zenbull, + collateralization: { + baseId: USDC, + ilkId: zenbull.assetId, + oracle: protocol().getOrThrow(ZENBULL_ORACLE)! as string, + ratio: 1400000, + }, + debtLimits: { + baseId: USDC, + ilkId: zenbull.assetId, + line: 250000, + dust: 1000, + dec: 6, + }, + auctionLineAndLimit: { + baseId: USDC, + ilkId: zenbull.assetId, + duration: 600, + vaultProportion: parseUnits('0.5'), + collateralProportion: parseUnits('0.75'), // 105 / 140 + max: parseUnits('1000'), + }, +} + +export const ilks: Ilk[] = [ilkToETH, ilkToDAI, ilkToUSDC] + +export const oracleSources: OracleSource[] = [ + { + baseId: USDC, + baseAddress: assets.getOrThrow(USDC)!, + quoteId: ZENBULL, + quoteAddress: assets.getOrThrow(ZENBULL)!, + sourceAddress: protocol().getOrThrow(ZENBULL_ORACLE)! as string, + }, +] + +export const oraclePaths: OraclePath[] = [ + { + baseId: ZENBULL, + quoteId: DAI, + path: [USDC], + }, + { + baseId: ZENBULL, + quoteId: ETH, + path: [USDC], + }, +] + +export const ethSeries: Series[] = [ + { + seriesId: FYETH2303, + fyToken: { assetId: FYETH2303, address: fyTokens.get(FYETH2303) as string }, + pool: zenbull, + chiOracle: '', + ilks: [ilkToETH], + }, + { + seriesId: FYETH2306, + fyToken: { assetId: FYETH2306, address: fyTokens.get(FYETH2306) as string }, + pool: zenbull, + chiOracle: '', + ilks: [ilkToETH], + }, +] + +export const daiSeries: Series[] = [ + { + seriesId: FYDAI2303, + fyToken: { assetId: FYDAI2303, address: fyTokens.get(FYDAI2303) as string }, + pool: zenbull, + chiOracle: '', + ilks: [ilkToDAI], + }, + { + seriesId: FYDAI2306, + fyToken: { assetId: FYDAI2306, address: fyTokens.get(FYDAI2306) as string }, + pool: zenbull, + chiOracle: '', + ilks: [ilkToDAI], + }, +] + +export const usdcSeries: Series[] = [ + { + seriesId: FYUSDC2303, + fyToken: { assetId: FYUSDC2303, address: fyTokens.get(FYUSDC2303) as string }, + pool: zenbull, + chiOracle: '', + ilks: [ilkToUSDC], + }, + { + seriesId: FYUSDC2306, + fyToken: { assetId: FYUSDC2306, address: fyTokens.get(FYUSDC2306) as string }, + pool: zenbull, + chiOracle: '', + ilks: [ilkToUSDC], + }, +] + +export const newSeries: Series[] = [...ethSeries, ...daiSeries, ...usdcSeries] diff --git a/scripts/governance/base.mainnet.config.ts b/scripts/governance/base.mainnet.config.ts index 31482be90..9fe93c735 100644 --- a/scripts/governance/base.mainnet.config.ts +++ b/scripts/governance/base.mainnet.config.ts @@ -22,6 +22,8 @@ import { YVDAI, YVUSDC, USDT, + RETH, + ZENBULL, } from '../../shared/constants' export const external = readAddressMappingIfExists('external.json') @@ -61,4 +63,6 @@ export const whales: Map = new Map([ [YSFRAX6MMSASSET, '0x430e076e5292e0028a0a17a00a65c43e6ee7fb91'], [YSFRAX6MJDASSET, '0x3b870db67a45611cf4723d44487eaf398fac51e3'], [CRAB, '0xa1cab67a4383312718a5799eaa127906e9d4b19e'], + [RETH, '0x7c5aaa2a20b01df027ad032f7a768ac015e77b86'], + [ZENBULL, '0xaae102ca930508e6da30924bf0374f0f247729d5'], ]) diff --git a/scripts/governance/confTypes.ts b/scripts/governance/confTypes.ts index ff0bae034..da7d88192 100644 --- a/scripts/governance/confTypes.ts +++ b/scripts/governance/confTypes.ts @@ -73,7 +73,7 @@ export interface Ilk { export interface Series { seriesId: string - base: Asset + base?: Asset fyToken: Asset chiOracle: string pool: Asset diff --git a/shared/constants.ts b/shared/constants.ts index 56a6599d5..b8949d162 100644 --- a/shared/constants.ts +++ b/shared/constants.ts @@ -152,6 +152,8 @@ export const CRAB = stringToBytes6('38') export const OSQTH = stringToBytes6('39') export const USDT = '0x30A000000000' export const EUSDT = '0xE0A014000000' +export const RETH = '0xE03016000000' +export const ZENBULL = '0xE03017000000' export const TIMELOCK = 'timelock' export const CLOAK = 'cloak' @@ -179,6 +181,8 @@ export const IDENTITY = 'identityOracle' export const POOL_ORACLE = 'poolOracle' export const YIELD_SPACE_MULTI_ORACLE = 'yieldSpaceMultiOracle' export const CRAB_ORACLE = 'crabOracle' +export const RETH_ORACLE = 'rethOracle' +export const ZENBULL_ORACLE = 'zenBullOracle' export const CONTANGO = 'contango' export const CONTANGO_WITCH = 'contangoWitch' export const CONTANGO_CAULDRON = 'contangoCauldron' @@ -197,6 +201,7 @@ export const NOTIONAL_PROVIDER = '12' export const CONVEX_PROVIDER = '13' export const EULER_PROVIDER = '14' export const OPYN_PROVIDER = '15' +export const ROCKET_PROVIDER = '16' export const EODEC21 = 1640919600 // Friday, Dec 31, 2021 3:00:00 AM GMT+00:00 export const EOMAR22 = 1648177200 // Friday, Mar 25, 2022 3:00:00 AM GMT+00:00 @@ -287,6 +292,7 @@ export const DISPLAY_NAMES = new Map([ [EDAI, 'EDAI'], [EUSDC, 'EUSDC'], [EFRAX, 'EFRAX'], + [RETH, 'RETH'], [FDAI2203, 'FDAI2203'], [FUSDC2203, 'FUSDC2203'], [FDAI2206, 'FDAI2206'], diff --git a/shared/helpers.ts b/shared/helpers.ts index 6eaa025b5..e68052078 100644 --- a/shared/helpers.ts +++ b/shared/helpers.ts @@ -39,6 +39,14 @@ export const propose = async ( proposal: Array<{ target: string; data: string }>, developer?: string ) => { + // Remove duplicate proposal if any + proposal = proposal.reduce((accumulator, current) => { + if (!accumulator.some((item) => item.target === current.target && item.data === current.data)) { + accumulator.push(current) + } + return accumulator + }, []) + const signerAcc = await getOwnerOrImpersonate(developer as string, ethers.utils.parseEther('1')) const proposalHash = await timelock.hash(proposal) console.log(`Proposal: ${proposalHash}`) @@ -146,6 +154,10 @@ export function bytesToBytes32(bytes: string): string { return stringToBytes32(getName(bytes)) } +export function bytes6ToBytes32(x: string): string { + return x + '00'.repeat(26) +} + export function flattenContractMap(map: Map): Map { const flat = new Map() map.forEach((value: any, key: string) => { diff --git a/shared/standardBorrowingTest.ts b/shared/standardBorrowingTest.ts new file mode 100644 index 000000000..0332d6df2 --- /dev/null +++ b/shared/standardBorrowingTest.ts @@ -0,0 +1,68 @@ +import { ethers } from 'hardhat' +import { BigNumber } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { impersonate, getOwnerOrImpersonate, bytes6ToBytes32 } from '../shared/helpers' +import { FYToken, ERC20__factory, Ladle__factory, Cauldron__factory, IOracle__factory } from '../typechain' +import { CAULDRON, LADLE, WAD } from '../shared/constants' +const { developer, newSeries, assets, whales, protocol } = require(process.env.CONF as string) + +/** + * @dev This script tests borrowing + */ +;(async () => { + let ownerAcc = await getOwnerOrImpersonate(developer, WAD) + let whaleAcc: SignerWithAddress + + const cauldron = Cauldron__factory.connect(protocol().getOrThrow(CAULDRON)!, ownerAcc) + const ladle = Ladle__factory.connect(protocol().getOrThrow(LADLE)!, ownerAcc) + + let oracle + for (let seri of newSeries) { + for (const ilk of seri.ilks) { + const collateral = ERC20__factory.connect(assets.get(ilk.ilkId)!, ownerAcc) + + oracle = IOracle__factory.connect(ilk.collateralization.oracle, ownerAcc) + + whaleAcc = await impersonate(whales.get(ilk.ilkId) as string, WAD.mul(10)) + console.log(`series: ${seri.seriesId}`) + console.log(`ilk.ilkId: ${ilk.ilkId}`) + const series = await cauldron.series(seri.seriesId) + const fyToken = (await ethers.getContractAt('FYToken', series.fyToken, ownerAcc)) as unknown as FYToken + const dust = (await cauldron.debt(series.baseId, ilk.ilkId)).min + + const ratio = (await cauldron.spotOracles(series.baseId, ilk.ilkId)).ratio + var borrowed = BigNumber.from(10) + .pow(await fyToken.decimals()) + .mul(dust) + const posted = (await oracle.peek(bytes6ToBytes32(ilk.baseId), bytes6ToBytes32(ilk.ilkId), borrowed))[0] + .mul(ratio) + .div(1000000) + .mul(101) + .div(100) + const collateralBalanceBefore = await collateral.balanceOf(whaleAcc.address) + // Build vault + let data = await (await ladle.connect(whaleAcc).build(seri.seriesId, ilk.ilkId, 0)).wait() + const vaultId = data.logs[0].topics[1].slice(0, 26) + console.log(`vault: ${vaultId}`) + + var name = await fyToken.callStatic.name() + // Post collateral and borrow + const collateralJoinAddress = await ladle.joins(ilk.ilkId) + console.log(`posting ${posted} ilk.ilkId out of ${await collateral.balanceOf(whaleAcc.address)}`) + await collateral.connect(whaleAcc).transfer(collateralJoinAddress, posted) + console.log(`borrowing ${borrowed} ${name}`) + await ladle.connect(whaleAcc).pour(vaultId, whaleAcc.address, posted, borrowed) + console.log(`posted and borrowed`) + + if ((await cauldron.balances(vaultId)).art.toString() !== borrowed.toString()) throw 'art mismatch' + if ((await cauldron.balances(vaultId)).ink.toString() !== posted.toString()) throw 'ink mismatch' + + await fyToken.connect(whaleAcc).transfer(fyToken.address, borrowed) + console.log(`repaying ${borrowed} ${name} and withdrawing ${posted} ilk.ilkId`) + await ladle.connect(whaleAcc).pour(vaultId, whaleAcc.address, posted.mul(-1), borrowed.mul(-1)) + console.log(`repaid and withdrawn`) + if ((await collateral.balanceOf(whaleAcc.address)).toString() !== collateralBalanceBefore.toString()) + throw 'balance mismatch' + } + } +})()