@oldzeppelin/contract 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docker/Dockerfile +17 -0
- package/.dockerignore +7 -0
- package/.env.sample +24 -0
- package/.gitlab-ci.yml +51 -0
- package/.gitmodules +15 -0
- package/.prettierrc +10 -0
- package/.solcover.js +4 -0
- package/.vscode/settings.json +23 -0
- package/LICENSE.MD +51 -0
- package/README.md +135 -0
- package/contracts/arbitrum/contracts/controllers/UniswapV2ControllerArbitrum.sol +37 -0
- package/contracts/arbitrum/contracts/controllers/UniswapV3ControllerArbitrum.sol +46 -0
- package/contracts/arbitrum/contracts/oracle/PriceOracleArbitrum.sol +51 -0
- package/contracts/main/contracts/controllers/Controller.sol +61 -0
- package/contracts/main/contracts/controllers/IController.sol +81 -0
- package/contracts/main/contracts/controllers/OneInchV5Controller.sol +332 -0
- package/contracts/main/contracts/controllers/UnoswapV2Controller.sol +789 -0
- package/contracts/main/contracts/controllers/UnoswapV3Controller.sol +1018 -0
- package/contracts/main/contracts/core/CoreWhitelist.sol +192 -0
- package/contracts/main/contracts/core/ICoreWhitelist.sol +92 -0
- package/contracts/main/contracts/core/IUFarmCore.sol +95 -0
- package/contracts/main/contracts/core/UFarmCore.sol +402 -0
- package/contracts/main/contracts/fund/FundFactory.sol +59 -0
- package/contracts/main/contracts/fund/IUFarmFund.sol +68 -0
- package/contracts/main/contracts/fund/UFarmFund.sol +504 -0
- package/contracts/main/contracts/oracle/ChainlinkedOracle.sol +71 -0
- package/contracts/main/contracts/oracle/IChainlinkAggregator.sol +18 -0
- package/contracts/main/contracts/oracle/IPriceOracle.sol +55 -0
- package/contracts/main/contracts/oracle/PriceOracle.sol +20 -0
- package/contracts/main/contracts/oracle/PriceOracleCore.sol +212 -0
- package/contracts/main/contracts/oracle/WstETHOracle.sol +64 -0
- package/contracts/main/contracts/permissions/Permissions.sol +54 -0
- package/contracts/main/contracts/permissions/UFarmPermissionsModel.sol +136 -0
- package/contracts/main/contracts/pool/IPoolAdmin.sol +57 -0
- package/contracts/main/contracts/pool/IUFarmPool.sol +304 -0
- package/contracts/main/contracts/pool/PerformanceFeeLib.sol +81 -0
- package/contracts/main/contracts/pool/PoolAdmin.sol +437 -0
- package/contracts/main/contracts/pool/PoolFactory.sol +74 -0
- package/contracts/main/contracts/pool/PoolWhitelist.sol +70 -0
- package/contracts/main/contracts/pool/UFarmPool.sol +959 -0
- package/contracts/main/shared/AssetController.sol +194 -0
- package/contracts/main/shared/ECDSARecover.sol +91 -0
- package/contracts/main/shared/NZGuard.sol +99 -0
- package/contracts/main/shared/SafeOPS.sol +128 -0
- package/contracts/main/shared/UFarmCoreLink.sol +83 -0
- package/contracts/main/shared/UFarmErrors.sol +16 -0
- package/contracts/main/shared/UFarmMathLib.sol +80 -0
- package/contracts/main/shared/UFarmOwnableUUPS.sol +59 -0
- package/contracts/main/shared/UFarmOwnableUUPSBeacon.sol +34 -0
- package/contracts/test/Block.sol +15 -0
- package/contracts/test/InchSwapTestProxy.sol +292 -0
- package/contracts/test/MockPoolAdmin.sol +8 -0
- package/contracts/test/MockUFarmPool.sol +8 -0
- package/contracts/test/MockV3wstETHstETHAgg.sol +128 -0
- package/contracts/test/MockedWETH9.sol +72 -0
- package/contracts/test/OneInchToUFarmTestEnv.sol +466 -0
- package/contracts/test/StableCoin.sol +25 -0
- package/contracts/test/UFarmMockSequencerUptimeFeed.sol +44 -0
- package/contracts/test/UFarmMockV3Aggregator.sol +145 -0
- package/contracts/test/UUPSBlock.sol +19 -0
- package/contracts/test/ufarmLocal/MulticallV3.sol +220 -0
- package/contracts/test/ufarmLocal/controllers/UniswapV2ControllerUFarm.sol +27 -0
- package/contracts/test/ufarmLocal/controllers/UniswapV3ControllerUFarm.sol +43 -0
- package/deploy/100_test_env_setup.ts +483 -0
- package/deploy/20_deploy_uniV2.ts +48 -0
- package/deploy/21_create_pairs_uniV2.ts +149 -0
- package/deploy/22_deploy_mocked_aggregators.ts +123 -0
- package/deploy/22_deploy_wsteth_oracle.ts +65 -0
- package/deploy/23_deploy_uniV3.ts +80 -0
- package/deploy/24_create_pairs_uniV3.ts +140 -0
- package/deploy/25_deploy_oneInch.ts +38 -0
- package/deploy/2_deploy_multicall.ts +34 -0
- package/deploy/30_deploy_price_oracle.ts +33 -0
- package/deploy/3_deploy_lido.ts +114 -0
- package/deploy/40_deploy_pool_beacon.ts +19 -0
- package/deploy/41_deploy_poolAdmin_beacon.ts +19 -0
- package/deploy/42_deploy_ufarmcore.ts +29 -0
- package/deploy/43_deploy_fund_beacon.ts +19 -0
- package/deploy/4_deploy_tokens.ts +76 -0
- package/deploy/50_deploy_poolFactory.ts +35 -0
- package/deploy/51_deploy_fundFactory.ts +29 -0
- package/deploy/60_init_contracts.ts +101 -0
- package/deploy/61_whitelist_tokens.ts +18 -0
- package/deploy/70_deploy_uniV2Controller.ts +70 -0
- package/deploy/71_deploy_uniV3Controller.ts +67 -0
- package/deploy/72_deploy_oneInchController.ts +25 -0
- package/deploy/79_whitelist_controllers.ts +125 -0
- package/deploy/ufarm/arbitrum/1_prepare_env.ts +82 -0
- package/deploy/ufarm/arbitrum/2_deploy_ufarm.ts +178 -0
- package/deploy/ufarm/arbitrum-sepolia/1000_prepare_arb_sepolia_env.ts +308 -0
- package/deploy-config.json +112 -0
- package/deploy-data/oracles.csv +32 -0
- package/deploy-data/protocols.csv +10 -0
- package/deploy-data/tokens.csv +32 -0
- package/docker-compose.yml +67 -0
- package/hardhat.config.ts +449 -0
- package/index.js +93 -0
- package/package.json +82 -0
- package/scripts/_deploy_helpers.ts +992 -0
- package/scripts/_deploy_network_options.ts +49 -0
- package/scripts/activatePool.ts +51 -0
- package/scripts/createPool.ts +62 -0
- package/scripts/deploy_1inch_proxy.ts +98 -0
- package/scripts/pool-data.ts +420 -0
- package/scripts/post-deploy.sh +24 -0
- package/scripts/setUniV2Rate.ts +252 -0
- package/scripts/swapOneInchV5.ts +94 -0
- package/scripts/swapUniswapV2.ts +65 -0
- package/scripts/swapUniswapV3.ts +71 -0
- package/scripts/test.ts +61 -0
- package/scripts/typings-copy-artifacts.ts +83 -0
- package/tasks/boostPool.ts +39 -0
- package/tasks/createFund.ts +44 -0
- package/tasks/deboostPool.ts +48 -0
- package/tasks/grantUFarmPermissions.ts +57 -0
- package/tasks/index.ts +7 -0
- package/tasks/mintUSDT.ts +62 -0
- package/test/Periphery.test.ts +640 -0
- package/test/PriceOracle.test.ts +82 -0
- package/test/TestCases.MD +109 -0
- package/test/UFarmCore.test.ts +331 -0
- package/test/UFarmFund.test.ts +406 -0
- package/test/UFarmPool.test.ts +4736 -0
- package/test/_fixtures.ts +783 -0
- package/test/_helpers.ts +2195 -0
- package/test/_oneInchTestData.ts +632 -0
- package/tsconfig.json +12 -0
@@ -0,0 +1,992 @@
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
2
|
+
|
3
|
+
import csv from 'csv-parser'
|
4
|
+
import fs from 'fs'
|
5
|
+
import {
|
6
|
+
ArtifactData,
|
7
|
+
DeployOptions,
|
8
|
+
DeployResult,
|
9
|
+
Deployment,
|
10
|
+
ExtendedArtifact,
|
11
|
+
} from 'hardhat-deploy/types'
|
12
|
+
import { HardhatRuntimeEnvironment, Network } from 'hardhat/types'
|
13
|
+
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
|
14
|
+
import {
|
15
|
+
DeployProxyOptions,
|
16
|
+
UpgradeProxyOptions,
|
17
|
+
DeployBeaconOptions,
|
18
|
+
UpgradeBeaconOptions,
|
19
|
+
} from '@openzeppelin/hardhat-upgrades/src/utils'
|
20
|
+
import { Signer, BigNumber, BaseContract, ContractFactory } from 'ethers'
|
21
|
+
import { BigNumberish } from '@ethersproject/bignumber'
|
22
|
+
import {
|
23
|
+
AggregatorV2V3Interface,
|
24
|
+
IERC20Metadata,
|
25
|
+
IUFarmPool,
|
26
|
+
UFarmCore,
|
27
|
+
UFarmFund,
|
28
|
+
UFarmFund__factory,
|
29
|
+
UFarmPool,
|
30
|
+
UFarmPool__factory,
|
31
|
+
UFarmOwnableUUPS,
|
32
|
+
} from '../typechain-types'
|
33
|
+
import {
|
34
|
+
AssetWithPriceFeed,
|
35
|
+
bigNumberToBits,
|
36
|
+
constants,
|
37
|
+
deployPool,
|
38
|
+
getEventFromTx,
|
39
|
+
getFieldsByValue,
|
40
|
+
MintableToken,
|
41
|
+
mintTokens,
|
42
|
+
PoolAndAdmin,
|
43
|
+
tokenToPriceFeedStruct,
|
44
|
+
} from '../test/_helpers'
|
45
|
+
import { ethers } from 'hardhat'
|
46
|
+
import { ADDRESS_ZERO } from '@uniswap/v3-sdk'
|
47
|
+
export type TokenData = {
|
48
|
+
name: string
|
49
|
+
rawName: string
|
50
|
+
symbol: string
|
51
|
+
decimals: number
|
52
|
+
}
|
53
|
+
|
54
|
+
export type NamedSigner = string
|
55
|
+
|
56
|
+
export type NamedDeployedOptions = DeployOptions & { deploymentName: string } & {
|
57
|
+
contract: string | ArtifactData
|
58
|
+
}
|
59
|
+
|
60
|
+
export interface TokenMetadata {
|
61
|
+
name: string
|
62
|
+
rawName: string
|
63
|
+
symbol: string
|
64
|
+
decimals: number
|
65
|
+
}
|
66
|
+
|
67
|
+
export interface ArbitrumOneAddr {
|
68
|
+
address_chain_42161: string
|
69
|
+
}
|
70
|
+
|
71
|
+
interface TokenTicker {
|
72
|
+
ticker: string
|
73
|
+
}
|
74
|
+
|
75
|
+
type OraclesRow = ArbitrumOneAddr & TokenTicker & {}
|
76
|
+
|
77
|
+
type TokensRow = ArbitrumOneAddr &
|
78
|
+
TokenTicker & {
|
79
|
+
name: string
|
80
|
+
decimals: number
|
81
|
+
}
|
82
|
+
|
83
|
+
enum RequiredProtocols {
|
84
|
+
UniswapV2Factory = 'UniswapV2Factory',
|
85
|
+
UniswapV2Router02 = 'UniswapV2Router02',
|
86
|
+
UniswapV3Factory = 'UniswapV3Factory',
|
87
|
+
SwapRouter = 'SwapRouter',
|
88
|
+
NonfungiblePositionManager = 'NonfungiblePositionManager',
|
89
|
+
QuoterV2 = 'QuoterV2',
|
90
|
+
AggregationRouterV5 = 'AggregationRouterV5',
|
91
|
+
Multicall3 = 'Multicall3',
|
92
|
+
LidoRateOracle = 'LidoRateOracle',
|
93
|
+
}
|
94
|
+
|
95
|
+
type ProtocolsRow = ArbitrumOneAddr & { name: string; abi: string }
|
96
|
+
|
97
|
+
enum DeployTags {
|
98
|
+
// External deployments
|
99
|
+
Tokens,
|
100
|
+
Lido,
|
101
|
+
Multicall3,
|
102
|
+
UniV2,
|
103
|
+
UniV2Pairs,
|
104
|
+
MockedAggregators,
|
105
|
+
UniV3,
|
106
|
+
UniV3Pairs,
|
107
|
+
OneInch,
|
108
|
+
// Internal deployments
|
109
|
+
WstETHOracle,
|
110
|
+
PriceOracle,
|
111
|
+
UFarmPool,
|
112
|
+
PoolAdmin,
|
113
|
+
UFarmCore,
|
114
|
+
UFarmFund,
|
115
|
+
PoolFactory,
|
116
|
+
FundFactory,
|
117
|
+
UniV2Controller,
|
118
|
+
UniV3Controller,
|
119
|
+
OneInchV5Controller,
|
120
|
+
// Actions
|
121
|
+
InitializeUFarm,
|
122
|
+
WhiteListTokens,
|
123
|
+
WhitelistControllers,
|
124
|
+
PrepareEnvARB,
|
125
|
+
ArbitrumENV,
|
126
|
+
TestEnv,
|
127
|
+
SepoliaEnv,
|
128
|
+
Update1inchArb,
|
129
|
+
}
|
130
|
+
|
131
|
+
export function getNewContractName(controllerName: string) {
|
132
|
+
return `${controllerName}_NEW`
|
133
|
+
}
|
134
|
+
|
135
|
+
enum NetworkTypes {
|
136
|
+
Arbitrum = 'arbitrum',
|
137
|
+
ArbitrumSepolia = 'arbitrumSepolia',
|
138
|
+
Dev = 'dev',
|
139
|
+
}
|
140
|
+
export function getNetworkType(network: Network) {
|
141
|
+
if (network.tags['arbitrum']) {
|
142
|
+
return NetworkTypes.Arbitrum
|
143
|
+
} else if (network.tags['arbitrumSepolia']) {
|
144
|
+
return NetworkTypes.ArbitrumSepolia
|
145
|
+
} else {
|
146
|
+
return NetworkTypes.Dev
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
export function _deployTags(tags: (keyof typeof DeployTags)[]): string[] {
|
151
|
+
if (tags.length === 0) {
|
152
|
+
return []
|
153
|
+
}
|
154
|
+
return tags.map((tag) => tag.toString())
|
155
|
+
}
|
156
|
+
|
157
|
+
async function readCSV<T>(path: string, filtr: (row: T) => boolean = () => true): Promise<T[]> {
|
158
|
+
try {
|
159
|
+
const parsed: T[] = []
|
160
|
+
console.log('Reading CSV file:', path)
|
161
|
+
|
162
|
+
await new Promise<void>((resolve, reject) => {
|
163
|
+
console.log('Reading CSV file...')
|
164
|
+
const stream = fs
|
165
|
+
.createReadStream(path, { encoding: 'utf8' })
|
166
|
+
.pipe(csv())
|
167
|
+
.on('data', (row: T) => {
|
168
|
+
// console.log(`push`)
|
169
|
+
parsed.push(row)
|
170
|
+
})
|
171
|
+
.on('end', () => {
|
172
|
+
resolve()
|
173
|
+
})
|
174
|
+
.on('error', (error: any) => {
|
175
|
+
console.error('Error processing CSV file:', error)
|
176
|
+
reject(error)
|
177
|
+
})
|
178
|
+
})
|
179
|
+
|
180
|
+
return parsed.filter(filtr)
|
181
|
+
} catch (e) {
|
182
|
+
throw new Error(`Error reading CSV file: ${e}`)
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
export const getPriceOracleContract = (network: Network) => {
|
187
|
+
switch (getNetworkType(network)) {
|
188
|
+
case 'arbitrum':
|
189
|
+
return {
|
190
|
+
contract: 'PriceOracleArbitrum',
|
191
|
+
args: [{ sequencerUptimeFeed: '0xFdB631F5EE196F0ed6FAa767959853A9F217697D' }],
|
192
|
+
initFunc: '__init__PriceOracleArbitrum',
|
193
|
+
}
|
194
|
+
break
|
195
|
+
default:
|
196
|
+
console.log('THIS IS NOT ARB')
|
197
|
+
return {
|
198
|
+
contract: 'PriceOracle',
|
199
|
+
args: [],
|
200
|
+
initFunc: '__init__PriceOracle',
|
201
|
+
}
|
202
|
+
break
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
export const updateFundPermissionsIfNotYet = async (
|
207
|
+
fund: UFarmFund,
|
208
|
+
fundMember: string,
|
209
|
+
permissions: BigNumberish,
|
210
|
+
) => {
|
211
|
+
const hasPermissions = await fund.hasPermissionsMask(fundMember, permissions)
|
212
|
+
if (!hasPermissions) {
|
213
|
+
await retryOperation(async () => {
|
214
|
+
await updateFundPermissions(fund, fundMember, permissions)
|
215
|
+
}, 3)
|
216
|
+
console.log(` - ${fundMember} permissions updated`)
|
217
|
+
} else {
|
218
|
+
console.log(` - ${fundMember} already has permissions in Fund(${fund.address})`)
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
export async function updateFundPermissions(
|
223
|
+
fundWithSigner: UFarmFund,
|
224
|
+
address: string,
|
225
|
+
permissions: BigNumberish,
|
226
|
+
) {
|
227
|
+
const receipt = await fundWithSigner.updatePermissions(address, permissions)
|
228
|
+
|
229
|
+
const permissionsString = getFieldsByValue(
|
230
|
+
constants.Fund.Permissions,
|
231
|
+
bigNumberToBits(BigNumber.from(permissions)),
|
232
|
+
).join(', ')
|
233
|
+
|
234
|
+
console.log(`` + `Addr: [${address}]\nPermissions: [${permissionsString}]\n-----------------`)
|
235
|
+
return receipt.wait()
|
236
|
+
}
|
237
|
+
|
238
|
+
export async function customSetTimeout(seconds: number): Promise<void> {
|
239
|
+
console.log(`Waiting ${seconds} seconds...`)
|
240
|
+
return new Promise<void>((resolve) => {
|
241
|
+
const milliseconds = seconds * 1000 // Convert seconds to milliseconds
|
242
|
+
setTimeout(() => {
|
243
|
+
resolve()
|
244
|
+
}, milliseconds)
|
245
|
+
})
|
246
|
+
}
|
247
|
+
|
248
|
+
export async function getPrefixedTokens(hre: HardhatRuntimeEnvironment) {
|
249
|
+
const deploy_constants = hre.testnetDeployConfig as {
|
250
|
+
tokens: {
|
251
|
+
testnet: Array<{
|
252
|
+
name: string
|
253
|
+
rawName: string
|
254
|
+
symbol: string
|
255
|
+
decimals: number
|
256
|
+
}>
|
257
|
+
}
|
258
|
+
}
|
259
|
+
let tokens: typeof deploy_constants.tokens.testnet = []
|
260
|
+
|
261
|
+
if (isTestnet(hre.network)) {
|
262
|
+
tokens = deploy_constants.tokens.testnet
|
263
|
+
} else {
|
264
|
+
const staticConfig = await getStaticConfig()
|
265
|
+
const pendingTokens = staticConfig.tokens
|
266
|
+
|
267
|
+
switch (getNetworkType(hre.network)) {
|
268
|
+
case 'arbitrum':
|
269
|
+
try {
|
270
|
+
const tokensToWhitelist = pendingTokens.filter(
|
271
|
+
(token) =>
|
272
|
+
!(token.ticker.toUpperCase() === 'STETH'),
|
273
|
+
)
|
274
|
+
for (let i = 0; i < tokensToWhitelist.length; i++) {
|
275
|
+
const token = tokensToWhitelist[i]
|
276
|
+
try {
|
277
|
+
const rawName = token.ticker.toUpperCase()
|
278
|
+
|
279
|
+
const contract = (await hre.ethers.getContractAt(
|
280
|
+
'@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol:IERC20Metadata',
|
281
|
+
token.address_chain_42161,
|
282
|
+
)) as IERC20Metadata
|
283
|
+
|
284
|
+
const [symbol, decimals] = await Promise.all([contract.symbol(), contract.decimals()])
|
285
|
+
const tokenData = {
|
286
|
+
name: token.name,
|
287
|
+
rawName: rawName,
|
288
|
+
symbol: symbol,
|
289
|
+
decimals: decimals,
|
290
|
+
}
|
291
|
+
console.log(`Fetched metadata for token ${token.name}:`, tokenData)
|
292
|
+
tokens.push(tokenData)
|
293
|
+
} catch (error) {
|
294
|
+
console.error(`Error fetching metadata for token ${token.name}:`, error)
|
295
|
+
throw error
|
296
|
+
}
|
297
|
+
await customSetTimeout(0.5)
|
298
|
+
}
|
299
|
+
} catch (error) {
|
300
|
+
console.error('Error fetching token metadata:', error)
|
301
|
+
throw error
|
302
|
+
}
|
303
|
+
break
|
304
|
+
default:
|
305
|
+
throw new Error(`This script is not meant to be run on this network: ${hre.network.name}`)
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
tokens.forEach((token) => {
|
310
|
+
token.name = `${token.rawName}`
|
311
|
+
token.symbol = `${token.rawName}`
|
312
|
+
})
|
313
|
+
|
314
|
+
return tokens
|
315
|
+
}
|
316
|
+
|
317
|
+
export async function getTokenDeployments(hre: HardhatRuntimeEnvironment) {
|
318
|
+
const tokenDeployments: Record<string, Deployment> = {}
|
319
|
+
|
320
|
+
const tokens = await getPrefixedTokens(hre)
|
321
|
+
for (let i = 0; i < tokens.length; i++) {
|
322
|
+
const token = tokens[i]
|
323
|
+
const savedDeployment = await hre.deployments.getOrNull(token.rawName)
|
324
|
+
if (savedDeployment) {
|
325
|
+
tokenDeployments[token.rawName] = savedDeployment
|
326
|
+
} else {
|
327
|
+
throw new Error(`No deployment found for ${token.name}`)
|
328
|
+
}
|
329
|
+
}
|
330
|
+
return tokenDeployments
|
331
|
+
}
|
332
|
+
|
333
|
+
export function isPublicTestnet(thisNetwork: Network) {
|
334
|
+
return thisNetwork.tags['public'] && thisNetwork.tags['test']
|
335
|
+
}
|
336
|
+
|
337
|
+
export function isMainnet(thisNetwork: Network) {
|
338
|
+
return thisNetwork.tags['mainnet']
|
339
|
+
}
|
340
|
+
|
341
|
+
export function isTestnet(thisNetwork: Network) {
|
342
|
+
return thisNetwork.tags['test']
|
343
|
+
}
|
344
|
+
|
345
|
+
async function getFactoryOfContract(
|
346
|
+
hre: HardhatRuntimeEnvironment,
|
347
|
+
contract: string | ArtifactData,
|
348
|
+
) {
|
349
|
+
if (typeof contract === 'string') {
|
350
|
+
return await hre.ethers.getContractFactory(contract)
|
351
|
+
} else {
|
352
|
+
return new ContractFactory(contract.abi, contract.bytecode)
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
async function getArtifactOfContract(
|
357
|
+
hre: HardhatRuntimeEnvironment,
|
358
|
+
contract: string | ArtifactData,
|
359
|
+
) {
|
360
|
+
if (typeof contract === 'string') {
|
361
|
+
return await hre.artifacts.readArtifact(contract)
|
362
|
+
} else {
|
363
|
+
console.error(`Unknown type ${typeof contract} for fetching artifcat`)
|
364
|
+
return null
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
export async function deployUpgradedContract(
|
369
|
+
hre: HardhatRuntimeEnvironment,
|
370
|
+
args: NamedDeployedOptions,
|
371
|
+
): Promise<
|
372
|
+
| { existingDeployment: Deployment; newDeployment: null }
|
373
|
+
| { existingDeployment: null; newDeployment: Deployment }
|
374
|
+
| { existingDeployment: Deployment; newDeployment: Deployment }
|
375
|
+
> {
|
376
|
+
const existingDeployment = await hre.deployments.getOrNull(args.deploymentName)
|
377
|
+
if (existingDeployment) {
|
378
|
+
const bytecode = await hre.ethers.provider.getCode(existingDeployment.address)
|
379
|
+
const artifact = await getArtifactOfContract(hre, args.contract)
|
380
|
+
const newContractName = getNewContractName(args.deploymentName)
|
381
|
+
|
382
|
+
if (bytecode === artifact?.deployedBytecode) {
|
383
|
+
console.log(`Contract ${args.deploymentName} already deployed.\n`)
|
384
|
+
return { existingDeployment, newDeployment: null }
|
385
|
+
} else {
|
386
|
+
const existingUpgradedController = await hre.deployments.getOrNull(newContractName)
|
387
|
+
if (existingUpgradedController) {
|
388
|
+
console.log(`Contract ${newContractName} already deployed.\n`)
|
389
|
+
return { existingDeployment, newDeployment: existingUpgradedController }
|
390
|
+
} else {
|
391
|
+
console.log(`Contract ${args.deploymentName} needs upgrade, deploying new version...`)
|
392
|
+
const newDeployment = await deployContract(hre, {
|
393
|
+
...args,
|
394
|
+
deploymentName: newContractName,
|
395
|
+
})
|
396
|
+
console.log(`Deployed ${newContractName} at ${newDeployment.address}`)
|
397
|
+
}
|
398
|
+
}
|
399
|
+
|
400
|
+
const newDeployment = await hre.deployments.getOrNull(newContractName)
|
401
|
+
return { existingDeployment, newDeployment }
|
402
|
+
} else {
|
403
|
+
console.log(`Deploying ${args.deploymentName}...`)
|
404
|
+
const newDeployment = await deployContract(hre, args)
|
405
|
+
console.log(`Deployed ${args.deploymentName} at ${newDeployment.address}`)
|
406
|
+
return { existingDeployment: null, newDeployment }
|
407
|
+
}
|
408
|
+
}
|
409
|
+
|
410
|
+
export async function replaceUpdatedContract(
|
411
|
+
hre: HardhatRuntimeEnvironment,
|
412
|
+
contractName: string,
|
413
|
+
): Promise<void> {
|
414
|
+
const newContractName = getNewContractName(contractName)
|
415
|
+
const oldContractDeployment = await hre.deployments.get(contractName)
|
416
|
+
const newContractDeployment = await hre.deployments.getOrNull(newContractName)
|
417
|
+
|
418
|
+
if (!newContractDeployment) {
|
419
|
+
return
|
420
|
+
}
|
421
|
+
|
422
|
+
try {
|
423
|
+
// Delete the old contract deployment
|
424
|
+
await hre.deployments.delete(contractName)
|
425
|
+
|
426
|
+
// Save the new contract deployment
|
427
|
+
await hre.deployments.save(contractName, newContractDeployment)
|
428
|
+
|
429
|
+
// Delete the temporary new contract deployment
|
430
|
+
await hre.deployments.delete(newContractName)
|
431
|
+
|
432
|
+
console.log(
|
433
|
+
`Replaced contract deployment of ${contractName} to newly deployed ${newContractDeployment.address} ...`,
|
434
|
+
)
|
435
|
+
} catch (error) {
|
436
|
+
// Revert the old contract deployment
|
437
|
+
await hre.deployments.save(contractName, oldContractDeployment)
|
438
|
+
}
|
439
|
+
}
|
440
|
+
|
441
|
+
export async function trySaveDeployment(
|
442
|
+
deploymentName: string,
|
443
|
+
args: NamedDeployedOptions & { address: string },
|
444
|
+
hre: HardhatRuntimeEnvironment,
|
445
|
+
): Promise<(ExtendedArtifact & { address: string }) | undefined> {
|
446
|
+
const attempts = 3
|
447
|
+
|
448
|
+
let deployment: (ExtendedArtifact & { address: string }) | undefined = {
|
449
|
+
abi: [''],
|
450
|
+
bytecode: '',
|
451
|
+
address: '',
|
452
|
+
}
|
453
|
+
|
454
|
+
for (let currentAttempt = 0; currentAttempt < attempts; currentAttempt++) {
|
455
|
+
try {
|
456
|
+
const contractHasCode = (await hre.ethers.provider.getCode(args.address)) !== '0x'
|
457
|
+
if (!contractHasCode) {
|
458
|
+
const errorText = `Contract ${deploymentName} at ${args.address} has no code`
|
459
|
+
console.error(errorText)
|
460
|
+
throw new Error(errorText)
|
461
|
+
}
|
462
|
+
if (typeof args.contract !== 'string') {
|
463
|
+
const errorText = `Contract is not a string, can't fetch ABI`
|
464
|
+
console.error(errorText)
|
465
|
+
throw new Error(errorText)
|
466
|
+
}
|
467
|
+
const contractArtifact = await hre.deployments.getExtendedArtifact(args.contract)
|
468
|
+
deployment = {
|
469
|
+
...contractArtifact,
|
470
|
+
address: args.address,
|
471
|
+
}
|
472
|
+
|
473
|
+
break
|
474
|
+
} catch (error) {
|
475
|
+
console.warn(`Could not save ${args.deploymentName} on attempt ${currentAttempt + 1}`)
|
476
|
+
await customSetTimeout(5 * currentAttempt + 1)
|
477
|
+
if (currentAttempt === attempts - 1) {
|
478
|
+
throw new Error(`Could not save ${args.deploymentName}` + `\n` + error)
|
479
|
+
}
|
480
|
+
}
|
481
|
+
}
|
482
|
+
if (!ethers.utils.isAddress(deployment.address)) {
|
483
|
+
throw new Error(`Could not save ${args.deploymentName}.`)
|
484
|
+
}
|
485
|
+
await hre.deployments.save(deploymentName, deployment)
|
486
|
+
console.log(`Saved ${deploymentName} at ${args.address}`)
|
487
|
+
|
488
|
+
return deployment
|
489
|
+
}
|
490
|
+
|
491
|
+
export const getStaticConfig = async () => {
|
492
|
+
const oracles = await readCSV(
|
493
|
+
'./deploy-data/oracles.csv',
|
494
|
+
(row: OraclesRow) => row.ticker !== '' && ethers.utils.isAddress(row.address_chain_42161),
|
495
|
+
)
|
496
|
+
const tokens = await readCSV(
|
497
|
+
'./deploy-data/tokens.csv',
|
498
|
+
(row: TokensRow) =>
|
499
|
+
row.name !== '' && row.decimals !== 0 && ethers.utils.isAddress(row.address_chain_42161),
|
500
|
+
)
|
501
|
+
const protocols = await readCSV<ProtocolsRow>(
|
502
|
+
'./deploy-data/protocols.csv',
|
503
|
+
(row: ProtocolsRow) =>
|
504
|
+
Object.values(RequiredProtocols).includes(row.name as RequiredProtocols) &&
|
505
|
+
ethers.utils.isAddress(row.address_chain_42161),
|
506
|
+
)
|
507
|
+
|
508
|
+
return {
|
509
|
+
oracles,
|
510
|
+
tokens,
|
511
|
+
protocols,
|
512
|
+
}
|
513
|
+
}
|
514
|
+
|
515
|
+
export async function tryDeploy(
|
516
|
+
deploymentName: string,
|
517
|
+
args: NamedDeployedOptions,
|
518
|
+
hre: HardhatRuntimeEnvironment,
|
519
|
+
) {
|
520
|
+
const attempts = 3
|
521
|
+
|
522
|
+
let deployment: DeployResult | undefined = undefined
|
523
|
+
|
524
|
+
for (let currentAttempt = 0; currentAttempt < attempts; currentAttempt++) {
|
525
|
+
try {
|
526
|
+
deployment = await hre.deployments.deploy(deploymentName, args)
|
527
|
+
break
|
528
|
+
} catch (error) {
|
529
|
+
console.warn(`Could not deploy ${args.deploymentName} on attempt ${currentAttempt + 1}`)
|
530
|
+
await customSetTimeout(5 * currentAttempt + 1)
|
531
|
+
if (currentAttempt === attempts - 1) {
|
532
|
+
throw new Error(`Could not deploy ${args.deploymentName}` + `\n` + error)
|
533
|
+
}
|
534
|
+
}
|
535
|
+
}
|
536
|
+
|
537
|
+
if (!deployment) {
|
538
|
+
throw new Error(`Could not deploy ${args.deploymentName}`)
|
539
|
+
}
|
540
|
+
|
541
|
+
return deployment
|
542
|
+
}
|
543
|
+
|
544
|
+
export async function retryOperation<T>(fn: () => Promise<T>, maxRetries: number): Promise<T> {
|
545
|
+
let lastError: Error | undefined
|
546
|
+
|
547
|
+
for (let retries = 1; retries < maxRetries + 1; retries++) {
|
548
|
+
try {
|
549
|
+
return await fn()
|
550
|
+
} catch (error) {
|
551
|
+
lastError = error as Error
|
552
|
+
console.error(`Retry ${retries}: Operation failed with error: ${lastError.message}`)
|
553
|
+
await customSetTimeout(5 * retries)
|
554
|
+
}
|
555
|
+
}
|
556
|
+
|
557
|
+
if (lastError) {
|
558
|
+
throw new Error(`Operation failed after max retries: ${lastError.message}`)
|
559
|
+
} else {
|
560
|
+
throw new Error(`Operation failed after max retries.`)
|
561
|
+
}
|
562
|
+
}
|
563
|
+
|
564
|
+
export async function runDeployTag(hre: HardhatRuntimeEnvironment, tag: keyof typeof DeployTags) {
|
565
|
+
await hre.run('deploy', { tags: tag.toString(), noCompile: true })
|
566
|
+
}
|
567
|
+
|
568
|
+
export async function getDeployerSigner(hre: HardhatRuntimeEnvironment) {
|
569
|
+
const { getNamedAccounts } = hre
|
570
|
+
const { deployer } = await getNamedAccounts()
|
571
|
+
return hre.ethers.getSigner(deployer)
|
572
|
+
}
|
573
|
+
|
574
|
+
export async function getSignerByName(hre: HardhatRuntimeEnvironment, name: string) {
|
575
|
+
const { getNamedAccounts } = hre
|
576
|
+
const { [name]: address } = await getNamedAccounts()
|
577
|
+
return hre.ethers.getSigner(address)
|
578
|
+
}
|
579
|
+
|
580
|
+
export async function getSignersByNames(hre: HardhatRuntimeEnvironment, names: string[]) {
|
581
|
+
const { getNamedAccounts } = hre
|
582
|
+
const namedAccounts = await getNamedAccounts()
|
583
|
+
const signers: SignerWithAddress[] = []
|
584
|
+
for (let i = 0; i < names.length; i++) {
|
585
|
+
const name = names[i]
|
586
|
+
const address = namedAccounts[name]
|
587
|
+
const signer = await hre.ethers.getSigner(address)
|
588
|
+
signers.push(signer)
|
589
|
+
}
|
590
|
+
return signers
|
591
|
+
}
|
592
|
+
|
593
|
+
export async function deployContract(hre: HardhatRuntimeEnvironment, args: NamedDeployedOptions) {
|
594
|
+
const deployment = await tryDeploy(args.deploymentName, args, hre)
|
595
|
+
// TODO: add return instance option
|
596
|
+
return deployment
|
597
|
+
}
|
598
|
+
|
599
|
+
export async function deployProxyContract(
|
600
|
+
hre: HardhatRuntimeEnvironment,
|
601
|
+
contractName: string,
|
602
|
+
signer: SignerWithAddress,
|
603
|
+
args?: unknown[] | undefined,
|
604
|
+
opts?: DeployProxyOptions | UpgradeProxyOptions | undefined,
|
605
|
+
deploymentName?: string,
|
606
|
+
): Promise<DeployResult> {
|
607
|
+
let instance : UFarmOwnableUUPS | null = null
|
608
|
+
|
609
|
+
const thisDeploymentName = deploymentName || contractName
|
610
|
+
const existingDeployment = await hre.deployments.getOrNull(thisDeploymentName)
|
611
|
+
const contractArtifact = await hre.artifacts.readArtifact(contractName)
|
612
|
+
const contractFactory = new hre.ethers.ContractFactory(
|
613
|
+
contractArtifact.abi,
|
614
|
+
contractArtifact.bytecode,
|
615
|
+
signer,
|
616
|
+
)
|
617
|
+
|
618
|
+
if (existingDeployment) {
|
619
|
+
const existingInstance = await hre.ethers.getContractAt('UFarmOwnableUUPS', existingDeployment.address)
|
620
|
+
const instanceOwner = await existingInstance.owner()
|
621
|
+
|
622
|
+
if (instanceOwner != ADDRESS_ZERO) {
|
623
|
+
console.log("Upgrade the proxy if needed")
|
624
|
+
instance = await retryOperation(async () => {
|
625
|
+
return await hre.upgrades.upgradeProxy(existingDeployment.address, contractFactory, opts)
|
626
|
+
}, 3) as UFarmOwnableUUPS
|
627
|
+
}
|
628
|
+
} else {
|
629
|
+
console.log("Deploy the proxy")
|
630
|
+
instance = await retryOperation(async () => {
|
631
|
+
return await hre.upgrades.deployProxy(contractFactory, args, opts)
|
632
|
+
}, 3) as UFarmOwnableUUPS
|
633
|
+
}
|
634
|
+
|
635
|
+
if (instance) {
|
636
|
+
const artifact = await hre.deployments.getExtendedArtifact(contractName)
|
637
|
+
|
638
|
+
const deployment = {
|
639
|
+
...artifact,
|
640
|
+
address: instance.address,
|
641
|
+
}
|
642
|
+
await hre.deployments.save(thisDeploymentName, deployment)
|
643
|
+
console.log(`Deployed/upgraded at ${instance.address} (owner ${await instance.owner()})`)
|
644
|
+
}
|
645
|
+
|
646
|
+
return { ...(await hre.deployments.get(thisDeploymentName)), newlyDeployed: !!instance }
|
647
|
+
}
|
648
|
+
|
649
|
+
export async function deployBeaconContract(
|
650
|
+
hre: HardhatRuntimeEnvironment,
|
651
|
+
contractName: string,
|
652
|
+
signer: SignerWithAddress,
|
653
|
+
opts?: DeployBeaconOptions | undefined,
|
654
|
+
): Promise<DeployResult> {
|
655
|
+
let instance = null
|
656
|
+
|
657
|
+
const existingDeployment = await hre.deployments.getOrNull(contractName)
|
658
|
+
const contractArtifact = await hre.artifacts.readArtifact(contractName)
|
659
|
+
const contractFactory = new hre.ethers.ContractFactory(
|
660
|
+
contractArtifact.abi,
|
661
|
+
contractArtifact.bytecode,
|
662
|
+
signer,
|
663
|
+
)
|
664
|
+
|
665
|
+
if (existingDeployment) {
|
666
|
+
const implAddress = hre.upgrades.beacon.getImplementationAddress(existingDeployment.address)
|
667
|
+
const bytecode = await hre.ethers.provider.getCode(implAddress)
|
668
|
+
|
669
|
+
if (contractFactory.bytecode !== bytecode) {
|
670
|
+
console.log(`Upgrading already existing contract ${contractName}`)
|
671
|
+
instance = await retryOperation(async () => {
|
672
|
+
return await hre.upgrades.upgradeBeacon(existingDeployment.address, contractFactory, opts)
|
673
|
+
}, 3)
|
674
|
+
}
|
675
|
+
} else {
|
676
|
+
console.log(`Deploying the new contract ${contractName}`)
|
677
|
+
instance = await retryOperation(async () => {
|
678
|
+
return await hre.upgrades.deployBeacon(contractFactory, opts)
|
679
|
+
}, 3)
|
680
|
+
}
|
681
|
+
|
682
|
+
if (instance) {
|
683
|
+
const artifact = await hre.deployments.getExtendedArtifact(contractName)
|
684
|
+
|
685
|
+
const deployment = {
|
686
|
+
...artifact,
|
687
|
+
address: instance.address,
|
688
|
+
}
|
689
|
+
await hre.deployments.save(contractName, deployment)
|
690
|
+
}
|
691
|
+
|
692
|
+
return { ...(await hre.deployments.get(contractName)), newlyDeployed: !!instance }
|
693
|
+
}
|
694
|
+
|
695
|
+
export function getInstanceFromDeployment<T extends BaseContract>(
|
696
|
+
hre: HardhatRuntimeEnvironment,
|
697
|
+
deployment: Deployment,
|
698
|
+
signer?: Signer | SignerWithAddress,
|
699
|
+
): T {
|
700
|
+
return new hre.ethers.Contract(
|
701
|
+
deployment.address,
|
702
|
+
deployment.abi,
|
703
|
+
signer || hre.ethers.provider,
|
704
|
+
) as T
|
705
|
+
}
|
706
|
+
|
707
|
+
export async function getInstanceOfDeployed<T extends BaseContract>(
|
708
|
+
hre: HardhatRuntimeEnvironment,
|
709
|
+
deploymentName: string,
|
710
|
+
signer?: Signer | SignerWithAddress,
|
711
|
+
): Promise<T> {
|
712
|
+
const deployment = await hre.deployments.get(deploymentName)
|
713
|
+
return getInstanceFromDeployment<T>(hre, deployment, signer)
|
714
|
+
}
|
715
|
+
|
716
|
+
export function mockedAggregatorName(tokenRawName: string, network: Network) {
|
717
|
+
if (tokenRawName === 'WSTETH') {
|
718
|
+
return 'WSTETHOracle'
|
719
|
+
}
|
720
|
+
return network.tags['mainnet']
|
721
|
+
? `${tokenRawName.toUpperCase()}USDAggregator`
|
722
|
+
: `Mocked${tokenRawName.toUpperCase()}USDAggregator`
|
723
|
+
}
|
724
|
+
|
725
|
+
export const getOrDeployPoolInstance = async (
|
726
|
+
poolName: string,
|
727
|
+
args: IUFarmPool.CreationSettingsStruct,
|
728
|
+
fund: UFarmFund,
|
729
|
+
hre: HardhatRuntimeEnvironment,
|
730
|
+
) => {
|
731
|
+
hre.network.name
|
732
|
+
const poolDeployment = await hre.deployments.getOrNull(poolName)
|
733
|
+
if (poolDeployment) {
|
734
|
+
const pool = await getInstanceFromDeployment<UFarmPool>(hre, poolDeployment, fund.signer)
|
735
|
+
const poolAdmin_addr = await pool.poolAdmin()
|
736
|
+
const poolAdmin = await hre.ethers.getContractAt('PoolAdmin', poolAdmin_addr, fund.signer)
|
737
|
+
console.log(`Pool ${poolName} already deployed at: ${pool.address}`)
|
738
|
+
return {
|
739
|
+
pool,
|
740
|
+
admin: poolAdmin,
|
741
|
+
} as PoolAndAdmin
|
742
|
+
} else {
|
743
|
+
const poolInstance = await deployPool(args, fund)
|
744
|
+
console.log(`Pool ${poolName} deployed at: ${poolInstance.pool.address}`)
|
745
|
+
await hre.deployments.save(poolName, {
|
746
|
+
address: poolInstance.pool.address,
|
747
|
+
abi: UFarmPool__factory.abi as unknown as any[],
|
748
|
+
})
|
749
|
+
return poolInstance
|
750
|
+
}
|
751
|
+
}
|
752
|
+
|
753
|
+
export const deployFund = async (
|
754
|
+
fundAdmin: string,
|
755
|
+
core_instance: UFarmCore,
|
756
|
+
hre: HardhatRuntimeEnvironment,
|
757
|
+
) => {
|
758
|
+
try {
|
759
|
+
const createFundEvent = await getEventFromTx(
|
760
|
+
core_instance.createFund(
|
761
|
+
fundAdmin,
|
762
|
+
hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes('anyValueFromBackend')),
|
763
|
+
),
|
764
|
+
core_instance,
|
765
|
+
'FundCreated',
|
766
|
+
)
|
767
|
+
|
768
|
+
const fundAddress = createFundEvent.args?.fund as string
|
769
|
+
const fund_instance = new hre.ethers.Contract(fundAddress, UFarmFund__factory.abi) as UFarmFund
|
770
|
+
|
771
|
+
return fund_instance
|
772
|
+
} catch (error) {
|
773
|
+
console.log(error)
|
774
|
+
throw new Error('Could not get fund instance')
|
775
|
+
}
|
776
|
+
}
|
777
|
+
|
778
|
+
export const deployOrGetFund = async (
|
779
|
+
fundName: string,
|
780
|
+
fundAdmin: string,
|
781
|
+
core_instance: UFarmCore,
|
782
|
+
hre: HardhatRuntimeEnvironment,
|
783
|
+
) => {
|
784
|
+
const fundDeployment = await hre.deployments.getOrNull(fundName)
|
785
|
+
if (fundDeployment) {
|
786
|
+
const fund = await getInstanceFromDeployment<UFarmFund>(hre, fundDeployment)
|
787
|
+
console.log(`Fund already deployed at: ${fund.address}`)
|
788
|
+
return fund
|
789
|
+
} else {
|
790
|
+
const fund_instance = await deployFund(fundAdmin, core_instance, hre)
|
791
|
+
|
792
|
+
console.log(`Fund deployed at: ${fund_instance.address}`)
|
793
|
+
await hre.deployments.save(fundName, {
|
794
|
+
address: fund_instance.address,
|
795
|
+
abi: UFarmFund__factory.abi as unknown as any[],
|
796
|
+
})
|
797
|
+
return fund_instance
|
798
|
+
}
|
799
|
+
}
|
800
|
+
|
801
|
+
export const activatePool = async (
|
802
|
+
poolAndAdmin: PoolAndAdmin,
|
803
|
+
tokenInstance: MintableToken,
|
804
|
+
signer: SignerWithAddress,
|
805
|
+
hre: HardhatRuntimeEnvironment,
|
806
|
+
) => {
|
807
|
+
const currentPoolStatus = await poolAndAdmin.pool.status()
|
808
|
+
const core_instance = await hre.ethers.getContractAt(
|
809
|
+
'UFarmCore',
|
810
|
+
await poolAndAdmin.pool.ufarmCore(),
|
811
|
+
)
|
812
|
+
const fund_instance = await hre.ethers.getContractAt(
|
813
|
+
'UFarmFund',
|
814
|
+
await poolAndAdmin.pool.ufarmFund(),
|
815
|
+
)
|
816
|
+
if (currentPoolStatus < constants.Pool.State.Active) {
|
817
|
+
const minimumFundDeposit = await core_instance.minimumFundDeposit()
|
818
|
+
const fundPoolBalance = await poolAndAdmin.pool.balanceOf(fund_instance.address)
|
819
|
+
if (fundPoolBalance.eq(0) && !minimumFundDeposit.eq(0)) {
|
820
|
+
const toDeposit = minimumFundDeposit.mul(2)
|
821
|
+
await mintTokens(tokenInstance, toDeposit, signer)
|
822
|
+
await (await tokenInstance.connect(signer).transfer(fund_instance.address, toDeposit)).wait()
|
823
|
+
await (await fund_instance.depositToPool(poolAndAdmin.pool.address, toDeposit)).wait()
|
824
|
+
}
|
825
|
+
console.log(`Current pool status is ${currentPoolStatus}, setting to Active`)
|
826
|
+
await (await poolAndAdmin.admin.changePoolStatus(constants.Pool.State.Active)).wait()
|
827
|
+
} else {
|
828
|
+
console.log(`Current pool (${poolAndAdmin.pool.address}) status is ${currentPoolStatus}`)
|
829
|
+
}
|
830
|
+
}
|
831
|
+
export const checkMinFundDep = async (core_instance: UFarmCore, minimumDeposit: BigNumber) => {
|
832
|
+
const minFundDep = await core_instance.minimumFundDeposit()
|
833
|
+
if (!minFundDep.eq(minimumDeposit)) {
|
834
|
+
console.log(`Current min fund deposit is ${minFundDep}, setting to ${minimumDeposit}`)
|
835
|
+
console.log(`Min fund deposit set to ${minimumDeposit}`)
|
836
|
+
return await (await core_instance.setMinimumFundDeposit(minimumDeposit)).wait()
|
837
|
+
} else {
|
838
|
+
console.log(`Current min fund deposit is ${minFundDep}`)
|
839
|
+
}
|
840
|
+
}
|
841
|
+
export const getTokenFeed = async <T extends AggregatorV2V3Interface>(
|
842
|
+
hre: HardhatRuntimeEnvironment,
|
843
|
+
tokenRawName: string,
|
844
|
+
) => {
|
845
|
+
const mockedAggregator = mockedAggregatorName(tokenRawName, hre.network)
|
846
|
+
const aggregatorDeployment = await hre.deployments.get(mockedAggregator)
|
847
|
+
const aggregatorInstance = getInstanceFromDeployment<T>(hre, aggregatorDeployment)
|
848
|
+
const tokenInstance = await getInstanceOfDeployed<IERC20Metadata>(hre, tokenRawName)
|
849
|
+
|
850
|
+
const [aggregatorDecimals, tokenDecimals] = await Promise.all([
|
851
|
+
aggregatorInstance.decimals(),
|
852
|
+
tokenInstance.decimals(),
|
853
|
+
])
|
854
|
+
|
855
|
+
return tokenToPriceFeedStruct(
|
856
|
+
tokenInstance.address,
|
857
|
+
tokenDecimals,
|
858
|
+
aggregatorInstance,
|
859
|
+
aggregatorDecimals,
|
860
|
+
)
|
861
|
+
}
|
862
|
+
|
863
|
+
export const getWstETHTokenFeed = async <T extends AggregatorV2V3Interface>(
|
864
|
+
hre: HardhatRuntimeEnvironment,
|
865
|
+
) => {
|
866
|
+
const wsteth_instance = await getInstanceOfDeployed<IERC20Metadata>(hre, 'WSTETH')
|
867
|
+
const wstethOracle_instance = await getInstanceOfDeployed<T>(hre, 'WSTETHOracle')
|
868
|
+
|
869
|
+
const [wstethDecimals, wstethOracleDecimals] = await Promise.all([
|
870
|
+
wsteth_instance.decimals(),
|
871
|
+
wstethOracle_instance.decimals(),
|
872
|
+
])
|
873
|
+
|
874
|
+
return tokenToPriceFeedStruct(
|
875
|
+
wsteth_instance.address,
|
876
|
+
wstethDecimals,
|
877
|
+
wstethOracle_instance,
|
878
|
+
wstethOracleDecimals,
|
879
|
+
)
|
880
|
+
}
|
881
|
+
|
882
|
+
const getFeedBySymbol = async <T extends AggregatorV2V3Interface>(
|
883
|
+
symbol: string,
|
884
|
+
hre: HardhatRuntimeEnvironment,
|
885
|
+
) => {
|
886
|
+
if (symbol === 'WSTETH') {
|
887
|
+
return getWstETHTokenFeed<T>(hre)
|
888
|
+
} else {
|
889
|
+
return getTokenFeed<AggregatorV2V3Interface>(hre, symbol)
|
890
|
+
}
|
891
|
+
}
|
892
|
+
|
893
|
+
export const whitelistTokensWithAggregator = async <T extends AggregatorV2V3Interface>(
|
894
|
+
hre: HardhatRuntimeEnvironment,
|
895
|
+
) => {
|
896
|
+
const deployerSigner = await getDeployerSigner(hre)
|
897
|
+
const tokenDeployments = await getTokenDeployments(hre)
|
898
|
+
|
899
|
+
const ufarmCore_instance = getInstanceFromDeployment<UFarmCore>(
|
900
|
+
hre,
|
901
|
+
await hre.deployments.get('UFarmCore'),
|
902
|
+
).connect(deployerSigner)
|
903
|
+
|
904
|
+
console.log('\nWhitelisting tokens...')
|
905
|
+
|
906
|
+
const tokensToWhitelist: Array<AssetWithPriceFeed> = []
|
907
|
+
const tokensToUpdate: Array<AssetWithPriceFeed> = []
|
908
|
+
|
909
|
+
for (let i = 0; i < Object.entries(tokenDeployments).length; i++) {
|
910
|
+
const [token, deployment] = Object.entries(tokenDeployments)[i]
|
911
|
+
console.log(`Prepairing ${token} with AggregatorV3 ...`)
|
912
|
+
|
913
|
+
if (token === 'STETH') {
|
914
|
+
console.log(`Skipping ${token} whitelist...`)
|
915
|
+
continue
|
916
|
+
}
|
917
|
+
|
918
|
+
const tokenFeed = await getFeedBySymbol<T>(token, hre)
|
919
|
+
|
920
|
+
const isTokenWhitelisted = await ufarmCore_instance.isTokenWhitelisted(deployment.address)
|
921
|
+
if (isTokenWhitelisted) {
|
922
|
+
const currentOracle = (await ufarmCore_instance.tokenInfo(deployment.address)).priceFeed
|
923
|
+
.feedAddr
|
924
|
+
if (currentOracle === tokenFeed.priceFeed.feedAddr) {
|
925
|
+
console.log(`Token ${token} already whitelisted with correct oracle.`)
|
926
|
+
continue
|
927
|
+
} else {
|
928
|
+
console.warn(`Token ${token} whitelisted with different oracle.`)
|
929
|
+
tokensToUpdate.push(tokenFeed)
|
930
|
+
}
|
931
|
+
} else {
|
932
|
+
tokensToWhitelist.push(tokenFeed)
|
933
|
+
}
|
934
|
+
|
935
|
+
await customSetTimeout(1)
|
936
|
+
}
|
937
|
+
|
938
|
+
if (tokensToWhitelist.length === 0) {
|
939
|
+
console.log(`All tokens already whitelisted!`)
|
940
|
+
return
|
941
|
+
} else {
|
942
|
+
console.log(`Whitelisting tokens: ${tokensToWhitelist.map((token) => token.assetAddr).join(', ')}`)
|
943
|
+
|
944
|
+
await retryOperation(async () => {
|
945
|
+
await hre.deployments.execute(
|
946
|
+
'UFarmCore',
|
947
|
+
{
|
948
|
+
from: deployerSigner.address,
|
949
|
+
log: true,
|
950
|
+
},
|
951
|
+
'whitelistTokens',
|
952
|
+
tokensToWhitelist,
|
953
|
+
)
|
954
|
+
}, 3)
|
955
|
+
|
956
|
+
console.log('Tokens whitelisted!')
|
957
|
+
}
|
958
|
+
|
959
|
+
if (tokensToUpdate.length === 0) {
|
960
|
+
console.log(`Don't need to update any tokens.`)
|
961
|
+
return
|
962
|
+
} else {
|
963
|
+
console.log(`Updating tokens: ${tokensToUpdate.map((token) => token.assetAddr).join(', ')}`)
|
964
|
+
await retryOperation(async () => {
|
965
|
+
await hre.deployments.execute(
|
966
|
+
'UFarmCore',
|
967
|
+
{
|
968
|
+
from: deployerSigner.address,
|
969
|
+
log: true,
|
970
|
+
},
|
971
|
+
'blacklistTokens',
|
972
|
+
tokensToUpdate,
|
973
|
+
)
|
974
|
+
}, 3)
|
975
|
+
|
976
|
+
console.log('Tokens blacklisted!')
|
977
|
+
|
978
|
+
await retryOperation(async () => {
|
979
|
+
await hre.deployments.execute(
|
980
|
+
'UFarmCore',
|
981
|
+
{
|
982
|
+
from: deployerSigner.address,
|
983
|
+
log: true,
|
984
|
+
},
|
985
|
+
'whitelistTokens',
|
986
|
+
tokensToUpdate,
|
987
|
+
)
|
988
|
+
}, 3)
|
989
|
+
|
990
|
+
console.log('Tokens updated!')
|
991
|
+
}
|
992
|
+
}
|