@dhedge/v2-sdk 2.1.8 → 2.2.0
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/README.md +400 -53
- package/dist/config.d.ts +13 -2
- package/dist/entities/pool.d.ts +25 -86
- package/dist/entities/utils.d.ts +15 -0
- package/dist/services/hyperliquid/index.d.ts +22 -0
- package/dist/services/kyberSwap/index.d.ts +1 -1
- package/dist/services/oneInch/index.d.ts +1 -1
- package/dist/services/toros/easySwapper.d.ts +14 -0
- package/dist/services/toros/swapData.d.ts +5 -5
- package/dist/services/uniswap/V3Liquidity.d.ts +2 -2
- package/dist/services/velodrome/liquidity.d.ts +3 -0
- package/dist/test/constants.d.ts +48 -3
- package/dist/test/utils/testingHelper.d.ts +4 -0
- package/dist/types.d.ts +19 -4
- package/dist/utils/contract.d.ts +20 -0
- package/dist/v2-sdk.cjs.development.js +4996 -6742
- package/dist/v2-sdk.cjs.development.js.map +1 -1
- package/dist/v2-sdk.cjs.production.min.js +1 -1
- package/dist/v2-sdk.cjs.production.min.js.map +1 -1
- package/dist/v2-sdk.esm.js +5001 -6742
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/PoolFactory.json +414 -204
- package/src/abi/PoolLogic.json +160 -134
- package/src/config.ts +13 -8
- package/src/entities/pool.ts +46 -253
- package/src/entities/utils.ts +15 -0
- package/src/services/hyperliquid/index.ts +22 -0
- package/src/services/kyberSwap/index.ts +5 -3
- package/src/services/oneInch/index.ts +5 -4
- package/src/services/toros/completeWithdrawal.ts +57 -40
- package/src/services/toros/easySwapper.ts +15 -1
- package/src/services/toros/initWithdrawal.ts +39 -31
- package/src/services/toros/swapData.ts +45 -131
- package/src/services/uniswap/V3Liquidity.ts +3 -24
- package/src/services/velodrome/liquidity.ts +3 -0
- package/src/test/aave.test.ts +99 -70
- package/src/test/aerodrome.test.ts +53 -24
- package/src/test/aerodromeCL.test.ts +64 -30
- package/src/test/arrakis.test.ts +23 -35
- package/src/test/balancer.test.ts +114 -106
- package/src/test/compoundV3.test.ts +45 -29
- package/src/test/constants.ts +56 -11
- package/src/test/cowswap.test.ts +33 -35
- package/src/test/dhedge.test.ts +45 -12
- package/src/test/flatmoney.test.ts +25 -39
- package/src/test/fluid.test.ts +33 -24
- package/src/test/hyperliquid.onchain.test.ts +131 -0
- package/src/test/kyberSwap.test.ts +37 -16
- package/src/test/lyra.test.ts +159 -150
- package/src/test/odos.test.ts +2 -2
- package/src/test/oneInch.test.ts +36 -22
- package/src/test/pancakeCL.test.ts +72 -31
- package/src/test/pendle.test.ts +94 -54
- package/src/test/{pendleMint.test.ts → pendleMint.onchain.test.ts} +22 -8
- package/src/test/pool.test.ts +152 -95
- package/src/test/toros.onchain.test.ts +92 -0
- package/src/test/toros.test.ts +74 -20
- package/src/test/torosLimitOrder.test.ts +87 -42
- package/src/test/uniswap.test.ts +77 -128
- package/src/test/utils/testingHelper.ts +120 -0
- package/src/test/velodrome.test.ts +126 -92
- package/src/test/velodromeCL.test.ts +43 -31
- package/src/test/velodromeV2.test.ts +153 -95
- package/src/types.ts +20 -5
- package/src/utils/contract.ts +20 -0
- package/dist/services/futures/constants.d.ts +0 -1
- package/dist/services/futures/index.d.ts +0 -2
- package/dist/services/futures/margin.d.ts +0 -2
- package/dist/services/futures/trade.d.ts +0 -3
- package/dist/services/ramses/vesting.d.ts +0 -4
- package/dist/services/uniswap/V3Trade.d.ts +0 -3
- package/dist/test/utils/futures.d.ts +0 -2
- package/src/abi/IRamsesNonfungiblePositionManager.json +0 -486
- package/src/abi/ISynthetiXFuturesMarketV2.json +0 -531
- package/src/abi/ISynthetix.json +0 -139
- package/src/abi/IUniswapV3Quoter.json +0 -195
- package/src/abi/IUniswapV3Router.json +0 -221
- package/src/abi/IXRam.json +0 -99
- package/src/services/futures/constants.ts +0 -1
- package/src/services/futures/index.ts +0 -2
- package/src/services/futures/margin.ts +0 -10
- package/src/services/futures/trade.ts +0 -32
- package/src/services/ramses/vesting.ts +0 -24
- package/src/services/uniswap/V3Trade.ts +0 -46
- package/src/test/futures.test.ts +0 -51
- package/src/test/hyperliquid.test.ts +0 -107
- package/src/test/ramses.test.ts +0 -190
- package/src/test/ramsesCL.test.ts +0 -155
- package/src/test/synthetix.test.ts +0 -36
- package/src/test/utils/futures.ts +0 -14
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
} from "../constants";
|
|
10
10
|
import { Pool } from "../../entities";
|
|
11
11
|
import AssetHandler from "../../abi/AssetHandler.json";
|
|
12
|
+
import PoolLogicAbi from "../../abi/PoolLogic.json";
|
|
13
|
+
import PoolManagerLogicAbi from "../../abi/PoolManagerLogic.json";
|
|
12
14
|
|
|
13
15
|
export type TestingRunParams = {
|
|
14
16
|
network: Network;
|
|
@@ -146,6 +148,124 @@ export const runWithImpersonateAccount = async (
|
|
|
146
148
|
await provider.send("hardhat_stopImpersonatingAccount", [account]);
|
|
147
149
|
};
|
|
148
150
|
|
|
151
|
+
// Fixes oracle staleness reverts on hardhat forks for ChainlinkPythPriceAggregator and PythPriceAggregator.
|
|
152
|
+
// These aggregators have their own maxAge staleness checks separate from the AssetHandler's chainlinkTimeout.
|
|
153
|
+
// This function dynamically finds all such aggregators for a pool's supported assets and overrides
|
|
154
|
+
// their maxAge fields to max uint32 (0xffffffff, ~136 years).
|
|
155
|
+
//
|
|
156
|
+
// Slot layouts below are written in big-endian hex order (high-order bytes first), matching the 64-char
|
|
157
|
+
// string returned by eth_getStorageAt. Within a packed slot, Solidity lays fields out from the low-order
|
|
158
|
+
// end in declaration order — so the first declared field ends up on the right side of the hex string.
|
|
159
|
+
//
|
|
160
|
+
// ChainlinkPythPriceAggregator storage layout:
|
|
161
|
+
// slot 0: asset (address)
|
|
162
|
+
// slot 1: oracleData.onchainOracle = [8 bytes padding][4 bytes maxAge][20 bytes oracleContract]
|
|
163
|
+
// → maxAge at hex offset 16
|
|
164
|
+
// slot 2: oracleData.offchainOracle.priceId (bytes32)
|
|
165
|
+
// slot 3: oracleData.offchainOracle = [24 bytes padding][4 bytes maxAge][4 bytes minConfidenceRatio]
|
|
166
|
+
// → maxAge at hex offset 48
|
|
167
|
+
//
|
|
168
|
+
// PythPriceAggregator storage layout:
|
|
169
|
+
// slot 0: asset (address)
|
|
170
|
+
// slot 1: oracleData.priceId (bytes32)
|
|
171
|
+
// slot 2: oracleData = [24 bytes padding][4 bytes maxAge][4 bytes minConfidenceRatio]
|
|
172
|
+
// → maxAge at hex offset 48
|
|
173
|
+
const MAX_UINT32_HEX = "ffffffff";
|
|
174
|
+
|
|
175
|
+
const overrideMaxAgeInSlot = async (
|
|
176
|
+
provider: ethers.providers.JsonRpcProvider,
|
|
177
|
+
contractAddress: string,
|
|
178
|
+
slotIndex: string,
|
|
179
|
+
maxAgeHexOffset: number // character offset of maxAge within the 64-char hex string
|
|
180
|
+
): Promise<void> => {
|
|
181
|
+
const slot: string = await provider.send("eth_getStorageAt", [
|
|
182
|
+
contractAddress,
|
|
183
|
+
slotIndex,
|
|
184
|
+
"latest"
|
|
185
|
+
]);
|
|
186
|
+
const hex = slot.slice(2); // remove 0x
|
|
187
|
+
const newHex =
|
|
188
|
+
hex.slice(0, maxAgeHexOffset) +
|
|
189
|
+
MAX_UINT32_HEX +
|
|
190
|
+
hex.slice(maxAgeHexOffset + 8);
|
|
191
|
+
await provider.send("hardhat_setStorageAt", [
|
|
192
|
+
contractAddress,
|
|
193
|
+
slotIndex,
|
|
194
|
+
"0x" + newHex
|
|
195
|
+
]);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export const fixOracleAggregatorStaleness = async ({
|
|
199
|
+
pool,
|
|
200
|
+
provider
|
|
201
|
+
}: {
|
|
202
|
+
pool: Pool;
|
|
203
|
+
provider: ethers.providers.JsonRpcProvider;
|
|
204
|
+
}): Promise<void> => {
|
|
205
|
+
const assetHandlerAddress = await pool.factory.callStatic.getAssetHandler();
|
|
206
|
+
const assetHandlerContract = new Contract(
|
|
207
|
+
assetHandlerAddress,
|
|
208
|
+
AssetHandler.abi,
|
|
209
|
+
provider
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Resolve managerLogic from poolLogic to support both isDhedge=true and isDhedge=false pools
|
|
213
|
+
const poolLogic = new Contract(pool.address, PoolLogicAbi.abi, provider);
|
|
214
|
+
const managerLogicAddress: string = await poolLogic.poolManagerLogic();
|
|
215
|
+
const managerLogic = new Contract(
|
|
216
|
+
managerLogicAddress,
|
|
217
|
+
PoolManagerLogicAbi.abi,
|
|
218
|
+
provider
|
|
219
|
+
);
|
|
220
|
+
const supportedAssets: {
|
|
221
|
+
asset: string;
|
|
222
|
+
}[] = await managerLogic.getSupportedAssets();
|
|
223
|
+
|
|
224
|
+
// ABI fragments to detect aggregator type
|
|
225
|
+
const chainlinkPythAbi = [
|
|
226
|
+
"function oracleData() view returns (address oracleContract, uint32 maxAge)"
|
|
227
|
+
];
|
|
228
|
+
const pythAbi = [
|
|
229
|
+
"function oracleData() view returns (bytes32 priceId, uint32 maxAge, uint32 minConfidenceRatio)"
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
for (const { asset } of supportedAssets) {
|
|
233
|
+
try {
|
|
234
|
+
const aggregatorAddress: string = await assetHandlerContract.priceAggregators(
|
|
235
|
+
asset
|
|
236
|
+
);
|
|
237
|
+
if (aggregatorAddress === ethers.constants.AddressZero) continue;
|
|
238
|
+
|
|
239
|
+
// Try ChainlinkPythPriceAggregator first (has onchainOracle + offchainOracle)
|
|
240
|
+
const agg = new Contract(aggregatorAddress, chainlinkPythAbi, provider);
|
|
241
|
+
try {
|
|
242
|
+
await agg.oracleData();
|
|
243
|
+
// ChainlinkPythPriceAggregator detected.
|
|
244
|
+
// Slot 1 layout: [8 bytes padding][4 bytes maxAge][20 bytes oracleContract] → maxAge at offset 16
|
|
245
|
+
await overrideMaxAgeInSlot(provider, aggregatorAddress, "0x1", 16);
|
|
246
|
+
// Slot 3 layout: [24 bytes padding][4 bytes maxAge][4 bytes minConfidenceRatio] → maxAge at offset 48
|
|
247
|
+
await overrideMaxAgeInSlot(provider, aggregatorAddress, "0x3", 48);
|
|
248
|
+
continue;
|
|
249
|
+
} catch {
|
|
250
|
+
// Not a ChainlinkPythPriceAggregator
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Try PythPriceAggregator (has only offchainOracle)
|
|
254
|
+
const pythAgg = new Contract(aggregatorAddress, pythAbi, provider);
|
|
255
|
+
try {
|
|
256
|
+
await pythAgg.oracleData();
|
|
257
|
+
// PythPriceAggregator detected.
|
|
258
|
+
// Slot 2 layout: [24 bytes padding][4 bytes maxAge][4 bytes minConfidenceRatio] → maxAge at offset 48
|
|
259
|
+
await overrideMaxAgeInSlot(provider, aggregatorAddress, "0x2", 48);
|
|
260
|
+
} catch {
|
|
261
|
+
// Not a PythPriceAggregator either — skip
|
|
262
|
+
}
|
|
263
|
+
} catch {
|
|
264
|
+
// No aggregator set for this asset — skip
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
149
269
|
export const setChainlinkTimeout = async (
|
|
150
270
|
{
|
|
151
271
|
pool,
|
|
@@ -4,111 +4,145 @@ import { Dhedge, Pool } from "..";
|
|
|
4
4
|
import { routerAddress } from "../config";
|
|
5
5
|
import { Dapp, Network } from "../types";
|
|
6
6
|
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
7
|
+
import {
|
|
8
|
+
TestingRunParams,
|
|
9
|
+
fixOracleAggregatorStaleness,
|
|
10
|
+
runWithImpersonateAccount,
|
|
11
|
+
setChainlinkTimeout,
|
|
12
|
+
testingHelper
|
|
13
|
+
} from "./utils/testingHelper";
|
|
7
14
|
import { allowanceDelta, balanceDelta } from "./utils/token";
|
|
8
15
|
|
|
9
|
-
import { wallet } from "./wallet";
|
|
10
|
-
|
|
11
16
|
const USDC_SUSD_Lp = "0xd16232ad60188b68076a235c65d692090caba155";
|
|
12
17
|
const USDC_SUSD_Gauge = "0xb03f52d2db3e758dd49982defd6aeefea9454e80";
|
|
13
|
-
const network = Network.OPTIMISM;
|
|
14
|
-
const SUSD = CONTRACT_ADDRESS[network].SUSD;
|
|
15
|
-
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const testVelodrome = ({ wallet, network, provider }: TestingRunParams) => {
|
|
20
|
+
const SUSD = CONTRACT_ADDRESS[network].SUSD;
|
|
21
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
25
|
-
});
|
|
23
|
+
let dhedge: Dhedge;
|
|
24
|
+
let pool: Pool;
|
|
25
|
+
jest.setTimeout(100000);
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
pool.
|
|
35
|
-
);
|
|
36
|
-
await expect(UsdcAllowanceDelta.gt(0));
|
|
37
|
-
});
|
|
27
|
+
describe(`pool on ${network}`, () => {
|
|
28
|
+
beforeAll(async () => {
|
|
29
|
+
await provider.send("hardhat_setBalance", [
|
|
30
|
+
wallet.address,
|
|
31
|
+
"0x10000000000000000"
|
|
32
|
+
]);
|
|
33
|
+
dhedge = new Dhedge(wallet, network);
|
|
34
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
USDC,
|
|
42
|
-
SUSD,
|
|
43
|
-
(5 * 1e6).toString(),
|
|
44
|
-
(5 * 1e18).toString(),
|
|
45
|
-
true
|
|
46
|
-
);
|
|
36
|
+
await setChainlinkTimeout({ pool, provider }, 86400 * 365);
|
|
37
|
+
await fixOracleAggregatorStaleness({ pool, provider });
|
|
47
38
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
await runWithImpersonateAccount(
|
|
40
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
41
|
+
async ({ signer }) => {
|
|
42
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
43
|
+
await pool.managerLogic.connect(signer).changeAssets(
|
|
44
|
+
[
|
|
45
|
+
[USDC, true],
|
|
46
|
+
[SUSD, true],
|
|
47
|
+
[USDC_SUSD_Lp, false]
|
|
48
|
+
],
|
|
49
|
+
[]
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
});
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
it("approves unlimited sUSD and USDC on for Velodrome", async () => {
|
|
56
|
+
await pool.approve(Dapp.VELODROME, SUSD, MAX_AMOUNT);
|
|
57
|
+
await pool.approve(Dapp.VELODROME, USDC, MAX_AMOUNT);
|
|
58
|
+
const UsdcAllowanceDelta = await allowanceDelta(
|
|
59
|
+
pool.address,
|
|
60
|
+
USDC,
|
|
61
|
+
routerAddress[network].velodrome!,
|
|
62
|
+
pool.signer
|
|
63
|
+
);
|
|
64
|
+
expect(UsdcAllowanceDelta.gt(0)).toBe(true);
|
|
65
|
+
});
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
it("adds USDC and SUSD to a Velodrome stable pool", async () => {
|
|
68
|
+
await pool.addLiquidityVelodrome(
|
|
69
|
+
USDC,
|
|
70
|
+
SUSD,
|
|
71
|
+
(5 * 1e6).toString(),
|
|
72
|
+
(5 * 1e18).toString(),
|
|
73
|
+
true
|
|
74
|
+
);
|
|
72
75
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
pool.address,
|
|
81
|
-
USDC_SUSD_Lp,
|
|
82
|
-
pool.signer
|
|
83
|
-
);
|
|
84
|
-
expect(lpTokenDelta.gt(0));
|
|
85
|
-
});
|
|
76
|
+
const lpTokenDelta = await balanceDelta(
|
|
77
|
+
pool.address,
|
|
78
|
+
USDC_SUSD_Lp,
|
|
79
|
+
pool.signer
|
|
80
|
+
);
|
|
81
|
+
expect(lpTokenDelta.gt(0)).toBe(true);
|
|
82
|
+
});
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
pool.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
84
|
+
it("should stake USDC-sUSD LP in a gauge", async () => {
|
|
85
|
+
const balance = await dhedge.utils.getBalance(USDC_SUSD_Lp, pool.address);
|
|
86
|
+
await pool.approveSpender(USDC_SUSD_Gauge, USDC_SUSD_Lp, MAX_AMOUNT);
|
|
87
|
+
await pool.stakeInGauge(Dapp.VELODROME, USDC_SUSD_Gauge, balance);
|
|
88
|
+
const gaugeBalance = await balanceDelta(
|
|
89
|
+
pool.address,
|
|
90
|
+
USDC_SUSD_Lp,
|
|
91
|
+
pool.signer
|
|
92
|
+
);
|
|
93
|
+
expect(gaugeBalance.gt(0)).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should claim rewards from Gauge", async () => {
|
|
97
|
+
const tx = await pool.claimFees(Dapp.VELODROME, USDC_SUSD_Gauge);
|
|
98
|
+
expect(tx).not.toBe(null);
|
|
99
|
+
});
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
|
|
101
|
+
it("should unStake USDC-sUSD LP from a gauge", async () => {
|
|
102
|
+
const gaugeBalance = await dhedge.utils.getBalance(
|
|
103
|
+
USDC_SUSD_Gauge,
|
|
104
|
+
pool.address
|
|
105
|
+
);
|
|
106
|
+
await pool.unstakeFromGauge(USDC_SUSD_Gauge, gaugeBalance);
|
|
107
|
+
const lpTokenDelta = await balanceDelta(
|
|
108
|
+
pool.address,
|
|
109
|
+
USDC_SUSD_Lp,
|
|
110
|
+
pool.signer
|
|
111
|
+
);
|
|
112
|
+
expect(lpTokenDelta.gt(0)).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("approves unlimited USDC-sUSD LP for Velodrome", async () => {
|
|
116
|
+
await pool.approve(Dapp.VELODROME, USDC_SUSD_Lp, MAX_AMOUNT);
|
|
117
|
+
const lpAllowanceDelta = await allowanceDelta(
|
|
118
|
+
pool.address,
|
|
119
|
+
USDC_SUSD_Lp,
|
|
120
|
+
routerAddress[network].velodrome!,
|
|
121
|
+
pool.signer
|
|
122
|
+
);
|
|
123
|
+
expect(lpAllowanceDelta.gt(0)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should remove all liquidity from an existing pool ", async () => {
|
|
127
|
+
const balance = await dhedge.utils.getBalance(USDC_SUSD_Lp, pool.address);
|
|
128
|
+
await pool.removeLiquidityVelodrome(USDC, SUSD, balance, true);
|
|
129
|
+
const usdcBalanceDelta = await balanceDelta(
|
|
130
|
+
pool.address,
|
|
131
|
+
USDC,
|
|
132
|
+
pool.signer
|
|
133
|
+
);
|
|
134
|
+
const susdBalanceDelta = await balanceDelta(
|
|
135
|
+
pool.address,
|
|
136
|
+
SUSD,
|
|
137
|
+
pool.signer
|
|
138
|
+
);
|
|
139
|
+
expect(usdcBalanceDelta.gt(0)).toBe(true);
|
|
140
|
+
expect(susdBalanceDelta.gt(0)).toBe(true);
|
|
141
|
+
});
|
|
113
142
|
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
testingHelper({
|
|
146
|
+
network: Network.OPTIMISM,
|
|
147
|
+
testingRun: testVelodrome
|
|
114
148
|
});
|
|
@@ -1,22 +1,24 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
1
2
|
import BigNumber from "bignumber.js";
|
|
2
3
|
import { Dhedge, Pool, ethers } from "..";
|
|
3
4
|
|
|
4
5
|
import { nonfungiblePositionManagerAddress } from "../config";
|
|
5
|
-
import {
|
|
6
|
+
import { Dapp, Network } from "../types";
|
|
6
7
|
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
7
8
|
import {
|
|
8
9
|
TestingRunParams,
|
|
9
10
|
beforeAfterReset,
|
|
11
|
+
fixOracleAggregatorStaleness,
|
|
12
|
+
runWithImpersonateAccount,
|
|
10
13
|
setChainlinkTimeout,
|
|
11
14
|
setUSDCAmount,
|
|
12
15
|
setWETHAmount,
|
|
13
16
|
testingHelper
|
|
14
17
|
} from "./utils/testingHelper";
|
|
15
|
-
import {
|
|
18
|
+
import { balanceDelta } from "./utils/token";
|
|
16
19
|
import INonfungiblePositionManager from "../abi/INonfungiblePositionManager.json";
|
|
17
20
|
|
|
18
21
|
const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
20
22
|
const VELODROME_POSITION_MANGER = nonfungiblePositionManagerAddress[network][
|
|
21
23
|
Dapp.VELODROMECL
|
|
22
24
|
]!;
|
|
@@ -33,18 +35,33 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
33
35
|
let tokenId: string;
|
|
34
36
|
jest.setTimeout(100000);
|
|
35
37
|
|
|
36
|
-
describe(`[${network}]
|
|
38
|
+
describe(`[${network}] velodrome CL tests`, () => {
|
|
37
39
|
beforeAll(async () => {
|
|
38
|
-
// top up ETH (gas)
|
|
39
40
|
await provider.send("hardhat_setBalance", [
|
|
40
41
|
wallet.address,
|
|
41
|
-
"
|
|
42
|
+
"0x10000000000000000"
|
|
42
43
|
]);
|
|
43
44
|
dhedge = new Dhedge(wallet, network);
|
|
44
45
|
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
45
46
|
|
|
46
|
-
// setChainlinkTimeout
|
|
47
47
|
await setChainlinkTimeout({ pool, provider }, 86400 * 365);
|
|
48
|
+
await fixOracleAggregatorStaleness({ pool, provider });
|
|
49
|
+
|
|
50
|
+
await runWithImpersonateAccount(
|
|
51
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
52
|
+
async ({ signer }) => {
|
|
53
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
54
|
+
await pool.managerLogic.connect(signer).changeAssets(
|
|
55
|
+
[
|
|
56
|
+
[USDC, true],
|
|
57
|
+
[WETH, true],
|
|
58
|
+
[VELODROME_POSITION_MANGER, false],
|
|
59
|
+
[VELO, false]
|
|
60
|
+
],
|
|
61
|
+
[]
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
48
65
|
|
|
49
66
|
await setUSDCAmount({
|
|
50
67
|
amount: new BigNumber(10000).times(1e6).toFixed(0),
|
|
@@ -59,20 +76,6 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
59
76
|
provider
|
|
60
77
|
});
|
|
61
78
|
|
|
62
|
-
const newAssets: AssetEnabled[] = [
|
|
63
|
-
{ asset: USDC, isDeposit: true },
|
|
64
|
-
{ asset: WETH, isDeposit: true },
|
|
65
|
-
{
|
|
66
|
-
asset: VELODROME_POSITION_MANGER,
|
|
67
|
-
isDeposit: false
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
asset: VELO,
|
|
71
|
-
isDeposit: false
|
|
72
|
-
}
|
|
73
|
-
];
|
|
74
|
-
await pool.changeAssets(newAssets);
|
|
75
|
-
|
|
76
79
|
velodromePositionManager = new ethers.Contract(
|
|
77
80
|
VELODROME_POSITION_MANGER,
|
|
78
81
|
INonfungiblePositionManager.abi,
|
|
@@ -86,13 +89,16 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
86
89
|
it("approves unlimited USDC and WETH on for Velodrome CL", async () => {
|
|
87
90
|
await pool.approveSpender(VELODROME_POSITION_MANGER, USDC, MAX_AMOUNT);
|
|
88
91
|
await pool.approveSpender(VELODROME_POSITION_MANGER, WETH, MAX_AMOUNT);
|
|
89
|
-
const
|
|
90
|
-
pool.address,
|
|
92
|
+
const iERC20 = new ethers.Contract(
|
|
91
93
|
USDC,
|
|
92
|
-
|
|
94
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
93
95
|
pool.signer
|
|
94
96
|
);
|
|
95
|
-
await
|
|
97
|
+
const usdcAllowance = await iERC20.allowance(
|
|
98
|
+
pool.address,
|
|
99
|
+
VELODROME_POSITION_MANGER
|
|
100
|
+
);
|
|
101
|
+
expect(usdcAllowance.gt(0)).toBe(true);
|
|
96
102
|
});
|
|
97
103
|
|
|
98
104
|
it("adds USDC and WETH to a Velodrome CL (mint position)", async () => {
|
|
@@ -114,7 +120,7 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
114
120
|
tokenId = (
|
|
115
121
|
await velodromePositionManager.tokenOfOwnerByIndex(pool.address, 0)
|
|
116
122
|
).toString();
|
|
117
|
-
expect(tokenId).
|
|
123
|
+
expect(tokenId).toBeDefined();
|
|
118
124
|
});
|
|
119
125
|
|
|
120
126
|
it("increases liquidity in a CL position", async () => {
|
|
@@ -130,7 +136,7 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
130
136
|
wethBalance.div(2)
|
|
131
137
|
);
|
|
132
138
|
const positionAfter = await velodromePositionManager.positions(tokenId);
|
|
133
|
-
expect(positionAfter.liquidity.gt(positionBefore.liquidity));
|
|
139
|
+
expect(positionAfter.liquidity.gt(positionBefore.liquidity)).toBe(true);
|
|
134
140
|
});
|
|
135
141
|
|
|
136
142
|
it("decreases liquidity from a CL position", async () => {
|
|
@@ -139,14 +145,17 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
139
145
|
);
|
|
140
146
|
await pool.decreaseLiquidity(Dapp.VELODROMECL, tokenId, 50);
|
|
141
147
|
const positionAfter = await velodromePositionManager.positions(tokenId);
|
|
142
|
-
expect(positionAfter.liquidity.lt(positionBefore.liquidity));
|
|
148
|
+
expect(positionAfter.liquidity.lt(positionBefore.liquidity)).toBe(true);
|
|
143
149
|
});
|
|
144
150
|
|
|
145
151
|
it("collects fess of a CL position", async () => {
|
|
146
|
-
await provider.send("evm_increaseTime", [24 * 3600 * 3]); //
|
|
152
|
+
await provider.send("evm_increaseTime", [24 * 3600 * 3]); // 3 days
|
|
147
153
|
await provider.send("evm_mine", []);
|
|
148
154
|
await pool.claimFees(Dapp.VELODROMECL, tokenId);
|
|
149
|
-
|
|
155
|
+
// Fork has no trading activity during evm_increaseTime so no fees accrue — assert gte(0) to verify the call succeeds
|
|
156
|
+
expect(
|
|
157
|
+
(await balanceDelta(pool.address, USDC, pool.signer)).gte(0)
|
|
158
|
+
).toBe(true);
|
|
150
159
|
});
|
|
151
160
|
});
|
|
152
161
|
describe("Liquidity staking", () => {
|
|
@@ -186,7 +195,10 @@ const testVelodromeCL = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
186
195
|
await provider.send("evm_increaseTime", [24 * 3600]); // 1 day
|
|
187
196
|
await provider.send("evm_mine", []);
|
|
188
197
|
await pool.claimFees(Dapp.VELODROMECL, tokenId);
|
|
189
|
-
|
|
198
|
+
// Fork has no gauge emissions during evm_increaseTime so no VELO rewards — assert gte(0) to verify the call succeeds
|
|
199
|
+
expect(
|
|
200
|
+
(await balanceDelta(pool.address, VELO, pool.signer)).gte(0)
|
|
201
|
+
).toBe(true);
|
|
190
202
|
});
|
|
191
203
|
|
|
192
204
|
it("unstakes a CL position from a gauge", async () => {
|