@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.
Files changed (127) hide show
  1. package/.docker/Dockerfile +17 -0
  2. package/.dockerignore +7 -0
  3. package/.env.sample +24 -0
  4. package/.gitlab-ci.yml +51 -0
  5. package/.gitmodules +15 -0
  6. package/.prettierrc +10 -0
  7. package/.solcover.js +4 -0
  8. package/.vscode/settings.json +23 -0
  9. package/LICENSE.MD +51 -0
  10. package/README.md +135 -0
  11. package/contracts/arbitrum/contracts/controllers/UniswapV2ControllerArbitrum.sol +37 -0
  12. package/contracts/arbitrum/contracts/controllers/UniswapV3ControllerArbitrum.sol +46 -0
  13. package/contracts/arbitrum/contracts/oracle/PriceOracleArbitrum.sol +51 -0
  14. package/contracts/main/contracts/controllers/Controller.sol +61 -0
  15. package/contracts/main/contracts/controllers/IController.sol +81 -0
  16. package/contracts/main/contracts/controllers/OneInchV5Controller.sol +332 -0
  17. package/contracts/main/contracts/controllers/UnoswapV2Controller.sol +789 -0
  18. package/contracts/main/contracts/controllers/UnoswapV3Controller.sol +1018 -0
  19. package/contracts/main/contracts/core/CoreWhitelist.sol +192 -0
  20. package/contracts/main/contracts/core/ICoreWhitelist.sol +92 -0
  21. package/contracts/main/contracts/core/IUFarmCore.sol +95 -0
  22. package/contracts/main/contracts/core/UFarmCore.sol +402 -0
  23. package/contracts/main/contracts/fund/FundFactory.sol +59 -0
  24. package/contracts/main/contracts/fund/IUFarmFund.sol +68 -0
  25. package/contracts/main/contracts/fund/UFarmFund.sol +504 -0
  26. package/contracts/main/contracts/oracle/ChainlinkedOracle.sol +71 -0
  27. package/contracts/main/contracts/oracle/IChainlinkAggregator.sol +18 -0
  28. package/contracts/main/contracts/oracle/IPriceOracle.sol +55 -0
  29. package/contracts/main/contracts/oracle/PriceOracle.sol +20 -0
  30. package/contracts/main/contracts/oracle/PriceOracleCore.sol +212 -0
  31. package/contracts/main/contracts/oracle/WstETHOracle.sol +64 -0
  32. package/contracts/main/contracts/permissions/Permissions.sol +54 -0
  33. package/contracts/main/contracts/permissions/UFarmPermissionsModel.sol +136 -0
  34. package/contracts/main/contracts/pool/IPoolAdmin.sol +57 -0
  35. package/contracts/main/contracts/pool/IUFarmPool.sol +304 -0
  36. package/contracts/main/contracts/pool/PerformanceFeeLib.sol +81 -0
  37. package/contracts/main/contracts/pool/PoolAdmin.sol +437 -0
  38. package/contracts/main/contracts/pool/PoolFactory.sol +74 -0
  39. package/contracts/main/contracts/pool/PoolWhitelist.sol +70 -0
  40. package/contracts/main/contracts/pool/UFarmPool.sol +959 -0
  41. package/contracts/main/shared/AssetController.sol +194 -0
  42. package/contracts/main/shared/ECDSARecover.sol +91 -0
  43. package/contracts/main/shared/NZGuard.sol +99 -0
  44. package/contracts/main/shared/SafeOPS.sol +128 -0
  45. package/contracts/main/shared/UFarmCoreLink.sol +83 -0
  46. package/contracts/main/shared/UFarmErrors.sol +16 -0
  47. package/contracts/main/shared/UFarmMathLib.sol +80 -0
  48. package/contracts/main/shared/UFarmOwnableUUPS.sol +59 -0
  49. package/contracts/main/shared/UFarmOwnableUUPSBeacon.sol +34 -0
  50. package/contracts/test/Block.sol +15 -0
  51. package/contracts/test/InchSwapTestProxy.sol +292 -0
  52. package/contracts/test/MockPoolAdmin.sol +8 -0
  53. package/contracts/test/MockUFarmPool.sol +8 -0
  54. package/contracts/test/MockV3wstETHstETHAgg.sol +128 -0
  55. package/contracts/test/MockedWETH9.sol +72 -0
  56. package/contracts/test/OneInchToUFarmTestEnv.sol +466 -0
  57. package/contracts/test/StableCoin.sol +25 -0
  58. package/contracts/test/UFarmMockSequencerUptimeFeed.sol +44 -0
  59. package/contracts/test/UFarmMockV3Aggregator.sol +145 -0
  60. package/contracts/test/UUPSBlock.sol +19 -0
  61. package/contracts/test/ufarmLocal/MulticallV3.sol +220 -0
  62. package/contracts/test/ufarmLocal/controllers/UniswapV2ControllerUFarm.sol +27 -0
  63. package/contracts/test/ufarmLocal/controllers/UniswapV3ControllerUFarm.sol +43 -0
  64. package/deploy/100_test_env_setup.ts +483 -0
  65. package/deploy/20_deploy_uniV2.ts +48 -0
  66. package/deploy/21_create_pairs_uniV2.ts +149 -0
  67. package/deploy/22_deploy_mocked_aggregators.ts +123 -0
  68. package/deploy/22_deploy_wsteth_oracle.ts +65 -0
  69. package/deploy/23_deploy_uniV3.ts +80 -0
  70. package/deploy/24_create_pairs_uniV3.ts +140 -0
  71. package/deploy/25_deploy_oneInch.ts +38 -0
  72. package/deploy/2_deploy_multicall.ts +34 -0
  73. package/deploy/30_deploy_price_oracle.ts +33 -0
  74. package/deploy/3_deploy_lido.ts +114 -0
  75. package/deploy/40_deploy_pool_beacon.ts +19 -0
  76. package/deploy/41_deploy_poolAdmin_beacon.ts +19 -0
  77. package/deploy/42_deploy_ufarmcore.ts +29 -0
  78. package/deploy/43_deploy_fund_beacon.ts +19 -0
  79. package/deploy/4_deploy_tokens.ts +76 -0
  80. package/deploy/50_deploy_poolFactory.ts +35 -0
  81. package/deploy/51_deploy_fundFactory.ts +29 -0
  82. package/deploy/60_init_contracts.ts +101 -0
  83. package/deploy/61_whitelist_tokens.ts +18 -0
  84. package/deploy/70_deploy_uniV2Controller.ts +70 -0
  85. package/deploy/71_deploy_uniV3Controller.ts +67 -0
  86. package/deploy/72_deploy_oneInchController.ts +25 -0
  87. package/deploy/79_whitelist_controllers.ts +125 -0
  88. package/deploy/ufarm/arbitrum/1_prepare_env.ts +82 -0
  89. package/deploy/ufarm/arbitrum/2_deploy_ufarm.ts +178 -0
  90. package/deploy/ufarm/arbitrum-sepolia/1000_prepare_arb_sepolia_env.ts +308 -0
  91. package/deploy-config.json +112 -0
  92. package/deploy-data/oracles.csv +32 -0
  93. package/deploy-data/protocols.csv +10 -0
  94. package/deploy-data/tokens.csv +32 -0
  95. package/docker-compose.yml +67 -0
  96. package/hardhat.config.ts +449 -0
  97. package/index.js +93 -0
  98. package/package.json +82 -0
  99. package/scripts/_deploy_helpers.ts +992 -0
  100. package/scripts/_deploy_network_options.ts +49 -0
  101. package/scripts/activatePool.ts +51 -0
  102. package/scripts/createPool.ts +62 -0
  103. package/scripts/deploy_1inch_proxy.ts +98 -0
  104. package/scripts/pool-data.ts +420 -0
  105. package/scripts/post-deploy.sh +24 -0
  106. package/scripts/setUniV2Rate.ts +252 -0
  107. package/scripts/swapOneInchV5.ts +94 -0
  108. package/scripts/swapUniswapV2.ts +65 -0
  109. package/scripts/swapUniswapV3.ts +71 -0
  110. package/scripts/test.ts +61 -0
  111. package/scripts/typings-copy-artifacts.ts +83 -0
  112. package/tasks/boostPool.ts +39 -0
  113. package/tasks/createFund.ts +44 -0
  114. package/tasks/deboostPool.ts +48 -0
  115. package/tasks/grantUFarmPermissions.ts +57 -0
  116. package/tasks/index.ts +7 -0
  117. package/tasks/mintUSDT.ts +62 -0
  118. package/test/Periphery.test.ts +640 -0
  119. package/test/PriceOracle.test.ts +82 -0
  120. package/test/TestCases.MD +109 -0
  121. package/test/UFarmCore.test.ts +331 -0
  122. package/test/UFarmFund.test.ts +406 -0
  123. package/test/UFarmPool.test.ts +4736 -0
  124. package/test/_fixtures.ts +783 -0
  125. package/test/_helpers.ts +2195 -0
  126. package/test/_oneInchTestData.ts +632 -0
  127. package/tsconfig.json +12 -0
@@ -0,0 +1,640 @@
1
+ // SPDX-License-Identifier: UNLICENSED
2
+
3
+ import { expect } from 'chai'
4
+ import { loadFixture, takeSnapshot } from '@nomicfoundation/hardhat-network-helpers'
5
+ import hre, { ethers } from 'hardhat'
6
+ import { Multicall, ContractCallResults, ContractCallContext } from 'ethereum-multicall'
7
+ import { tokensFixture, UniswapV3Fixture } from './_fixtures'
8
+ import {
9
+ IERC20Metadata,
10
+ IERC20Metadata__factory,
11
+ INonfungiblePositionManager,
12
+ Multicall3__factory,
13
+ } from '../typechain-types'
14
+ import {
15
+ constants,
16
+ getBlockchainTimestamp,
17
+ MintableToken,
18
+ mintTokens,
19
+ safeApprove,
20
+ } from './_helpers'
21
+ import { customSetTimeout } from '../scripts/_deploy_helpers'
22
+
23
+ import {
24
+ Pool,
25
+ TickMath,
26
+ nearestUsableTick,
27
+ Position,
28
+ maxLiquidityForAmounts,
29
+ } from '@uniswap/v3-sdk'
30
+ import { BigintIsh } from '@uniswap/sdk-core'
31
+
32
+ import JSBI from 'jsbi'
33
+
34
+ describe('Multicall', async () => {
35
+ it('Should return correct results for multiple calls', async () => {
36
+ const { tokens, deployer } = await loadFixture(tokensFixture)
37
+
38
+ const multicall_factory = (await hre.ethers.getContractFactory(
39
+ 'Multicall3',
40
+ )) as Multicall3__factory
41
+
42
+ const multicall_instance = await multicall_factory.deploy()
43
+
44
+ // mint tokens to deployer and prepare for multicall
45
+ let multicall_contexts: ContractCallContext[] = []
46
+
47
+ const balanceOfCall: ContractCallContext = {
48
+ reference: 'testContract2',
49
+ contractAddress: '0x6795b15f3b16Cf8fB3E56499bbC07F6261e9b0C3',
50
+ abi: [
51
+ {
52
+ name: 'balanceOf',
53
+ type: 'function',
54
+ stateMutability: 'view',
55
+ inputs: [{ name: 'account', type: 'address' }],
56
+ outputs: [{ name: 'amounts', type: 'uint256' }],
57
+ },
58
+ ],
59
+ calls: [
60
+ {
61
+ reference: 'balanceOfCall',
62
+ methodName: 'balanceOf',
63
+ methodParameters: [deployer.address],
64
+ },
65
+ ],
66
+ }
67
+
68
+ await Promise.all(
69
+ Object.values(tokens).map(async (token) => {
70
+ // if WETH (has attribute 'deposit') then deposit 1 ETH
71
+ if ('deposit' in token) {
72
+ await token.deposit({ value: (10n ** 18n).toString() })
73
+ }
74
+ // else if USDT (has attribute 'mint') then mint 1 USDT
75
+ else if ('mint' in token) {
76
+ await token.mint(deployer.address, (10n ** 6n).toString())
77
+ } else {
78
+ throw new Error('Unknown token')
79
+ }
80
+ multicall_contexts.push({
81
+ ...balanceOfCall,
82
+ reference: await token.symbol(),
83
+ contractAddress: token.address,
84
+ })
85
+ }),
86
+ )
87
+
88
+ const multicall = new Multicall({
89
+ ethersProvider: hre.ethers.provider,
90
+ tryAggregate: false,
91
+ multicallCustomContractAddress: multicall_instance.address,
92
+ })
93
+
94
+ expect(await multicall.call(multicall_contexts)).to.be.not.reverted
95
+ })
96
+
97
+ it.skip(`UniswapV3 tick calculation test`, async () => {
98
+ const all = await loadFixture(UniswapV3Fixture)
99
+
100
+ const UNIV3 = {
101
+ FEE_TICK: {
102
+ zero01: 5,
103
+ zero05: 10,
104
+ zero3: 60,
105
+ one: 200,
106
+ },
107
+ MIN_TICK: -887272,
108
+ MAX_TICK: 887272,
109
+ MIN_SQRT_RATIO: BigInt(4295128739),
110
+ MAX_SQRT_RATIO: BigInt('1461446703485210103287273052203988822378723970342'),
111
+ }
112
+ const ONE = BigInt(1e18)
113
+
114
+ const Q96 = 2n ** 96n // Equivalent to the Solidity's type uint256 for the Q96 format in sqrtPrice
115
+
116
+ async function getCurrentPrice(pool: string, decimalsA: number, decimalsB: number) {
117
+ const pool_instance = await ethers.getContractAt('UniswapV3Pool', pool, signer)
118
+ const slot0 = await pool_instance.slot0()
119
+ const sqrtPriceX96 = slot0.sqrtPriceX96.toBigInt()
120
+ const nonNormalisedPrice = (Number(sqrtPriceX96) / 2 ** 96) ** 2
121
+ const _buyOneOfToken0 = ((nonNormalisedPrice * 10 ** decimalsA) / 10 ** decimalsB).toFixed(
122
+ decimalsB,
123
+ )
124
+ const buyOneOfToken0 = ethers.utils.parseUnits(_buyOneOfToken0, decimalsB).toBigInt()
125
+ const _buyOneOfToken1 = (1 / Number(_buyOneOfToken0)).toFixed(decimalsA)
126
+ const buyOneOfToken1 = ethers.utils.parseUnits(_buyOneOfToken1, decimalsA).toBigInt()
127
+
128
+ console.log(`Price A of B: ${buyOneOfToken0}\nPrice B of A: ${buyOneOfToken1}`)
129
+
130
+ return { buyOneOfToken0, buyOneOfToken1 }
131
+ }
132
+
133
+ function getTickAtSqrtRatio(sqrtRatioX96: bigint): number {
134
+ const sqrtPrice = Number(sqrtRatioX96) / Number(Q96)
135
+ return Math.floor((Math.log(sqrtPrice) / Math.log(1.0001)) * 2)
136
+ }
137
+
138
+ function sqrtPriceX96ToPrice(sqrtPriceX96: bigint): number {
139
+ const sqrtPrice = Number(sqrtPriceX96) / Number(Q96)
140
+ return sqrtPrice * sqrtPrice
141
+ }
142
+
143
+ function priceToSqrtPriceX96(price: number): bigint {
144
+ const sqrtPrice = Math.sqrt(price)
145
+ return BigInt(Math.floor(sqrtPrice * Number(Q96)))
146
+ }
147
+
148
+ let tokenA: MintableToken = all.tokens.WETH
149
+ let tokenB: MintableToken = all.tokens.USDT
150
+
151
+ const reversed = BigInt(tokenA.address) > BigInt(tokenB.address)
152
+
153
+ if (reversed) {
154
+ ;[tokenA, tokenB] = [tokenB, tokenA]
155
+ }
156
+
157
+ const [decimalsA, decimalsB, symbolA, symbolB] = await Promise.all([
158
+ tokenA.decimals(),
159
+ tokenB.decimals(),
160
+ tokenA.symbol(),
161
+ tokenB.symbol(),
162
+ ])
163
+
164
+ const fee = 500
165
+
166
+ const uniswapV3Factory_instance = all.uniswapV3Factory_instance
167
+ const nfpm_instance = all.nonFungPosManager_instance
168
+
169
+ const signer = all.wallet
170
+
171
+ const pool = await uniswapV3Factory_instance.getPool(tokenA.address, tokenB.address, fee)
172
+ const pool_instance = await ethers.getContractAt('UniswapV3Pool', pool, signer)
173
+ const slot0_initial = await pool_instance.slot0()
174
+
175
+ function maxLiquidityForAmount0Precise(
176
+ sqrtRatioAX96: JSBI,
177
+ sqrtRatioBX96: JSBI,
178
+ amount0: BigintIsh,
179
+ ): JSBI {
180
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
181
+ ;[sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]
182
+ }
183
+
184
+ const numerator = JSBI.multiply(
185
+ JSBI.multiply(JSBI.BigInt(amount0), sqrtRatioAX96),
186
+ sqrtRatioBX96,
187
+ )
188
+ const denominator = JSBI.multiply(
189
+ JSBI.BigInt(Q96.toString()),
190
+ JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96),
191
+ )
192
+
193
+ return JSBI.divide(numerator, denominator)
194
+ }
195
+
196
+ /**
197
+ * Computes the maximum amount of liquidity received for a given amount of token1
198
+ * @param sqrtRatioAX96 The price at the lower tick boundary
199
+ * @param sqrtRatioBX96 The price at the upper tick boundary
200
+ * @param amount1 The token1 amount
201
+ * @returns liquidity for amount1
202
+ */
203
+ function maxLiquidityForAmount1(
204
+ sqrtRatioAX96: JSBI,
205
+ sqrtRatioBX96: JSBI,
206
+ amount1: BigintIsh,
207
+ ): JSBI {
208
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
209
+ ;[sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]
210
+ }
211
+ return JSBI.divide(
212
+ JSBI.multiply(JSBI.BigInt(amount1), JSBI.BigInt(Q96.toString())),
213
+ JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96),
214
+ )
215
+ }
216
+
217
+ /**
218
+ * Gets the amount1 delta between two prices
219
+ * @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
220
+ * @param sqrtRatioAX96 The price at the lower tick boundary
221
+ * @param sqrtRatioBX96 The price at the upper tick boundary
222
+ * @param liquidity The liquidity amount
223
+ * @param roundUp Whether to round the amount up, or down
224
+ * @returns Amount of token1 required to cover a position of size liquidity between the two passed prices
225
+ */
226
+ function getAmount1Delta(
227
+ sqrtRatioAX96: JSBI,
228
+ sqrtRatioBX96: JSBI,
229
+ liquidity: JSBI,
230
+ roundUp: boolean,
231
+ ): JSBI {
232
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
233
+ ;[sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]
234
+ console.log(`Swapped prices`)
235
+ }
236
+
237
+ const answer = roundUp
238
+ ? JSBI.divide(
239
+ JSBI.multiply(
240
+ JSBI.BigInt(liquidity.toString()),
241
+ JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96),
242
+ ),
243
+ JSBI.BigInt(Q96.toString()),
244
+ )
245
+ : JSBI.divide(
246
+ JSBI.multiply(
247
+ JSBI.BigInt(liquidity.toString()),
248
+ JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96),
249
+ ),
250
+ JSBI.BigInt(Q96.toString()),
251
+ )
252
+
253
+ return answer
254
+ }
255
+
256
+ /**
257
+ * Gets the amount0 delta between two prices
258
+ * @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
259
+ * @param sqrtRatioAX96 - A sqrt price
260
+ * @param sqrtRatioBX96 - Another sqrt price
261
+ * @param liquidity - The amount of usable liquidity
262
+ * @param roundUp - Whether to round the amount up or down
263
+ * @returns
264
+ */
265
+ function getAmount0Delta(
266
+ sqrtRatioAX96: JSBI,
267
+ sqrtRatioBX96: JSBI,
268
+ liquidity: JSBI,
269
+ roundUp: boolean,
270
+ ): JSBI {
271
+ if (JSBI.greaterThan(sqrtRatioAX96, sqrtRatioBX96)) {
272
+ ;[sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]
273
+ }
274
+
275
+ const numerator1 = JSBI.leftShift(JSBI.BigInt(liquidity.toString()), JSBI.BigInt(96))
276
+ const numerator2 = JSBI.subtract(sqrtRatioBX96, sqrtRatioAX96)
277
+
278
+ const answer = roundUp
279
+ ? JSBI.divide(
280
+ JSBI.divide(JSBI.multiply(numerator1, numerator2), sqrtRatioBX96),
281
+ sqrtRatioAX96,
282
+ )
283
+ : JSBI.divide(
284
+ JSBI.divide(JSBI.multiply(numerator1, numerator2), sqrtRatioBX96),
285
+ sqrtRatioAX96,
286
+ )
287
+
288
+ return answer
289
+ }
290
+
291
+ // Set the tick spacing
292
+ const tickSpacing = UNIV3.FEE_TICK.zero05
293
+
294
+ const initialPrice = await getCurrentPrice(pool, decimalsA, decimalsB)
295
+ const calculatedTick = getTickAtSqrtRatio(slot0_initial.sqrtPriceX96.toBigInt())
296
+
297
+ // expect(calculatedTick).to.be.equal(
298
+ // slot0_initial.tick,
299
+ // 'Initial tick should be equal to calculated tick',
300
+ // )
301
+
302
+ const calculatedPrice = BigInt(TickMath.getSqrtRatioAtTick(slot0_initial.tick).toString())
303
+ const tickFromCalcualtedPrice = getTickAtSqrtRatio(calculatedPrice)
304
+
305
+ // expect(calculatedTick).to.be.equal(
306
+ // tickFromCalcualtedPrice,
307
+ // 'Initial tick should be equal to tickFromCalcualtedPrice',
308
+ // )
309
+
310
+ const [priceLowerBound, priceUpperBound] = [
311
+ initialPrice.buyOneOfToken0 / 2n,
312
+ initialPrice.buyOneOfToken0 * 2n,
313
+ ]
314
+
315
+ const sqrtRatioAX96 = priceToSqrtPriceX96(Number(priceLowerBound))
316
+ const sqrtRatioBX96 = priceToSqrtPriceX96(Number(priceUpperBound))
317
+
318
+ const [tickLower, tickUpper] = [
319
+ getTickAtSqrtRatio(sqrtRatioAX96),
320
+ getTickAtSqrtRatio(sqrtRatioBX96),
321
+ ]
322
+
323
+ console.log(
324
+ `tick upper: ${tickUpper}\n` +
325
+ `tick initial: ${slot0_initial.tick}\n` +
326
+ `tick lower: ${tickLower}\n`,
327
+ )
328
+
329
+ // Determine the usable ticks given a tick spacing
330
+ const roundedTickLower = nearestUsableTick(tickLower, tickSpacing)
331
+ const roundedTickUpper = nearestUsableTick(tickUpper, tickSpacing)
332
+
333
+ const roundedRatioAX96 = TickMath.getSqrtRatioAtTick(roundedTickLower)
334
+ const roundedRatioBX96 = TickMath.getSqrtRatioAtTick(roundedTickUpper)
335
+
336
+ const amountA = () => 10n ** BigInt(decimalsA) // like a user input, wait for it when met
337
+ const amountB = () => 10n ** BigInt(decimalsB) // like a user input, wait for it when met
338
+
339
+ // if (slot0_initial.tick < roundedTickLower) {
340
+ // only amount0
341
+ console.log(`Tick is less than lower bound`)
342
+
343
+ const tickAbovePrice0 = nearestUsableTick(slot0_initial.tick + 100, tickSpacing)
344
+ const sqrtPrice0Above = BigInt(TickMath.getSqrtRatioAtTick(tickAbovePrice0).toString())
345
+ const price0Above = sqrtPriceX96ToPrice(sqrtPrice0Above)
346
+ const price1Above = (price0Above * 3) / 2
347
+ const _sqrtPrice1Above = priceToSqrtPriceX96(price1Above)
348
+ const _tickAbovePrice1 = getTickAtSqrtRatio(_sqrtPrice1Above)
349
+ const tickAbovePrice1 = nearestUsableTick(_tickAbovePrice1, tickSpacing)
350
+ const sqrtPrice1Above = BigInt(TickMath.getSqrtRatioAtTick(tickAbovePrice1).toString())
351
+
352
+ const liquidityAbove = maxLiquidityForAmounts(
353
+ JSBI.BigInt(slot0_initial.sqrtPriceX96.toString()),
354
+ JSBI.BigInt(sqrtPrice0Above.toString()),
355
+ JSBI.BigInt(sqrtPrice1Above.toString()),
356
+ JSBI.BigInt(amountA().toString()),
357
+ JSBI.BigInt(0),
358
+ true,
359
+ )
360
+
361
+ console.log(`Liquidity when current price below borders: \n${liquidityAbove.toString()}\n`)
362
+
363
+ const amount0Above = getAmount0Delta(
364
+ JSBI.BigInt(sqrtPrice0Above.toString()),
365
+ JSBI.BigInt(sqrtPrice1Above.toString()),
366
+ liquidityAbove,
367
+ true,
368
+ )
369
+
370
+ const mintDataAbove: INonfungiblePositionManager.MintParamsStruct = {
371
+ token0: tokenA.address,
372
+ token1: tokenB.address,
373
+ fee: fee,
374
+ tickLower: tickAbovePrice0,
375
+ tickUpper: tickAbovePrice1,
376
+ amount0Desired: amount0Above.toString(),
377
+ amount1Desired: 0,
378
+ amount0Min: 0,
379
+ amount1Min: 0,
380
+ recipient: all.deployer.address,
381
+ deadline: (await getBlockchainTimestamp(ethers.provider)) + 100,
382
+ }
383
+
384
+ let snapshotBeforeMint = await takeSnapshot()
385
+
386
+ const aToSpend = amount0Above.toString()
387
+ await mintTokens(tokenA, aToSpend, all.deployer)
388
+ await safeApprove(tokenA, nfpm_instance.address, aToSpend, all.deployer)
389
+
390
+ await nfpm_instance.mint(mintDataAbove)
391
+ console.log(`Minted position upper price\n`)
392
+
393
+ await snapshotBeforeMint.restore()
394
+ snapshotBeforeMint = await takeSnapshot()
395
+
396
+ // } else if (slot0_initial.tick < roundedTickUpper) {
397
+
398
+ // amount0 and amount1
399
+
400
+ console.log(`Tick is between bounds`)
401
+
402
+ const liquidityInside = maxLiquidityForAmounts(
403
+ JSBI.BigInt(slot0_initial.sqrtPriceX96.toString()),
404
+ JSBI.BigInt(roundedRatioAX96.toString()),
405
+ JSBI.BigInt(roundedRatioBX96.toString()),
406
+ JSBI.BigInt(amountA().toString()),
407
+ JSBI.BigInt(amountB().toString()),
408
+ true,
409
+ )
410
+
411
+ const [amount0Inside, amount1Inside] = [
412
+ getAmount0Delta(
413
+ JSBI.BigInt(slot0_initial.sqrtPriceX96.toString()),
414
+ JSBI.BigInt(roundedRatioAX96.toString()),
415
+ liquidityInside,
416
+ true,
417
+ ),
418
+ getAmount1Delta(
419
+ JSBI.BigInt(slot0_initial.sqrtPriceX96.toString()),
420
+ JSBI.BigInt(roundedRatioBX96.toString()),
421
+ liquidityInside,
422
+ true,
423
+ ),
424
+ ]
425
+
426
+ const mintDataInside: INonfungiblePositionManager.MintParamsStruct = {
427
+ token0: tokenA.address,
428
+ token1: tokenB.address,
429
+ fee: fee,
430
+ tickLower: roundedTickLower,
431
+ tickUpper: roundedTickUpper,
432
+ amount0Desired: amount0Inside.toString(),
433
+ amount1Desired: amount1Inside.toString(),
434
+ amount0Min: 0,
435
+ amount1Min: 0,
436
+ recipient: all.deployer.address,
437
+ deadline: (await getBlockchainTimestamp(ethers.provider)) + 100,
438
+ }
439
+
440
+ const aInsideToSpend = amount0Inside.toString()
441
+ const bInsideToSpend = amount1Inside.toString()
442
+
443
+ await mintTokens(tokenA, aInsideToSpend, all.deployer)
444
+ await mintTokens(tokenB, bInsideToSpend, all.deployer)
445
+ await safeApprove(tokenA, nfpm_instance.address, aInsideToSpend, all.deployer)
446
+ await safeApprove(tokenB, nfpm_instance.address, bInsideToSpend, all.deployer)
447
+
448
+ await nfpm_instance.mint(mintDataInside)
449
+
450
+ console.log(`Minted position inside price\n`)
451
+
452
+ await snapshotBeforeMint.restore()
453
+
454
+ // console.log(`Liquidity when current price above borders: \n${liquidityBelow.toString()}\n`)
455
+ // } else {
456
+
457
+ // amount1
458
+ console.log(`Tick is below bounds`)
459
+
460
+ console.log(`Tick is greater than upper bound`)
461
+ const _tickBelowPrice1 = slot0_initial.tick - 100
462
+ const tickBelowPrice1 = nearestUsableTick(_tickBelowPrice1, tickSpacing)
463
+ const sqrtPrice1Below = BigInt(TickMath.getSqrtRatioAtTick(tickBelowPrice1).toString())
464
+ const price1Below = sqrtPriceX96ToPrice(sqrtPrice1Below)
465
+ const _price0Below = (price1Below * 2) / 3
466
+ const _sqrtPrice0Below = priceToSqrtPriceX96(_price0Below)
467
+ const _tickBelowPrice0 = getTickAtSqrtRatio(_sqrtPrice0Below)
468
+ const tickBelowPrice0 = nearestUsableTick(_tickBelowPrice0, tickSpacing)
469
+ const sqrtPrice0Below = BigInt(TickMath.getSqrtRatioAtTick(tickBelowPrice0).toString())
470
+ const price0Below = sqrtPriceX96ToPrice(sqrtPrice0Below)
471
+
472
+ const liquidityBelow = maxLiquidityForAmounts(
473
+ JSBI.BigInt(slot0_initial.sqrtPriceX96.toString()),
474
+ JSBI.BigInt(sqrtPrice0Below.toString()),
475
+ JSBI.BigInt(sqrtPrice1Below.toString()),
476
+ JSBI.BigInt(0),
477
+ JSBI.BigInt(amountB().toString()), // user input like
478
+ true,
479
+ )
480
+
481
+ console.log(`Liquidity when current price above borders: \n${liquidityBelow.toString()}\n`)
482
+
483
+ const amount1Below = getAmount1Delta(
484
+ JSBI.BigInt(sqrtPrice0Below.toString()),
485
+ JSBI.BigInt(sqrtPrice1Below.toString()),
486
+ liquidityBelow,
487
+ false,
488
+ )
489
+
490
+ const mintDataBelow: INonfungiblePositionManager.MintParamsStruct = {
491
+ token0: tokenA.address,
492
+ token1: tokenB.address,
493
+ fee: fee,
494
+ tickLower: tickBelowPrice0,
495
+ tickUpper: tickBelowPrice1,
496
+ amount0Desired: 0,
497
+ amount1Desired: amount1Below.toString(),
498
+ amount0Min: 0,
499
+ amount1Min: 0,
500
+ recipient: all.deployer.address,
501
+ deadline: (await getBlockchainTimestamp(ethers.provider)) + 100,
502
+ }
503
+
504
+ const bBelowToSpend = amount1Below.toString()
505
+ await mintTokens(tokenB, bBelowToSpend, all.deployer)
506
+ await safeApprove(tokenB, nfpm_instance.address, bBelowToSpend, all.deployer)
507
+
508
+ await nfpm_instance.mint(mintDataBelow)
509
+
510
+ console.log(`Minted position lower price\n`)
511
+
512
+ await snapshotBeforeMint.restore()
513
+
514
+ // }
515
+ })
516
+
517
+ it.skip('one inch fork test', async () => {
518
+ const [deployer] = await hre.ethers.getSigners()
519
+ console.log(`Deplyer address: ${deployer.address}`)
520
+
521
+ const routerV6 = '0x111111125421ca6dc452d289314280a0f8842a65'
522
+ const aggregationRouterV5_orig = '0x1111111254eeb25477b68fb85ed929f73a960582'
523
+ const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
524
+ const usdtAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7'
525
+ const usdtHolderAddr = '0xDFd5293D8e347dFe59E90eFd55b2956a1343963d'
526
+ const pureOneInchTx =
527
+ '0x0502b1c5000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000f374f00000000000000000000000000000000000000000000000000000000000f0d6d0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d03403041cbd36888becc7bbcbc0045e3b1f144466f5f8b1ccac8'
528
+
529
+ const oneInchTx = `0x4c9ddf69000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c80502b1c5000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000f374f00000000000000000000000000000000000000000000000000000000000f0d6d0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d03403041cbd36888becc7bbcbc0045e3b1f144466f5f8b1ccac8000000000000000000000000000000000000000000000000`
530
+ const selectorToController =
531
+ '0x4c9ddf69000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c8'
532
+
533
+ // Get code of original myAggrRouterV5
534
+ const code = await hre.ethers.provider.getCode(aggregationRouterV5_orig)
535
+ if (code === '0x') {
536
+ throw new Error('AggregationRouterV5 not deployed')
537
+ } else {
538
+ console.log(`AggregationRouterV5 code: ${code.slice(0, 10)}...`)
539
+ }
540
+
541
+ await await hre.ethers.provider.send('hardhat_impersonateAccount', [usdtHolderAddr])
542
+
543
+ const usdtHolder = hre.ethers.provider.getSigner(usdtHolderAddr)
544
+ console.log(`Impersonated usdt holder: ${usdtHolderAddr}`)
545
+
546
+ const usdtInstance = (await hre.ethers.getContractAt(
547
+ '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol:IERC20Metadata',
548
+ usdtAddress,
549
+ )) as IERC20Metadata
550
+ const usdcInstance = (await hre.ethers.getContractAt(
551
+ '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol:IERC20Metadata',
552
+ usdcAddress,
553
+ )) as IERC20Metadata
554
+
555
+ const oneInchControllerFactory = await hre.ethers.getContractFactory('InchSwapTestController')
556
+ const testProxyFactory = await hre.ethers.getContractFactory('InchSwapTestProxy')
557
+
558
+ const aggregationRouterV5Factory = await hre.ethers.getContractFactory('AggregationRouterV5')
559
+ const myAggrRouterV5 = await aggregationRouterV5Factory.deploy(
560
+ '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
561
+ )
562
+ console.log(`AggregationRouterV5 deployed at: ${myAggrRouterV5.address}`)
563
+
564
+ // const inchTarget = aggregationRouterV5_orig
565
+ const inchTarget = myAggrRouterV5.address
566
+
567
+ const testController = await oneInchControllerFactory.deploy(inchTarget)
568
+ console.log(`test controller deployed at: ${testController.address}`)
569
+
570
+ const testProxy = await testProxyFactory.deploy()
571
+ console.log(`TestProxy deployed at: ${testProxy.address}`)
572
+
573
+ const usdtInitialBalance = await usdtInstance.balanceOf(testProxy.address)
574
+ const usdcInitialBalance = await usdcInstance.balanceOf(testProxy.address)
575
+
576
+ console.log(`usdt initial balance: ${usdtInitialBalance.toString()}`)
577
+ console.log(`usdc initial balance: ${usdcInitialBalance.toString()}`)
578
+
579
+ await testProxy.addController(
580
+ constants.UFarm.prtocols.OneInchProtocolString,
581
+ testController.address,
582
+ )
583
+ console.log(`OneInchController added to TestProxy`)
584
+
585
+ const usdtAmountOut = constants.ONE_HUNDRED_BUCKS.mul(20)
586
+
587
+ if ((await usdtInstance.balanceOf(usdtHolderAddr)).lt(usdtAmountOut)) {
588
+ throw new Error('usdtAmountOut is greater than balance of holder')
589
+ }
590
+
591
+ await customSetTimeout(2)
592
+
593
+ await (await usdtInstance.connect(usdtHolder).transfer(testProxy.address, usdtAmountOut)).wait()
594
+ console.log(`Transferred ${usdtAmountOut} USDT to TestProxy`)
595
+ const logs = await (
596
+ await usdtInstance.connect(usdtHolder).transfer(deployer.address, usdtAmountOut)
597
+ ).wait()
598
+ // console.log(`Transferred ${JSON.stringify(logs,null,2)} USDT to Deployer`)
599
+
600
+ await customSetTimeout(2)
601
+
602
+ await safeApprove(usdtInstance, inchTarget, usdtAmountOut, deployer)
603
+
604
+ console.log(`Approved ${usdtAmountOut} USDT to AggregationRouter from deployer`)
605
+
606
+ await customSetTimeout(2)
607
+
608
+ const usdtBalanceBeforeSwap = await usdtInstance.balanceOf(deployer.address)
609
+ const usdtProxyBalanceBeforeSwap = await usdtInstance.balanceOf(testProxy.address)
610
+ console.log(`usdt balance before deployer swap: ${usdtBalanceBeforeSwap.toString()}`)
611
+ console.log(`usdt balance before proxy swap: ${usdtProxyBalanceBeforeSwap.toString()}`)
612
+
613
+ const receipt1inch = await (
614
+ await deployer.sendTransaction({ to: inchTarget, data: pureOneInchTx })
615
+ ).wait()
616
+
617
+ console.log(`1inch swap executed #1 \n`)
618
+
619
+ const usdcHolderBalanceAfter = await usdcInstance.balanceOf(deployer.address)
620
+
621
+ console.log(`\n\nusdc balance after deployer swap: ${usdcHolderBalanceAfter.toString()}`)
622
+
623
+ const controllerCall = testController.interface.encodeFunctionData(`delegated1InchSwap`, [
624
+ pureOneInchTx,
625
+ ])
626
+ try {
627
+ await testProxy.protocolAction(constants.UFarm.prtocols.OneInchProtocolString, controllerCall)
628
+ console.log(`1inch swap executed #2 \n`)
629
+ } catch (e) {
630
+ console.log(`Error: ${e}`)
631
+ }
632
+
633
+ try {
634
+ await testProxy.justCall(usdtAddress, inchTarget, pureOneInchTx)
635
+ console.log(`1inch swap executed #3`)
636
+ } catch (e) {
637
+ console.log(`Error: ${e}`)
638
+ }
639
+ })
640
+ })