@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,49 @@
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
2
|
+
|
3
|
+
import { Network } from 'hardhat/types'
|
4
|
+
import { getNetworkType } from './_deploy_helpers'
|
5
|
+
|
6
|
+
export const initOptsUniV2: Record<
|
7
|
+
string,
|
8
|
+
{
|
9
|
+
codeHash: string
|
10
|
+
controller: string
|
11
|
+
}
|
12
|
+
> = {
|
13
|
+
arbitrum: {
|
14
|
+
codeHash: '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f',
|
15
|
+
controller: 'UniswapV2ControllerArbitrum',
|
16
|
+
},
|
17
|
+
}
|
18
|
+
|
19
|
+
export const initOptsUniV3: Record<
|
20
|
+
string,
|
21
|
+
{
|
22
|
+
codeHash: string
|
23
|
+
controller: string
|
24
|
+
}
|
25
|
+
> = {
|
26
|
+
arbitrum: {
|
27
|
+
codeHash: '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54',
|
28
|
+
controller: 'UniswapV3ControllerArbitrum',
|
29
|
+
},
|
30
|
+
}
|
31
|
+
|
32
|
+
export const getInitCodeUniV2 = (network: Network) => {
|
33
|
+
const networkType = getNetworkType(network)
|
34
|
+
if (networkType === 'arbitrum') {
|
35
|
+
return initOptsUniV2.arbitrum
|
36
|
+
} else {
|
37
|
+
throw new Error(`Init code not found for network: ${network.name} with tags: ${network.tags}`)
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
export const getInitCodeUniV3 = (network: Network) => {
|
42
|
+
const networkType = getNetworkType(network)
|
43
|
+
|
44
|
+
if (networkType === 'arbitrum') {
|
45
|
+
return initOptsUniV3.arbitrum
|
46
|
+
} else {
|
47
|
+
throw new Error(`Init code not found for network: ${network.name} with tags: ${network.tags}`)
|
48
|
+
}
|
49
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
2
|
+
|
3
|
+
import hre from 'hardhat'
|
4
|
+
import { BigNumberish } from 'ethers'
|
5
|
+
import { UFarmPool, StableCoin, UFarmFund, PoolAdmin, UFarmCore } from '../typechain-types'
|
6
|
+
import { PoolCreationStruct, constants, getEventFromTx } from '../test/_helpers'
|
7
|
+
|
8
|
+
async function main() {
|
9
|
+
const { pool } = {
|
10
|
+
pool: '0x2240ce642A77f4B7ea926035181DEC1f4e968AA4',
|
11
|
+
}
|
12
|
+
|
13
|
+
const pool_instance = (await hre.ethers.getContractAt('UFarmPool', pool)) as UFarmPool
|
14
|
+
const pool_admin = await pool_instance.poolAdmin()
|
15
|
+
console.log('Pool admin contract:', pool_admin)
|
16
|
+
|
17
|
+
const pool_admin_instance = (await hre.ethers.getContractAt('PoolAdmin', pool_admin)) as PoolAdmin
|
18
|
+
|
19
|
+
const core = await pool_instance.ufarmCore()
|
20
|
+
const core_instance = (await hre.ethers.getContractAt('UFarmCore', core)) as UFarmCore
|
21
|
+
const minFundDeposit = await core_instance.minimumFundDeposit()
|
22
|
+
|
23
|
+
const fund = await pool_instance.ufarmFund()
|
24
|
+
const fund_instance = (await hre.ethers.getContractAt('UFarmFund', fund)) as UFarmFund
|
25
|
+
|
26
|
+
|
27
|
+
if (minFundDeposit.gt(0)) {
|
28
|
+
console.log('Minimum fund deposit is not zero, depositing...')
|
29
|
+
await(await fund_instance.depositToPool(pool, minFundDeposit)).wait()
|
30
|
+
console.log('Deposit done')
|
31
|
+
}
|
32
|
+
|
33
|
+
const event = await getEventFromTx(
|
34
|
+
pool_admin_instance.changePoolStatus(constants.Pool.State.Active),
|
35
|
+
pool_instance,
|
36
|
+
'PoolStatusChanged',
|
37
|
+
)
|
38
|
+
|
39
|
+
if (!event) {
|
40
|
+
throw new Error('Pool activation failed')
|
41
|
+
} else {
|
42
|
+
console.log('Pool activated')
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
main()
|
47
|
+
.then(() => process.exit(0))
|
48
|
+
.catch((error) => {
|
49
|
+
console.error(error)
|
50
|
+
process.exit(1)
|
51
|
+
})
|
@@ -0,0 +1,62 @@
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
2
|
+
|
3
|
+
import hre from 'hardhat'
|
4
|
+
import { BigNumberish } from 'ethers'
|
5
|
+
import { UFarmPool, StableCoin, UFarmFund } from '../typechain-types'
|
6
|
+
import {
|
7
|
+
PoolCreationStruct,
|
8
|
+
getEventFromTx,
|
9
|
+
} from '../test/_helpers'
|
10
|
+
|
11
|
+
async function main() {
|
12
|
+
const {
|
13
|
+
fund,
|
14
|
+
usdt,
|
15
|
+
} = {
|
16
|
+
fund: '0x8D30D3D813694415d4e44B1604F24a53236b6726',
|
17
|
+
usdt: '0xd71fe004d84b10FbD161838F87A94f2327A315a1',
|
18
|
+
}
|
19
|
+
const poolArgs: PoolCreationStruct = {
|
20
|
+
minInvestment: 1 as BigNumberish,
|
21
|
+
maxInvestment: hre.ethers.utils.parseUnits('1000000', 6),
|
22
|
+
managementCommission: 200 as BigNumberish,
|
23
|
+
performanceCommission: 3000 as BigNumberish,
|
24
|
+
depositLockupPeriod: 0 as BigNumberish, // will be removed
|
25
|
+
withdrawalLockupPeriod: 0 as BigNumberish,
|
26
|
+
valueToken: usdt,
|
27
|
+
staff: [
|
28
|
+
// Example staff member:
|
29
|
+
// {
|
30
|
+
// addr: bob.address,
|
31
|
+
// permissionsMask: bitsToBigNumber([
|
32
|
+
// constants.Pool.Permissions.Member,
|
33
|
+
// constants.Pool.Permissions.UpdateLockupPeriods,
|
34
|
+
// ]),
|
35
|
+
// },
|
36
|
+
// {
|
37
|
+
// addr: alice.address,
|
38
|
+
// permissionsMask: bitsToBigNumber(Array.from(Object.values(constants.Pool.Permissions))),
|
39
|
+
// },
|
40
|
+
],
|
41
|
+
name: 'UFarmPool',
|
42
|
+
symbol: 'Pool symbol',
|
43
|
+
}
|
44
|
+
|
45
|
+
const fund_instance = (await hre.ethers.getContractAt('UFarmFund', fund)) as UFarmFund
|
46
|
+
|
47
|
+
const event = await getEventFromTx(fund_instance.createPool(poolArgs),fund_instance,'PoolCreated')
|
48
|
+
|
49
|
+
if (!event) {
|
50
|
+
throw new Error('Pool creation failed')
|
51
|
+
}
|
52
|
+
|
53
|
+
console.log('Pool created at', event.args.pool)
|
54
|
+
|
55
|
+
}
|
56
|
+
|
57
|
+
main()
|
58
|
+
.then(() => process.exit(0))
|
59
|
+
.catch((error) => {
|
60
|
+
console.error(error)
|
61
|
+
process.exit(1)
|
62
|
+
})
|
@@ -0,0 +1,98 @@
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
2
|
+
|
3
|
+
import hre from 'hardhat'
|
4
|
+
import { BigNumberish } from 'ethers'
|
5
|
+
import { UFarmPool, StableCoin, UFarmFund, OneInchV5Controller__factory } from '../typechain-types'
|
6
|
+
import { PoolCreationStruct, constants, encodePoolOneInchSwap, getEventFromTx } from '../test/_helpers'
|
7
|
+
import { IERC20Metadata } from '../typechain-types/@openzeppelin/contracts/token/ERC20/extensions'
|
8
|
+
|
9
|
+
|
10
|
+
// args: (0xe6e40dcfe2607f89f8642ab4a065a8e8605a1a57c2cc8d316950366809a262fc, 0x4c9ddf69000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c80502b1c5000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000098214f00000000000000000000000000000000000000000000000000000000009627d20000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d03403041cbd36888becc7bbcbc0045e3b1f144466f5f8b1ccac8000000000000000000000000000000000000000000000000)
|
11
|
+
|
12
|
+
async function main() {
|
13
|
+
const [deployer] = await hre.ethers.getSigners()
|
14
|
+
console.log(`Deplyer address: ${deployer.address}`)
|
15
|
+
|
16
|
+
const aggregationRouterV5_orig = '0x1111111254eeb25477b68fb85ed929f73a960582'
|
17
|
+
const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
18
|
+
const usdtAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7'
|
19
|
+
const usdtHolderAddr = '0xDFd5293D8e347dFe59E90eFd55b2956a1343963d'
|
20
|
+
const oneInchTx = `0x4c9ddf69000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c80502b1c5000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000005f19b4a0000000000000000000000000000000000000000000000000000000005dfb5bd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d03403041cbd36888becc7bbcbc0045e3b1f144466f5f8b1ccac8000000000000000000000000000000000000000000000000`
|
21
|
+
// 0x4c9ddf69000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e4f78dc253000000000000000000000000cd8fc37291cb0e7ea855b58377adc7bccdad46f900000000000000000000000010c12d979b9e48f208f530ec5f3ea67837a4f8220000000000000000000000000000000000000000000000000000000002faf08000000000000000000000000000000000000000000000000000626340c0ec97ed00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000003b6d034070831b48335d931e07b64ab0c7d28d5e0aec101c00000000000000000000000000000000000000000000000000000000
|
22
|
+
// 0x4c9ddf69000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c8
|
23
|
+
// 0502b1c5000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000098214f00000000000000000000000000000000000000000000000000000000009627d20000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000180000000000000003b6d03403041cbd36888becc7bbcbc0045e3b1f144466f5f8b1ccac8000000000000000000000000000000000000000000000000`
|
24
|
+
// const oneInchTx = '0xf91abd17000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000007aadfda890440000000000000000000000000000000000000000000000000000018e86d4a84500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bec08b12212b461e207ac0b5d6106d9dfe01282e00000000000000000000000026569e2199c92f8b7c3deb52f9b33aee257f9c76'
|
25
|
+
|
26
|
+
// impersonate usdt holder
|
27
|
+
const provider = new hre.ethers.providers.JsonRpcProvider(
|
28
|
+
"http://localhost:8545"
|
29
|
+
);
|
30
|
+
await provider.send("hardhat_impersonateAccount", [usdtHolderAddr]);
|
31
|
+
|
32
|
+
// hre.e
|
33
|
+
// const account = provider.getSigner(usdtHolderAddr);
|
34
|
+
|
35
|
+
// await hre.network.provider.request({
|
36
|
+
// method: 'hardhat_impersonateAccount',
|
37
|
+
// params: [usdtHolderAddr],
|
38
|
+
// })
|
39
|
+
const usdtHolder = await provider.getSigner(usdtHolderAddr)
|
40
|
+
// console.log(`Impersonated usdt holder: ${usdtHolder.address}`)
|
41
|
+
|
42
|
+
const usdtInstance = await hre.ethers.getContractAt('@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol:IERC20Metadata', usdtAddress) as IERC20Metadata
|
43
|
+
const usdcInstance = await hre.ethers.getContractAt('@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol:IERC20Metadata', usdcAddress) as IERC20Metadata
|
44
|
+
|
45
|
+
const oneInchControllerFactory = await hre.ethers.getContractFactory('InchSwapTestController')
|
46
|
+
const testProxyFactory = await hre.ethers.getContractFactory('InchSwapTestProxy')
|
47
|
+
|
48
|
+
const aggregationRouterV5Factory = await hre.ethers.getContractFactory('AggregationRouterV5')
|
49
|
+
const aggregationRouterV5 = await aggregationRouterV5Factory.deploy('0xDFd5293D8e347dFe59E90eFd55b2956a1343963d')
|
50
|
+
console.log(`AggregationRouterV5 deployed at: ${aggregationRouterV5.address}`)
|
51
|
+
|
52
|
+
const testController = await oneInchControllerFactory.deploy(aggregationRouterV5.address)
|
53
|
+
console.log(`test controller deployed at: ${testController.address}`)
|
54
|
+
|
55
|
+
const testProxy = await testProxyFactory.deploy()
|
56
|
+
console.log(`TestProxy deployed at: ${testProxy.address}`)
|
57
|
+
|
58
|
+
const usdtInitialBalance = await usdtInstance.balanceOf(testProxy.address)
|
59
|
+
const usdcInitialBalance = await usdcInstance.balanceOf(testProxy.address)
|
60
|
+
|
61
|
+
console.log(`usdt initial balance: ${usdtInitialBalance.toString()}`)
|
62
|
+
console.log(`usdc initial balance: ${usdcInitialBalance.toString()}`)
|
63
|
+
|
64
|
+
|
65
|
+
await testProxy.addController(constants.UFarm.prtocols.OneInchProtocolString, testController.address)
|
66
|
+
console.log(`OneInchController added to TestProxy`)
|
67
|
+
|
68
|
+
const usdtAmountOut = constants.ONE_HUNDRED_BUCKS.mul(2)
|
69
|
+
if ((await usdtInstance.balanceOf(usdtHolderAddr)).lt(usdtAmountOut)) {
|
70
|
+
throw new Error('usdtAmountOut is greater than balance of holder')
|
71
|
+
}
|
72
|
+
|
73
|
+
await (await usdtInstance.connect(usdtHolder).transfer(testProxy.address, usdtAmountOut)).wait()
|
74
|
+
console.log(`Transferred ${usdtAmountOut} USDT to TestProxy`)
|
75
|
+
|
76
|
+
// make approve from proxyContract
|
77
|
+
// const encodedApproveToAggRouter = usdtInstance.interface.encodeFunctionData('approve', [aggregationRouterV5, hre.ethers.constants.MaxUint256])
|
78
|
+
|
79
|
+
// await testProxy.executeAny(usdtAddress, encodedApproveToAggRouter)
|
80
|
+
// console.log(`Approved ${usdtAmountOut} USDT to AggregationRouter from TestProxy`)
|
81
|
+
|
82
|
+
// const originalControllerFactory = await hre.ethers.getContractFactory('InchSwapTestController')
|
83
|
+
// const oneInchSwapCalldata = originalControllerFactory.interface.encodeFunctionData('delegated1InchSwap',[oneInchTx])
|
84
|
+
console.log(`oneInchSwapCalldata: ${oneInchTx}`)
|
85
|
+
// const oneInchSwapCalldata = encodePoolOneInchSwap(oneInchTx)
|
86
|
+
await testProxy.protocolAction(constants.UFarm.prtocols.OneInchProtocolString, oneInchTx)
|
87
|
+
console.log(`1inch swap executed`)
|
88
|
+
|
89
|
+
const newUsdtBalance = await usdtInstance.balanceOf(usdtHolderAddr)
|
90
|
+
const newUsdcBalance = await usdcInstance.balanceOf(testProxy.address)
|
91
|
+
console.log(`usdt balance after swap: ${newUsdtBalance.toString()}`)
|
92
|
+
console.log(`usdc balance after swap: ${newUsdcBalance.toString()}`)
|
93
|
+
|
94
|
+
}
|
95
|
+
main().catch((error) => {
|
96
|
+
console.error(error)
|
97
|
+
process.exitCode = 1
|
98
|
+
})
|
@@ -0,0 +1,420 @@
|
|
1
|
+
// SPDX-License-Identifier: UNLICENSED
|
2
|
+
|
3
|
+
import { ethers } from 'hardhat'
|
4
|
+
import * as dotenv from 'dotenv'
|
5
|
+
import hre from 'hardhat'
|
6
|
+
import fs from 'fs'
|
7
|
+
import {
|
8
|
+
PoolCreationStruct,
|
9
|
+
constants,
|
10
|
+
deployPool,
|
11
|
+
encodePoolSwapDataUniswapV2,
|
12
|
+
encodePoolAddLiqudityDataUniswapV2,
|
13
|
+
getEventFromTx,
|
14
|
+
mintAndDeposit,
|
15
|
+
getBlockchainTimestamp,
|
16
|
+
mintAndCreatePairUniV2,
|
17
|
+
mintAndCreatePairUniV2WithEth,
|
18
|
+
logChangeBalanceWrapper,
|
19
|
+
packPerformanceCommission,
|
20
|
+
} from '../test/_helpers'
|
21
|
+
import {
|
22
|
+
IERC20,
|
23
|
+
IERC20Metadata__factory,
|
24
|
+
PoolAdmin,
|
25
|
+
PriceOracle,
|
26
|
+
UFarmCore,
|
27
|
+
UFarmPool,
|
28
|
+
UniswapV2Factory,
|
29
|
+
} from '../typechain-types'
|
30
|
+
import { BigNumber } from 'ethers'
|
31
|
+
import { customSetTimeout, retryOperation } from './_deploy_helpers'
|
32
|
+
|
33
|
+
dotenv.config()
|
34
|
+
|
35
|
+
type ContractInfo = {
|
36
|
+
address: string
|
37
|
+
abi: any[]
|
38
|
+
}
|
39
|
+
|
40
|
+
type RequiredContracts = 'UFarmCore' | 'TestFund' | 'USDT' | 'USDC' | 'WETH'
|
41
|
+
|
42
|
+
type Deployments = {
|
43
|
+
name: string
|
44
|
+
chainId: string
|
45
|
+
contracts: {
|
46
|
+
[contractName in RequiredContracts]: ContractInfo
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
async function isUniswapV2PairExist(
|
51
|
+
factoryContract: UniswapV2Factory,
|
52
|
+
token0Address: string,
|
53
|
+
token1Address: string,
|
54
|
+
): Promise<boolean> {
|
55
|
+
try {
|
56
|
+
const pairAddress = await factoryContract.getPair(token0Address, token1Address)
|
57
|
+
return (await hre.ethers.provider.getCode(pairAddress)) !== '0x'
|
58
|
+
} catch (error) {
|
59
|
+
console.error('Error checking pair existence:', error)
|
60
|
+
return false
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
const increaseGasLimit = (estimatedGasLimit: BigNumber) => {
|
65
|
+
return estimatedGasLimit.mul(130).div(100) // increase by 30%
|
66
|
+
}
|
67
|
+
|
68
|
+
async function main(iterations: number = 150_000, pool1_addr?: string, pool2_addr?: string) {
|
69
|
+
console.log('Starting pool data script...')
|
70
|
+
|
71
|
+
const [deployer, alice, bob, carol, david, emma] = await ethers.getSigners()
|
72
|
+
|
73
|
+
const deployConfig: Deployments = JSON.parse(fs.readFileSync(hre.deploymentsJsonPath, 'utf8'))
|
74
|
+
|
75
|
+
const [core_addr, fund_addr, usdt_addr, usdc_addr, weth_addr] = [
|
76
|
+
deployConfig.contracts.UFarmCore.address,
|
77
|
+
deployConfig.contracts.TestFund.address,
|
78
|
+
deployConfig.contracts.USDT.address,
|
79
|
+
deployConfig.contracts.USDC.address,
|
80
|
+
deployConfig.contracts.WETH.address,
|
81
|
+
]
|
82
|
+
|
83
|
+
const [core_instance, fund_instance, usdt_instance, usdc_instance, weth_instance] = [
|
84
|
+
await ethers.getContractAt('UFarmCore', core_addr, deployer),
|
85
|
+
await ethers.getContractAt('UFarmFund', fund_addr, deployer),
|
86
|
+
await ethers.getContractAt('StableCoin', usdt_addr, deployer),
|
87
|
+
await ethers.getContractAt('StableCoin', usdc_addr, deployer),
|
88
|
+
await ethers.getContractAt('WETH9', weth_addr, deployer),
|
89
|
+
]
|
90
|
+
|
91
|
+
// Create 2 new pools
|
92
|
+
|
93
|
+
const getPools = async (pool1_addr?: string, pool2_addr?: string) => {
|
94
|
+
if (pool1_addr && pool2_addr) {
|
95
|
+
return [
|
96
|
+
await ethers.getContractAt('UFarmPool', pool1_addr, david),
|
97
|
+
await ethers.getContractAt('UFarmPool', pool2_addr, emma),
|
98
|
+
]
|
99
|
+
}
|
100
|
+
|
101
|
+
const emptyPoolArgs: PoolCreationStruct = {
|
102
|
+
minInvestment: 0,
|
103
|
+
maxInvestment: hre.ethers.constants.MaxUint256,
|
104
|
+
managementCommission: hre.ethers.constants.One.div(101),
|
105
|
+
packedPerformanceCommission: packPerformanceCommission([{
|
106
|
+
step: 0,
|
107
|
+
commission: Math.floor(constants.Pool.Commission.MAX_PERFORMANCE_COMMISION / 80)
|
108
|
+
}]),
|
109
|
+
withdrawalLockupPeriod: 0,
|
110
|
+
valueToken: usdt_addr,
|
111
|
+
staff: [],
|
112
|
+
name: 'name',
|
113
|
+
symbol: 'symbol',
|
114
|
+
}
|
115
|
+
|
116
|
+
const pool1 = (
|
117
|
+
await retryOperation(async () => {
|
118
|
+
return await deployPool(
|
119
|
+
{ ...emptyPoolArgs, name: 'Data-Pool-1', symbol: 'dp-1' },
|
120
|
+
fund_instance,
|
121
|
+
)
|
122
|
+
}, 5)
|
123
|
+
).pool.connect(david)
|
124
|
+
|
125
|
+
const pool2 = (
|
126
|
+
await retryOperation(async () => {
|
127
|
+
return await deployPool(
|
128
|
+
{ ...emptyPoolArgs, name: 'Data-Pool-2', symbol: 'dp-2' },
|
129
|
+
fund_instance,
|
130
|
+
)
|
131
|
+
}, 5)
|
132
|
+
).pool.connect(emma)
|
133
|
+
|
134
|
+
console.log(`Pools:\n${pool1.address}\n${pool2.address}`)
|
135
|
+
|
136
|
+
// Deposit 10k USDT into each pool
|
137
|
+
const tenThousandBucks = BigNumber.from(10_000).mul(1e6)
|
138
|
+
await usdt_instance.mint(fund_addr, tenThousandBucks.mul(2))
|
139
|
+
console.log('Minted 20k USDT to fund contract')
|
140
|
+
|
141
|
+
await retryOperation(async () => {
|
142
|
+
await fund_instance.depositToPool(pool1.address, tenThousandBucks)
|
143
|
+
}, 5)
|
144
|
+
console.log('Deposited 10k USDT into pool 1')
|
145
|
+
|
146
|
+
await retryOperation(async () => {
|
147
|
+
await fund_instance.depositToPool(pool2.address, tenThousandBucks)
|
148
|
+
}, 5)
|
149
|
+
console.log('Deposited 10k USDT into pool 2')
|
150
|
+
|
151
|
+
// Buy USDC and WETH with USDT on UniswapV2 for each pool
|
152
|
+
const buyUSDCdata = async () => {
|
153
|
+
return encodePoolSwapDataUniswapV2(
|
154
|
+
tenThousandBucks.div(2),
|
155
|
+
BigNumber.from(1000),
|
156
|
+
(await getBlockchainTimestamp(hre.ethers.provider)) + 200,
|
157
|
+
[usdt_addr, usdc_addr],
|
158
|
+
)
|
159
|
+
}
|
160
|
+
|
161
|
+
const buyWETHdata = async () => {
|
162
|
+
return encodePoolSwapDataUniswapV2(
|
163
|
+
tenThousandBucks.div(2),
|
164
|
+
BigNumber.from(1000),
|
165
|
+
(await getBlockchainTimestamp(hre.ethers.provider)) + 200,
|
166
|
+
[usdt_addr, weth_addr],
|
167
|
+
)
|
168
|
+
}
|
169
|
+
|
170
|
+
await retryOperation(async () => {
|
171
|
+
await (
|
172
|
+
await pool1.protocolAction(
|
173
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
174
|
+
await buyUSDCdata(),
|
175
|
+
)
|
176
|
+
).wait()
|
177
|
+
}, 5)
|
178
|
+
console.log(`Bought ${await usdc_instance.balanceOf(pool1.address)} USDC with USDT on pool 1`)
|
179
|
+
|
180
|
+
await retryOperation(async () => {
|
181
|
+
await (
|
182
|
+
await pool2.protocolAction(
|
183
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
184
|
+
await buyUSDCdata(),
|
185
|
+
)
|
186
|
+
).wait()
|
187
|
+
}, 5)
|
188
|
+
console.log(`Bought ${await usdc_instance.balanceOf(pool2.address)} USDC with USDT on pool 2`)
|
189
|
+
|
190
|
+
await retryOperation(async () => {
|
191
|
+
await (
|
192
|
+
await pool1.protocolAction(
|
193
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
194
|
+
await buyWETHdata(),
|
195
|
+
)
|
196
|
+
).wait()
|
197
|
+
}, 5)
|
198
|
+
console.log(`Bought ${await weth_instance.balanceOf(pool1.address)} WETH with USDT on pool 1`)
|
199
|
+
|
200
|
+
await retryOperation(async () => {
|
201
|
+
await (
|
202
|
+
await pool2.protocolAction(
|
203
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
204
|
+
await buyWETHdata(),
|
205
|
+
)
|
206
|
+
).wait()
|
207
|
+
}, 5)
|
208
|
+
console.log(`Bought ${await weth_instance.balanceOf(pool2.address)} WETH with USDT on pool 2`)
|
209
|
+
|
210
|
+
// Become liquidity provider of USDC/WETH pair
|
211
|
+
const addLiquidityData = async (pool: UFarmPool) => {
|
212
|
+
const [usdcBalance, wethBalance] = await Promise.all([
|
213
|
+
usdc_instance.balanceOf(pool.address),
|
214
|
+
weth_instance.balanceOf(pool.address),
|
215
|
+
])
|
216
|
+
|
217
|
+
const UniV2Controller_addr = await core_instance.controllers(
|
218
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
219
|
+
)
|
220
|
+
|
221
|
+
const UniV2Controller_instance = await ethers.getContractAt(
|
222
|
+
'UnoswapV2Controller',
|
223
|
+
UniV2Controller_addr,
|
224
|
+
deployer,
|
225
|
+
)
|
226
|
+
|
227
|
+
const getQuotedAmounts = async (): ReturnType<
|
228
|
+
typeof UniV2Controller_instance.quoteExactLiquidityAmounts
|
229
|
+
> => {
|
230
|
+
try {
|
231
|
+
const quotedAmounts = await UniV2Controller_instance.quoteExactLiquidityAmounts(
|
232
|
+
usdc_addr,
|
233
|
+
weth_addr,
|
234
|
+
usdcBalance,
|
235
|
+
wethBalance,
|
236
|
+
1000,
|
237
|
+
1000,
|
238
|
+
(await getBlockchainTimestamp(hre.ethers.provider)) + 200,
|
239
|
+
)
|
240
|
+
|
241
|
+
console.log(
|
242
|
+
`Quoted amounts: ${quotedAmounts[0].toString()}, ${quotedAmounts[1].toString()}`,
|
243
|
+
)
|
244
|
+
|
245
|
+
return quotedAmounts
|
246
|
+
} catch (error) {
|
247
|
+
console.log('Checking for pair existence...')
|
248
|
+
const [factory_addr, router_addr] = await Promise.all([
|
249
|
+
UniV2Controller_instance.factory(),
|
250
|
+
UniV2Controller_instance.router(),
|
251
|
+
])
|
252
|
+
const factory_instance = await ethers.getContractAt(
|
253
|
+
'UniswapV2Factory',
|
254
|
+
factory_addr,
|
255
|
+
deployer,
|
256
|
+
)
|
257
|
+
const router_instance = await ethers.getContractAt(
|
258
|
+
'UniswapV2Router02',
|
259
|
+
router_addr,
|
260
|
+
deployer,
|
261
|
+
)
|
262
|
+
if (await isUniswapV2PairExist(factory_instance, usdc_addr, weth_addr)) {
|
263
|
+
console.log('Pair already exists')
|
264
|
+
} else {
|
265
|
+
await mintAndCreatePairUniV2WithEth(
|
266
|
+
usdc_instance,
|
267
|
+
BigNumber.from(10).pow(6).mul(2000),
|
268
|
+
constants.ONE,
|
269
|
+
deployer,
|
270
|
+
router_instance,
|
271
|
+
)
|
272
|
+
console.log('Pair created!')
|
273
|
+
}
|
274
|
+
// retry
|
275
|
+
return await getQuotedAmounts()
|
276
|
+
}
|
277
|
+
|
278
|
+
}
|
279
|
+
|
280
|
+
await getQuotedAmounts()
|
281
|
+
|
282
|
+
return encodePoolAddLiqudityDataUniswapV2(
|
283
|
+
usdc_addr,
|
284
|
+
weth_addr,
|
285
|
+
usdcBalance.div(2),
|
286
|
+
wethBalance.div(2),
|
287
|
+
1000,
|
288
|
+
1000,
|
289
|
+
(await getBlockchainTimestamp(hre.ethers.provider)) + 200,
|
290
|
+
)
|
291
|
+
}
|
292
|
+
|
293
|
+
const poolAddLiquidity = async (pool: UFarmPool) => {
|
294
|
+
const addLiqData = await addLiquidityData(pool)
|
295
|
+
const estimateAddLiquidty = await pool.estimateGas.protocolAction(
|
296
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
297
|
+
addLiqData,
|
298
|
+
)
|
299
|
+
|
300
|
+
const receiptAddLiq = await (
|
301
|
+
await pool.protocolAction(constants.UFarm.prtocols.UniswapV2ProtocolString, addLiqData, {
|
302
|
+
gasLimit: increaseGasLimit(estimateAddLiquidty),
|
303
|
+
})
|
304
|
+
).wait()
|
305
|
+
|
306
|
+
console.log(`Added liquidity to pool ${pool.address} in block ${receiptAddLiq.blockNumber}`)
|
307
|
+
}
|
308
|
+
|
309
|
+
await poolAddLiquidity(pool1)
|
310
|
+
await poolAddLiquidity(pool2)
|
311
|
+
|
312
|
+
console.log('Preparation done!')
|
313
|
+
|
314
|
+
return [pool1, pool2]
|
315
|
+
}
|
316
|
+
|
317
|
+
const [pool1, pool2] = await getPools(pool1_addr, pool2_addr)
|
318
|
+
|
319
|
+
const ufarmCore_addr = await pool1.ufarmCore()
|
320
|
+
const ufarmCore_instance = await ethers.getContractAt('UFarmCore', ufarmCore_addr, deployer)
|
321
|
+
|
322
|
+
const UnoswapV2Controller_addr = await ufarmCore_instance.controllers(
|
323
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
324
|
+
)
|
325
|
+
|
326
|
+
const UnoswapV2Controller_instance = await ethers.getContractAt(
|
327
|
+
'UnoswapV2Controller',
|
328
|
+
UnoswapV2Controller_addr,
|
329
|
+
deployer,
|
330
|
+
)
|
331
|
+
|
332
|
+
const encodeSwapOfHalf = async (pool: UFarmPool, swapTo: string, swapFrom: string) => {
|
333
|
+
const swapFrom_instance = IERC20Metadata__factory.connect(swapFrom, deployer)
|
334
|
+
const swapTo_instance = IERC20Metadata__factory.connect(swapTo, deployer)
|
335
|
+
|
336
|
+
const [symbol1, symbol2] = await Promise.all([
|
337
|
+
swapFrom_instance.symbol(),
|
338
|
+
swapTo_instance.symbol(),
|
339
|
+
])
|
340
|
+
|
341
|
+
const amountToSwap = (await swapFrom_instance.balanceOf(pool.address)).div(2)
|
342
|
+
const timestamp = (await getBlockchainTimestamp(hre.ethers.provider)) + 200
|
343
|
+
const amountOut = await UnoswapV2Controller_instance.getAmountOut(amountToSwap, [
|
344
|
+
swapFrom,
|
345
|
+
swapTo,
|
346
|
+
])
|
347
|
+
|
348
|
+
console.log(
|
349
|
+
`Going to swap ${amountToSwap.toString()} ${symbol1} to ${amountOut.toString()} ${symbol2}`,
|
350
|
+
)
|
351
|
+
|
352
|
+
return encodePoolSwapDataUniswapV2(amountToSwap, BigNumber.from(10000), timestamp, [
|
353
|
+
swapFrom,
|
354
|
+
swapTo,
|
355
|
+
])
|
356
|
+
}
|
357
|
+
|
358
|
+
async function threeRetries<T>(fn: () => Promise<T>): Promise<T> {
|
359
|
+
return await retryOperation(async () => {
|
360
|
+
return fn()
|
361
|
+
}, 3)
|
362
|
+
}
|
363
|
+
|
364
|
+
async function logBalanceSwapRetry<T>(pool: UFarmPool, token1: string, token2: string) {
|
365
|
+
return await logChangeBalanceWrapper(
|
366
|
+
async () => {
|
367
|
+
return await threeRetries(async () => {
|
368
|
+
const encodedSwap1 = await encodeSwapOfHalf(pool, token1, token2)
|
369
|
+
|
370
|
+
const estimatedGasLimit = await pool.estimateGas.protocolAction(
|
371
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
372
|
+
encodedSwap1,
|
373
|
+
)
|
374
|
+
|
375
|
+
return await (
|
376
|
+
await pool.protocolAction(
|
377
|
+
constants.UFarm.prtocols.UniswapV2ProtocolString,
|
378
|
+
encodedSwap1,
|
379
|
+
{
|
380
|
+
gasLimit: increaseGasLimit(estimatedGasLimit),
|
381
|
+
},
|
382
|
+
)
|
383
|
+
).wait()
|
384
|
+
})
|
385
|
+
},
|
386
|
+
pool.address,
|
387
|
+
token1,
|
388
|
+
token2,
|
389
|
+
)
|
390
|
+
}
|
391
|
+
|
392
|
+
const swapToAndFrom = async (pool: UFarmPool, swapTo: string, swapFrom: string) => {
|
393
|
+
const receiptTo = await logBalanceSwapRetry(pool, swapTo, swapFrom)
|
394
|
+
console.log(`Block: ${receiptTo.blockNumber}`)
|
395
|
+
|
396
|
+
await customSetTimeout(15)
|
397
|
+
|
398
|
+
const receiptFrom = await logBalanceSwapRetry(pool, swapFrom, swapTo)
|
399
|
+
console.log(`Block: ${receiptFrom.blockNumber}`)
|
400
|
+
await customSetTimeout(15)
|
401
|
+
|
402
|
+
}
|
403
|
+
|
404
|
+
for (let i = 0; i < iterations; i++) {
|
405
|
+
console.log(`Iteration ${i + 1} from ${iterations}`)
|
406
|
+
|
407
|
+
await swapToAndFrom(pool1, usdc_addr, weth_addr)
|
408
|
+
console.log('Swapped USDC <=> WETH on pool 1')
|
409
|
+
|
410
|
+
await swapToAndFrom(pool2, usdc_addr, weth_addr)
|
411
|
+
console.log('Swapped USDC <=> WETH on pool 2\n')
|
412
|
+
}
|
413
|
+
|
414
|
+
// TODO: sell liquidity and buy it again
|
415
|
+
}
|
416
|
+
|
417
|
+
main().catch((error) => {
|
418
|
+
console.error(error)
|
419
|
+
process.exitCode = 1
|
420
|
+
})
|