-
Notifications
You must be signed in to change notification settings - Fork 83
/
deployFeeders.ts
223 lines (188 loc) · 11.3 KB
/
deployFeeders.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
import "ts-node/register"
import "tsconfig-paths/register"
import { task, types } from "hardhat/config"
import {
FeederPool__factory,
CompoundIntegration__factory,
CompoundIntegration,
AlchemixIntegration,
AlchemixIntegration__factory,
FeederWrapper__factory,
} from "types/generated"
import { simpleToExactAmount } from "@utils/math"
import { ALCX, alUSD, BUSD, CREAM, cyMUSD, GUSD, mUSD, tokens } from "./utils/tokens"
import { deployContract, logTxDetails } from "./utils/deploy-utils"
import { getSigner } from "./utils/signerFactory"
import { deployFeederPool, deployVault, FeederData, VaultData } from "./utils/feederUtils"
import { getChain, getChainAddress, resolveToken } from "./utils/networkAddressFactory"
task("deployFeederPool", "Deploy Feeder Pool")
.addParam("masset", "Token symbol of mAsset. eg mUSD", "mUSD", types.string)
.addParam("fasset", "Token symbol of Feeder Pool asset. eg GUSD, WBTC, PFRAX for Polygon", "alUSD", types.string)
.addOptionalParam("a", "Amplitude coefficient (A)", 100, types.int)
.addOptionalParam("min", "Minimum asset weight of the basket as a percentage. eg 10 for 10% of the basket.", 10, types.int)
.addOptionalParam("max", "Maximum asset weight of the basket as a percentage. eg 90 for 90% of the basket.", 90, types.int)
.addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", types.string)
.setAction(async (taskArgs, hre) => {
const signer = await getSigner(hre, taskArgs.speed)
const chain = getChain(hre)
const mAsset = resolveToken(taskArgs.masset, chain)
const fAsset = resolveToken(taskArgs.fasset, chain)
if (taskArgs.a < 10 || taskArgs.min > 5000) throw Error(`Invalid amplitude coefficient (A) ${taskArgs.a}`)
if (taskArgs.min < 0 || taskArgs.min > 50) throw Error(`Invalid min limit ${taskArgs.min}`)
if (taskArgs.max < 50 || taskArgs.max > 100) throw Error(`Invalid max limit ${taskArgs.min}`)
const poolData: FeederData = {
mAsset,
fAsset,
name: `${mAsset.symbol}/${fAsset.symbol} Feeder Pool`,
symbol: `fP${mAsset.symbol}/${fAsset.symbol}`,
config: {
a: taskArgs.a,
limits: {
min: simpleToExactAmount(taskArgs.min, 16),
max: simpleToExactAmount(taskArgs.max, 16),
},
},
}
// Deploy Feeder Pool
await deployFeederPool(signer, poolData, hre)
})
task("deployNonPeggedFeederPool", "Deploy Non Pegged Feeder Pool")
.addParam("masset", "Token symbol of mAsset. eg mUSD or PmUSD for Polygon", "mUSD", types.string)
.addParam("fasset", "Token symbol of Feeder Pool asset. eg GUSD, WBTC, PFRAX for Polygon", "alUSD", types.string)
.addOptionalParam("a", "Amplitude coefficient (A)", 100, types.int)
.addOptionalParam("min", "Minimum asset weight of the basket as a percentage. eg 10 for 10% of the basket.", 10, types.int)
.addOptionalParam("max", "Maximum asset weight of the basket as a percentage. eg 90 for 90% of the basket.", 90, types.int)
.addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", types.string)
.setAction(async (taskArgs, hre) => {
const signer = await getSigner(hre, taskArgs.speed)
const chain = getChain(hre)
const mAsset = resolveToken(taskArgs.masset, chain)
const fAsset = resolveToken(taskArgs.fasset, chain)
if (taskArgs.a < 10 || taskArgs.min > 5000) throw Error(`Invalid amplitude coefficient (A) ${taskArgs.a}`)
if (taskArgs.min < 0 || taskArgs.min > 50) throw Error(`Invalid min limit ${taskArgs.min}`)
if (taskArgs.max < 50 || taskArgs.max > 100) throw Error(`Invalid max limit ${taskArgs.min}`)
if (!fAsset.priceGetter) throw Error(`Token ${fAsset.symbol} does not have a priceGetter`)
const poolData: FeederData = {
mAsset,
fAsset,
fAssetRedemptionPriceGetter: fAsset.priceGetter,
name: `${mAsset.symbol}/${fAsset.symbol} Feeder Pool`,
symbol: `fP${mAsset.symbol}/${fAsset.symbol}`,
config: {
a: taskArgs.a,
limits: {
min: simpleToExactAmount(taskArgs.min, 16),
max: simpleToExactAmount(taskArgs.max, 16),
},
},
}
// Deploy Feeder Pool
await deployFeederPool(signer, poolData, hre)
})
task("deployAlcxInt", "Deploy Alchemix integration contract for alUSD Feeder Pool")
.addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", types.string)
.setAction(async (taskArgs, hre) => {
const signer = await getSigner(hre, taskArgs.speed)
const chain = getChain(hre)
const nexusAddress = getChainAddress("Nexus", chain)
const alchemixStakingPoolsAddress = getChainAddress("AlchemixStakingPool", chain)
const alchemixIntegration = await deployContract<AlchemixIntegration>(
new AlchemixIntegration__factory(signer),
"Alchemix alUSD Integration",
[nexusAddress, alUSD.feederPool, ALCX.address, alchemixStakingPoolsAddress, alUSD.address],
)
const tx = await alchemixIntegration.initialize()
logTxDetails(tx, "initialize Alchemix integration")
const fp = FeederPool__factory.connect(alUSD.feederPool, signer)
const migrateData = fp.interface.encodeFunctionData("migrateBassets", [[alUSD.address], alchemixIntegration.address])
console.log(`migrateBassets data:\n${migrateData}`)
})
task("deployVault", "Deploy Feeder Pool with boosted dual vault")
.addParam("name", "Token name of the vault. eg mUSD/alUSD fPool Vault", undefined, types.string)
.addParam("symbol", "Token symbol of the vault. eg v-fPmUSD/alUSD", undefined, types.string)
.addParam("boosted", "Rewards are boosted by staked MTA (vMTA)", undefined, types.boolean)
.addParam(
"stakingToken",
"Symbol of token that is being staked. Feeder Pool is just the fAsset. eg mUSD, MTA, GUSD, alUSD",
undefined,
types.string,
)
.addOptionalParam("rewardToken", "Token symbol of reward. eg MTA", "MTA", types.string)
.addOptionalParam("dualRewardToken", "Token symbol of second reward. eg WMATIC, ALCX, QI", undefined, types.string)
.addOptionalParam("price", "Price coefficient is the value of the mAsset in USD. eg mUSD/USD = 1, mBTC/USD", 1, types.int)
.addOptionalParam("boostCoeff", "Boost coefficient", 9, types.int)
.addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", types.string)
.setAction(async (taskArgs, hre) => {
const chain = getChain(hre)
if (taskArgs.name?.length < 4) throw Error(`Invalid token name ${taskArgs.name}`)
if (taskArgs.symbol?.length <= 0 || taskArgs.symbol?.length > 16) throw Error(`Invalid token symbol ${taskArgs.name}`)
if (taskArgs.boosted === undefined) throw Error(`Invalid boolean boost ${taskArgs.boosted}`)
const stakingToken = tokens.find((t) => t.symbol === taskArgs.stakingToken && t.chain === chain)
if (!stakingToken) throw Error(`Could not find staking token with symbol ${taskArgs.stakingToken}`)
// Staking Token is for Feeder Pool, Savings Vault or the token itself. eg
// alUSD will stake feeder pool in a v-fPmUSD/alUSD vault
// mUSD will stake savings vault in a v-imUSD vault
// MTA will stake MTA in a v-MTA vault
const stakingTokenAddress = stakingToken.feederPool || stakingToken.savings || stakingToken.address
const rewardToken = tokens.find((t) => t.symbol === taskArgs.rewardToken && t.chain === chain)
if (!rewardToken) throw Error(`Could not find reward token with symbol ${taskArgs.rewardToken}`)
if (taskArgs.price < 0 || taskArgs.price >= simpleToExactAmount(1)) throw Error(`Invalid price coefficient ${taskArgs.price}`)
if (taskArgs.boostCoeff < 1 || taskArgs.boostCoeff > 10) throw Error(`Invalid boost coefficient ${taskArgs.boostCoeff}`)
const dualRewardToken = tokens.find((t) => t.symbol === taskArgs.dualRewardToken)
const vaultData: VaultData = {
boosted: taskArgs.boosted,
name: taskArgs.name,
symbol: taskArgs.symbol,
priceCoeff: simpleToExactAmount(taskArgs.price),
stakingToken: stakingTokenAddress,
rewardToken: rewardToken.address,
dualRewardToken: dualRewardToken?.address,
boostCoeff: taskArgs.boostCoeff,
}
await deployVault(hre, vaultData)
})
task("FeederWrapper-deploy", "Deploy a new FeederWrapper").setAction(async (taskArgs, hre) => {
const deployer = await getSigner(hre)
await deployContract(new FeederWrapper__factory(deployer), "FeederWrapper")
})
task("deployIronBank", "Deploys mUSD Iron Bank (CREAM) integration contracts for GUSD and BUSD Feeder Pools")
.addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", types.string)
.setAction(async (taskArgs, hre) => {
const signer = await getSigner(hre, taskArgs.speed)
const chain = getChain(hre)
const nexusAddress = getChainAddress("Nexus", chain)
// CREAM's ABI is the same as Compound so can use the CompoundIntegration contract
const gusdIntegration = await deployContract<CompoundIntegration>(
new CompoundIntegration__factory(signer),
"CREAM Integration for GUSD FP",
[nexusAddress, GUSD.feederPool, CREAM.address],
)
let tx = await gusdIntegration.initialize([mUSD.address], [cyMUSD.address])
await logTxDetails(tx, "initialize GUSD Iron Bank integration")
const busdIntegration = await deployContract<CompoundIntegration>(
new CompoundIntegration__factory(signer),
"CREAM Integration for BUSD FP",
[nexusAddress, BUSD.feederPool, CREAM.address],
)
tx = await busdIntegration.initialize([mUSD.address], [cyMUSD.address])
await logTxDetails(tx, "initialize BUSD Iron Bank integration")
// This will be done via the delayedProxyAdmin on mainnet
// Governor approves Liquidator to spend the reward (CREAM) token
const approveRewardTokenData = await gusdIntegration.interface.encodeFunctionData("approveRewardToken")
console.log(`\napproveRewardToken data for GUSD and BUSD: ${approveRewardTokenData}`)
const gudsFp = FeederPool__factory.connect(GUSD.address, signer)
const gusdMigrateBassetsData = await gudsFp.interface.encodeFunctionData("migrateBassets", [
[mUSD.address],
gusdIntegration.address,
])
console.log(`GUSD Feeder Pool migrateBassets tx data: ${gusdMigrateBassetsData}`)
const budsFp = FeederPool__factory.connect(BUSD.address, signer)
const busdMigrateBassetsData = await budsFp.interface.encodeFunctionData("migrateBassets", [
[mUSD.address],
busdIntegration.address,
])
console.log(`BUSD Feeder Pool migrateBassets tx data: ${busdMigrateBassetsData}`)
})
module.exports = {}