@dhedge/v2-sdk 2.1.7 → 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 +14 -2
- package/dist/entities/pool.d.ts +25 -86
- package/dist/entities/utils.d.ts +15 -0
- package/dist/services/cowSwap/index.d.ts +10 -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 +21 -5
- package/dist/utils/contract.d.ts +20 -0
- package/dist/v2-sdk.cjs.development.js +5193 -6711
- 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 +5198 -6711
- 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 +19 -9
- package/src/entities/pool.ts +103 -254
- package/src/entities/utils.ts +15 -0
- package/src/services/cowSwap/index.ts +281 -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 +57 -12
- package/src/test/cowswap.test.ts +79 -0
- 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 +22 -6
- 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
package/src/test/constants.ts
CHANGED
|
@@ -35,8 +35,6 @@ export const SUSD = "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9";
|
|
|
35
35
|
export const SETH = "0xE405de8F52ba7559f9df3C368500B6E6ae6Cee49";
|
|
36
36
|
export const ARRAKIS_USDC_WETH_GAUGE =
|
|
37
37
|
"0xb8888ea29e2f70ad62a3b69b1a1342720612a00d";
|
|
38
|
-
export const KWENTA_ETH_PERP = "0xf86048dff23cf130107dfb4e6386f574231a5c65";
|
|
39
|
-
export const KWENTA_ETH_PERP_V2 = "0x2b3bb4c683bfc5239b029131eef3b1d214478d93";
|
|
40
38
|
|
|
41
39
|
export const TEST_POOL = {
|
|
42
40
|
[Network.POLYGON]: "0x699fd4d6eadb216704c7e355cfa0a12f51813163",
|
|
@@ -50,7 +48,7 @@ export const TEST_POOL = {
|
|
|
50
48
|
|
|
51
49
|
export const CONTRACT_ADDRESS = {
|
|
52
50
|
[Network.POLYGON]: {
|
|
53
|
-
USDC: "
|
|
51
|
+
USDC: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
|
|
54
52
|
USDT: "",
|
|
55
53
|
USDE: "",
|
|
56
54
|
SUSD: "",
|
|
@@ -68,7 +66,10 @@ export const CONTRACT_ADDRESS = {
|
|
|
68
66
|
COMPOUNDV3_WETH: "",
|
|
69
67
|
FLUID_WETH: "",
|
|
70
68
|
TOROS: "",
|
|
71
|
-
UNIT: ""
|
|
69
|
+
UNIT: "",
|
|
70
|
+
WSTETH: "",
|
|
71
|
+
BALANCER_WSTETH_WETH_POOL: "",
|
|
72
|
+
BALANCER_WSTETH_WETH_GAUGE: ""
|
|
72
73
|
},
|
|
73
74
|
|
|
74
75
|
[Network.OPTIMISM]: {
|
|
@@ -79,7 +80,6 @@ export const CONTRACT_ADDRESS = {
|
|
|
79
80
|
SUSD: "0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9",
|
|
80
81
|
WETH: "0x4200000000000000000000000000000000000006",
|
|
81
82
|
WBTC: "0x68f180fcCe6836688e9084f035309E29Bf0A2095",
|
|
82
|
-
KWENTA_ETH_PERP_V2: "0x2b3bb4c683bfc5239b029131eef3b1d214478d93",
|
|
83
83
|
uniswapV3: {
|
|
84
84
|
nonfungiblePositionManager: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
|
|
85
85
|
},
|
|
@@ -93,7 +93,10 @@ export const CONTRACT_ADDRESS = {
|
|
|
93
93
|
VELO: "0x9560e827aF36c94D2Ac33a39bCE1Fe78631088Db",
|
|
94
94
|
COMPOUNDV3_WETH: "",
|
|
95
95
|
FLUID_WETH: "",
|
|
96
|
-
TOROS: "0xcacb5a722a36cff6baeb359e21c098a4acbffdfa" //ETHBEAR1X
|
|
96
|
+
TOROS: "0xcacb5a722a36cff6baeb359e21c098a4acbffdfa", //ETHBEAR1X
|
|
97
|
+
WSTETH: "",
|
|
98
|
+
BALANCER_WSTETH_WETH_POOL: "",
|
|
99
|
+
BALANCER_WSTETH_WETH_GAUGE: ""
|
|
97
100
|
},
|
|
98
101
|
[Network.ARBITRUM]: {
|
|
99
102
|
USDC: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
@@ -121,7 +124,7 @@ export const CONTRACT_ADDRESS = {
|
|
|
121
124
|
VELO: "",
|
|
122
125
|
COMPOUNDV3_WETH: "0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486",
|
|
123
126
|
FLUID_WETH: "0x45df0656f8adf017590009d2f1898eeca4f0a205",
|
|
124
|
-
TOROS: ""
|
|
127
|
+
TOROS: "0xA6711f8a184E352c5A0714a48912cD33ca4a16A0" //DYTMT
|
|
125
128
|
},
|
|
126
129
|
[Network.BASE]: {
|
|
127
130
|
USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
@@ -143,7 +146,10 @@ export const CONTRACT_ADDRESS = {
|
|
|
143
146
|
VELO: "0x940181a94A35A4569E4529A3CDfB74e38FD98631",
|
|
144
147
|
COMPOUNDV3_WETH: "",
|
|
145
148
|
FLUID_WETH: "",
|
|
146
|
-
TOROS: ""
|
|
149
|
+
TOROS: "",
|
|
150
|
+
WSTETH: "",
|
|
151
|
+
BALANCER_WSTETH_WETH_POOL: "",
|
|
152
|
+
BALANCER_WSTETH_WETH_GAUGE: ""
|
|
147
153
|
},
|
|
148
154
|
[Network.ETHEREUM]: {
|
|
149
155
|
USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
@@ -165,17 +171,56 @@ export const CONTRACT_ADDRESS = {
|
|
|
165
171
|
COMPOUNDV3_WETH: "",
|
|
166
172
|
FLUID_WETH: "",
|
|
167
173
|
TOROS: "",
|
|
168
|
-
UNIT: ""
|
|
174
|
+
UNIT: "",
|
|
175
|
+
WSTETH: "",
|
|
176
|
+
BALANCER_WSTETH_WETH_POOL: "",
|
|
177
|
+
BALANCER_WSTETH_WETH_GAUGE: ""
|
|
169
178
|
},
|
|
170
179
|
[Network.PLASMA]: {
|
|
171
180
|
USDC: "",
|
|
172
181
|
WETH: "0x9895d81bb462a195b4922ed7de0e3acd007c32cb",
|
|
182
|
+
WBTC: "",
|
|
173
183
|
USDT: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
|
|
174
|
-
USDE: "0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34"
|
|
184
|
+
USDE: "0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34",
|
|
185
|
+
VELO: "",
|
|
186
|
+
uniswapV3: {
|
|
187
|
+
nonfungiblePositionManager: ""
|
|
188
|
+
},
|
|
189
|
+
COMPOUNDV3_WETH: "",
|
|
190
|
+
FLUID_WETH: "",
|
|
191
|
+
UNIT: "",
|
|
192
|
+
TOROS: "",
|
|
193
|
+
SUSD: "",
|
|
194
|
+
VELODROME_CL_USDC_WETH_GAUGE: "",
|
|
195
|
+
ARRAKIS_USDC_WETH_GAUGE: "",
|
|
196
|
+
ARRAKIS_USDC_WETH_LP: "",
|
|
197
|
+
WMATIC: "",
|
|
198
|
+
WSTETH: "",
|
|
199
|
+
BALANCER_WSTETH_WETH_POOL: "",
|
|
200
|
+
BALANCER_WSTETH_WETH_GAUGE: ""
|
|
175
201
|
},
|
|
176
202
|
[Network.HYPERLIQUID]: {
|
|
177
203
|
USDC: "0xb88339cb7199b77e23db6e890353e22632ba630f",
|
|
178
|
-
|
|
204
|
+
USDT: "",
|
|
205
|
+
USDE: "",
|
|
206
|
+
WETH: "",
|
|
207
|
+
WBTC: "",
|
|
208
|
+
VELO: "",
|
|
209
|
+
uniswapV3: {
|
|
210
|
+
nonfungiblePositionManager: ""
|
|
211
|
+
},
|
|
212
|
+
COMPOUNDV3_WETH: "",
|
|
213
|
+
FLUID_WETH: "",
|
|
214
|
+
UNIT: "",
|
|
215
|
+
TOROS: "",
|
|
216
|
+
SUSD: "",
|
|
217
|
+
VELODROME_CL_USDC_WETH_GAUGE: "",
|
|
218
|
+
ARRAKIS_USDC_WETH_GAUGE: "",
|
|
219
|
+
ARRAKIS_USDC_WETH_LP: "",
|
|
220
|
+
WMATIC: "",
|
|
221
|
+
WSTETH: "",
|
|
222
|
+
BALANCER_WSTETH_WETH_POOL: "",
|
|
223
|
+
BALANCER_WSTETH_WETH_GAUGE: ""
|
|
179
224
|
}
|
|
180
225
|
};
|
|
181
226
|
|
|
@@ -195,7 +240,7 @@ export const WETH_BALANCEOF_SLOT = {
|
|
|
195
240
|
[Network.OPTIMISM]: 3,
|
|
196
241
|
[Network.ARBITRUM]: 51,
|
|
197
242
|
[Network.POLYGON]: 0,
|
|
198
|
-
[Network.BASE]:
|
|
243
|
+
[Network.BASE]: 3,
|
|
199
244
|
[Network.ETHEREUM]: 3,
|
|
200
245
|
[Network.PLASMA]: 1,
|
|
201
246
|
[Network.HYPERLIQUID]: 1
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CowSwap tests require a live chain connection (onFork: false).
|
|
5
|
+
* CowSwap orders are settled off-chain by solvers, so they cannot
|
|
6
|
+
* be tested on a Hardhat fork. Run with a funded wallet and
|
|
7
|
+
* PRIVATE_KEY + POLYGON_URL set in .env.
|
|
8
|
+
*
|
|
9
|
+
* Flow: approve CoW vault relayer → trade
|
|
10
|
+
* Note: estimateGas and onlyGetTxData are not supported for CowSwap
|
|
11
|
+
* because it requires two sequential transactions (submit + preSign).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { Dhedge, Pool } from "..";
|
|
15
|
+
|
|
16
|
+
import { Dapp, Network } from "../types";
|
|
17
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
18
|
+
import { getTxOptions } from "./txOptions";
|
|
19
|
+
import { TestingRunParams, testingHelper } from "./utils/testingHelper";
|
|
20
|
+
import { allowanceDelta, balanceDelta } from "./utils/token";
|
|
21
|
+
|
|
22
|
+
// CoW Protocol Vault Relayer — must be approved before CowSwap trades
|
|
23
|
+
const COWSWAP_VAULT_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110";
|
|
24
|
+
|
|
25
|
+
const testCowswap = ({ wallet, network }: TestingRunParams) => {
|
|
26
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
27
|
+
const WETH = CONTRACT_ADDRESS[network].WETH;
|
|
28
|
+
|
|
29
|
+
let dhedge: Dhedge;
|
|
30
|
+
let pool: Pool;
|
|
31
|
+
jest.setTimeout(100000);
|
|
32
|
+
|
|
33
|
+
describe(`[${network}] cowswap tests`, () => {
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
dhedge = new Dhedge(wallet, network);
|
|
36
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("approves unlimited USDC on Cowswap vault relayer", async () => {
|
|
40
|
+
await pool.approveSpender(
|
|
41
|
+
COWSWAP_VAULT_RELAYER,
|
|
42
|
+
USDC,
|
|
43
|
+
MAX_AMOUNT,
|
|
44
|
+
await getTxOptions(network)
|
|
45
|
+
);
|
|
46
|
+
const usdcAllowanceDelta = await allowanceDelta(
|
|
47
|
+
pool.address,
|
|
48
|
+
USDC,
|
|
49
|
+
COWSWAP_VAULT_RELAYER,
|
|
50
|
+
pool.signer
|
|
51
|
+
);
|
|
52
|
+
expect(usdcAllowanceDelta.gt(0)).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("trades 2 USDC into WETH on Cowswap", async () => {
|
|
56
|
+
await pool.trade(
|
|
57
|
+
Dapp.COWSWAP,
|
|
58
|
+
USDC,
|
|
59
|
+
WETH,
|
|
60
|
+
"2000000",
|
|
61
|
+
0.5,
|
|
62
|
+
await getTxOptions(network)
|
|
63
|
+
);
|
|
64
|
+
const wethBalanceDelta = await balanceDelta(
|
|
65
|
+
pool.address,
|
|
66
|
+
WETH,
|
|
67
|
+
pool.signer
|
|
68
|
+
);
|
|
69
|
+
expect(wethBalanceDelta.gt(0)).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// CowSwap requires live chain — cannot run on fork
|
|
75
|
+
testingHelper({
|
|
76
|
+
network: Network.POLYGON,
|
|
77
|
+
testingRun: testCowswap,
|
|
78
|
+
onFork: false
|
|
79
|
+
});
|
package/src/test/dhedge.test.ts
CHANGED
|
@@ -1,32 +1,65 @@
|
|
|
1
1
|
import { Dhedge } from "..";
|
|
2
2
|
import { Network } from "../types";
|
|
3
|
+
import { CONTRACT_ADDRESS, TEST_POOL } from "./constants";
|
|
4
|
+
import {
|
|
5
|
+
testingHelper,
|
|
6
|
+
TestingRunParams,
|
|
7
|
+
beforeAfterReset
|
|
8
|
+
} from "./utils/testingHelper";
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const testDhedge = ({ wallet, network }: TestingRunParams) => {
|
|
10
|
+
const testDhedge = ({ wallet, network, provider }: TestingRunParams) => {
|
|
7
11
|
let dhedge: Dhedge;
|
|
8
12
|
|
|
9
13
|
jest.setTimeout(200000);
|
|
10
14
|
|
|
11
15
|
describe(`dHEDGE on ${network}`, () => {
|
|
12
16
|
beforeAll(async () => {
|
|
17
|
+
// Fund the test wallet with gas
|
|
18
|
+
await provider.send("hardhat_setBalance", [
|
|
19
|
+
wallet.address,
|
|
20
|
+
"0x10000000000000000"
|
|
21
|
+
]);
|
|
13
22
|
dhedge = new Dhedge(wallet, network);
|
|
14
23
|
});
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
beforeAfterReset({ beforeAll, afterAll, provider });
|
|
26
|
+
|
|
27
|
+
it("creates a pool with USDC and WETH", async () => {
|
|
28
|
+
const pool = await dhedge.createPool(
|
|
29
|
+
"Test Manager",
|
|
30
|
+
"Test Fund",
|
|
31
|
+
"TEST",
|
|
32
|
+
[
|
|
33
|
+
[CONTRACT_ADDRESS[network].USDC, true],
|
|
34
|
+
[CONTRACT_ADDRESS[network].WETH, false]
|
|
35
|
+
]
|
|
36
|
+
);
|
|
37
|
+
expect(pool.address).toBeDefined();
|
|
23
38
|
expect(pool.poolLogic.address).toBe(pool.address);
|
|
24
39
|
});
|
|
40
|
+
|
|
41
|
+
it("loads an existing pool", async () => {
|
|
42
|
+
const pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
43
|
+
expect(pool.address).toBe(TEST_POOL[network]);
|
|
44
|
+
expect(pool.poolLogic.address).toBe(TEST_POOL[network]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("validates a real pool address", async () => {
|
|
48
|
+
const isValid = await dhedge.validatePool(TEST_POOL[network]);
|
|
49
|
+
expect(isValid).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("rejects an invalid pool address", async () => {
|
|
53
|
+
const isValid = await dhedge.validatePool(
|
|
54
|
+
"0x0000000000000000000000000000000000000001"
|
|
55
|
+
);
|
|
56
|
+
expect(isValid).toBe(false);
|
|
57
|
+
});
|
|
25
58
|
});
|
|
26
59
|
};
|
|
27
60
|
|
|
28
61
|
testingHelper({
|
|
29
|
-
network: Network.
|
|
30
|
-
onFork:
|
|
62
|
+
network: Network.ARBITRUM,
|
|
63
|
+
onFork: true,
|
|
31
64
|
testingRun: testDhedge
|
|
32
65
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
1
|
import BigNumber from "bignumber.js";
|
|
3
2
|
import { Dhedge, Pool } from "../entities";
|
|
4
|
-
import {
|
|
3
|
+
import { Network } from "../types";
|
|
5
4
|
import {
|
|
6
5
|
TestingRunParams,
|
|
7
6
|
runWithImpersonateAccount,
|
|
@@ -12,7 +11,6 @@ import { Contract, ethers } from "ethers";
|
|
|
12
11
|
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
13
12
|
import { flatMoneyContractAddresses } from "../config";
|
|
14
13
|
import DelayedOrderAbi from "../abi/flatmoney/DelayedOrder.json";
|
|
15
|
-
import { allowanceDelta } from "./utils/token";
|
|
16
14
|
import { getKeeperFee } from "../services/flatmoney/keeperFee";
|
|
17
15
|
|
|
18
16
|
const COLLATERAL_SLOT = 0; // same for RETH(base) and WBTC(optimism)
|
|
@@ -32,19 +30,15 @@ const testFlatMoney = ({
|
|
|
32
30
|
let delayOrderContract: Contract;
|
|
33
31
|
let COLLATERAL: string;
|
|
34
32
|
jest.setTimeout(200000);
|
|
33
|
+
// FlatMoney's OracleModule reverts with ETHPriceStale() when the forked block's
|
|
34
|
+
// Chainlink ETH/USD price is older than maxAge. Re-run the fork before this suite
|
|
35
|
+
// so the oracle timestamp is fresh (there is no helper to override maxAge here).
|
|
35
36
|
describe(`flatmoney on ${network}`, () => {
|
|
36
37
|
beforeAll(async () => {
|
|
37
38
|
await provider.send("evm_mine", []);
|
|
38
39
|
dhedge = new Dhedge(wallet, network);
|
|
39
40
|
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
40
41
|
|
|
41
|
-
await runWithImpersonateAccount(
|
|
42
|
-
{ provider, account: await pool.managerLogic.manager() },
|
|
43
|
-
async ({ signer }) => {
|
|
44
|
-
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
|
|
48
42
|
const flatMoneyContracts = flatMoneyContractAddresses[pool.network];
|
|
49
43
|
if (!flatMoneyContracts) {
|
|
50
44
|
throw new Error("testFlatMoney: network not supported");
|
|
@@ -56,7 +50,20 @@ const testFlatMoney = ({
|
|
|
56
50
|
pool.signer
|
|
57
51
|
);
|
|
58
52
|
|
|
59
|
-
|
|
53
|
+
await runWithImpersonateAccount(
|
|
54
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
55
|
+
async ({ signer }) => {
|
|
56
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
57
|
+
await pool.managerLogic.connect(signer).changeAssets(
|
|
58
|
+
[
|
|
59
|
+
[COLLATERAL, false],
|
|
60
|
+
[CONTRACT_ADDRESS[network].UNIT, false]
|
|
61
|
+
],
|
|
62
|
+
[]
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
60
67
|
await provider.send("hardhat_setBalance", [
|
|
61
68
|
wallet.address,
|
|
62
69
|
"0x10000000000000000"
|
|
@@ -77,45 +84,24 @@ const testFlatMoney = ({
|
|
|
77
84
|
slot: UNIT_SLOT,
|
|
78
85
|
userAddress: pool.address
|
|
79
86
|
});
|
|
80
|
-
|
|
81
|
-
const currentAssets: any[] = await pool.managerLogic.getSupportedAssets();
|
|
82
|
-
const exisitingAssets = currentAssets.map(item => {
|
|
83
|
-
return {
|
|
84
|
-
asset: item[0],
|
|
85
|
-
isDeposit: item[1]
|
|
86
|
-
};
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const newAssets: AssetEnabled[] = [
|
|
90
|
-
...exisitingAssets,
|
|
91
|
-
{ asset: CONTRACT_ADDRESS[network].USDC, isDeposit: true },
|
|
92
|
-
{ asset: CONTRACT_ADDRESS[network].WETH, isDeposit: true },
|
|
93
|
-
{
|
|
94
|
-
asset: CONTRACT_ADDRESS[network].UNIT,
|
|
95
|
-
isDeposit: false
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
asset: COLLATERAL,
|
|
99
|
-
isDeposit: false
|
|
100
|
-
}
|
|
101
|
-
];
|
|
102
|
-
await pool.changeAssets(newAssets);
|
|
103
87
|
});
|
|
104
88
|
|
|
105
89
|
it("mint UNIT", async () => {
|
|
106
|
-
//approve
|
|
107
90
|
await pool.approveSpender(
|
|
108
91
|
delayOrderContract.address,
|
|
109
92
|
COLLATERAL,
|
|
110
93
|
MAX_AMOUNT
|
|
111
94
|
);
|
|
112
|
-
const
|
|
113
|
-
pool.address,
|
|
95
|
+
const iERC20 = new ethers.Contract(
|
|
114
96
|
COLLATERAL,
|
|
115
|
-
|
|
97
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
116
98
|
pool.signer
|
|
117
99
|
);
|
|
118
|
-
await
|
|
100
|
+
const collateralAllowance = await iERC20.allowance(
|
|
101
|
+
pool.address,
|
|
102
|
+
delayOrderContract.address
|
|
103
|
+
);
|
|
104
|
+
expect(collateralAllowance.gt(0)).toBe(true);
|
|
119
105
|
|
|
120
106
|
const depositAmountStr = new BigNumber(1).times(1e18).toString();
|
|
121
107
|
const estimateData = await pool.mintUnitViaFlatMoney(
|
package/src/test/fluid.test.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
3
|
import BigNumber from "bignumber.js";
|
|
4
|
+
import { ethers } from "ethers";
|
|
4
5
|
import { Dhedge, Pool } from "..";
|
|
5
|
-
import {
|
|
6
|
+
import { Network } from "../types";
|
|
6
7
|
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
7
8
|
import {
|
|
8
9
|
TestingRunParams,
|
|
9
10
|
beforeAfterReset,
|
|
10
11
|
setWETHAmount,
|
|
12
|
+
runWithImpersonateAccount,
|
|
11
13
|
testingHelper
|
|
12
14
|
} from "./utils/testingHelper";
|
|
13
|
-
import {
|
|
14
|
-
import { getWalletData } from "./wallet";
|
|
15
|
+
import { balanceDelta } from "./utils/token";
|
|
15
16
|
|
|
16
|
-
const testFluid = ({ network, provider }: TestingRunParams) => {
|
|
17
|
+
const testFluid = ({ wallet, network, provider }: TestingRunParams) => {
|
|
17
18
|
const WETH = CONTRACT_ADDRESS[network].WETH;
|
|
18
19
|
const FLUID_WETH = CONTRACT_ADDRESS[network].FLUID_WETH;
|
|
19
20
|
|
|
@@ -21,16 +22,15 @@ const testFluid = ({ network, provider }: TestingRunParams) => {
|
|
|
21
22
|
let pool: Pool;
|
|
22
23
|
jest.setTimeout(100000);
|
|
23
24
|
|
|
24
|
-
describe(`[${network}]
|
|
25
|
+
describe(`[${network}] fluid tests`, () => {
|
|
25
26
|
beforeAll(async () => {
|
|
26
|
-
const { wallet } = getWalletData(network);
|
|
27
|
-
// top up ETH (gas)
|
|
28
27
|
await provider.send("hardhat_setBalance", [
|
|
29
28
|
wallet.address,
|
|
30
|
-
"
|
|
29
|
+
"0x10000000000000000"
|
|
31
30
|
]);
|
|
32
31
|
dhedge = new Dhedge(wallet, network);
|
|
33
32
|
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
33
|
+
|
|
34
34
|
await setWETHAmount({
|
|
35
35
|
amount: new BigNumber(1e18).toFixed(0),
|
|
36
36
|
userAddress: pool.address,
|
|
@@ -38,26 +38,31 @@ const testFluid = ({ network, provider }: TestingRunParams) => {
|
|
|
38
38
|
provider
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
// Impersonate pool manager to set trader and configure assets
|
|
42
|
+
await runWithImpersonateAccount(
|
|
43
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
44
|
+
async ({ signer }) => {
|
|
45
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
46
|
+
const newAssets = [
|
|
47
|
+
[WETH, true],
|
|
48
|
+
[FLUID_WETH, false]
|
|
49
|
+
];
|
|
50
|
+
await pool.managerLogic.connect(signer).changeAssets(newAssets, []);
|
|
46
51
|
}
|
|
47
|
-
|
|
48
|
-
await pool.managerLogic.changeAssets(newAssets, []);
|
|
52
|
+
);
|
|
49
53
|
});
|
|
50
54
|
beforeAfterReset({ beforeAll, afterAll, provider });
|
|
51
55
|
|
|
52
56
|
it("approves unlimited WETH for fWETH market", async () => {
|
|
53
|
-
await pool.approveSpender(FLUID_WETH, WETH, MAX_AMOUNT);
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
const tx = await pool.approveSpender(FLUID_WETH, WETH, MAX_AMOUNT);
|
|
58
|
+
await tx.wait(1);
|
|
59
|
+
const iERC20 = new ethers.Contract(
|
|
56
60
|
WETH,
|
|
57
|
-
|
|
61
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
58
62
|
pool.signer
|
|
59
63
|
);
|
|
60
|
-
await
|
|
64
|
+
const wethAllowance = await iERC20.allowance(pool.address, FLUID_WETH);
|
|
65
|
+
expect(wethAllowance.gt(0)).toBe(true);
|
|
61
66
|
});
|
|
62
67
|
|
|
63
68
|
it("lends WETH to Fluid WETH market", async () => {
|
|
@@ -69,17 +74,21 @@ const testFluid = ({ network, provider }: TestingRunParams) => {
|
|
|
69
74
|
FLUID_WETH,
|
|
70
75
|
pool.signer
|
|
71
76
|
);
|
|
72
|
-
expect(fWETHTokenDelta.gt(0));
|
|
77
|
+
expect(fWETHTokenDelta.gt(0)).toBe(true);
|
|
73
78
|
});
|
|
74
79
|
|
|
75
|
-
it("
|
|
80
|
+
it("withdraws WETH from Fluid WETH market", async () => {
|
|
76
81
|
const fWETHBalance = await pool.utils.getBalance(
|
|
77
82
|
FLUID_WETH,
|
|
78
83
|
pool.address
|
|
79
84
|
);
|
|
80
85
|
await pool.withdrawCompoundV3(FLUID_WETH, WETH, fWETHBalance);
|
|
81
|
-
const
|
|
82
|
-
|
|
86
|
+
const wethBalanceDelta = await balanceDelta(
|
|
87
|
+
pool.address,
|
|
88
|
+
WETH,
|
|
89
|
+
pool.signer
|
|
90
|
+
);
|
|
91
|
+
expect(wethBalanceDelta.gt(0)).toBe(true);
|
|
83
92
|
});
|
|
84
93
|
});
|
|
85
94
|
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hyperliquid on-chain tests for deposit/withdraw/perp-spot/open/close flows.
|
|
5
|
+
* These require a live chain connection (onFork: false) because Hyperliquid
|
|
6
|
+
* precompile and CoreWriter state cannot be faithfully forked.
|
|
7
|
+
*
|
|
8
|
+
* Prerequisites:
|
|
9
|
+
* - PRIVATE_KEY in .env (must be the pool manager or trader)
|
|
10
|
+
* - HYPERLIQUID_URL in .env
|
|
11
|
+
* - The test pool must hold USDC and an existing ETH perp position
|
|
12
|
+
* - Spot wallet must hold the amount expected by the withdraw test
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { ethers } from "ethers";
|
|
16
|
+
import { Dhedge, Pool } from "..";
|
|
17
|
+
|
|
18
|
+
import { Dapp, Network } from "../types";
|
|
19
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
20
|
+
import { routerAddress } from "../config";
|
|
21
|
+
import { getTxOptions } from "./txOptions";
|
|
22
|
+
|
|
23
|
+
import { TestingRunParams, testingHelper } from "./utils/testingHelper";
|
|
24
|
+
|
|
25
|
+
const testHyperliquid = ({ wallet, network }: TestingRunParams) => {
|
|
26
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
27
|
+
|
|
28
|
+
let dhedge: Dhedge;
|
|
29
|
+
let pool: Pool;
|
|
30
|
+
jest.setTimeout(200000);
|
|
31
|
+
|
|
32
|
+
describe(`pool on ${network}`, () => {
|
|
33
|
+
beforeAll(async () => {
|
|
34
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) {
|
|
35
|
+
console.warn(
|
|
36
|
+
"Skipping hyperliquid on-chain tests: PRIVATE_KEY and HYPERLIQUID_URL env vars required"
|
|
37
|
+
);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
dhedge = new Dhedge(wallet, network);
|
|
41
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("approves unlimited USDC on Hyperliquid Core Wallet", async () => {
|
|
45
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) return;
|
|
46
|
+
const tx = await pool.approve(
|
|
47
|
+
Dapp.HYPERLIQUID,
|
|
48
|
+
USDC,
|
|
49
|
+
MAX_AMOUNT,
|
|
50
|
+
await getTxOptions(network)
|
|
51
|
+
);
|
|
52
|
+
await tx.wait(1);
|
|
53
|
+
const iERC20 = new ethers.Contract(
|
|
54
|
+
USDC,
|
|
55
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
56
|
+
pool.signer
|
|
57
|
+
);
|
|
58
|
+
const allowance = await iERC20.allowance(
|
|
59
|
+
pool.address,
|
|
60
|
+
routerAddress[network][Dapp.HYPERLIQUID]!
|
|
61
|
+
);
|
|
62
|
+
expect(allowance.gt(0)).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("deposits 30 USDC into Hyperliquid Core Wallet", async () => {
|
|
66
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) return;
|
|
67
|
+
const usdcBefore = await pool.utils.getBalance(USDC, pool.address);
|
|
68
|
+
const tx = await pool.depositHyperliquid(
|
|
69
|
+
"30000000", // 30 USDC (6 decimals)
|
|
70
|
+
4294967295,
|
|
71
|
+
await getTxOptions(network)
|
|
72
|
+
);
|
|
73
|
+
await tx.wait(1);
|
|
74
|
+
const usdcAfter = await pool.utils.getBalance(USDC, pool.address);
|
|
75
|
+
expect(usdcBefore.sub(usdcAfter).eq("30000000")).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("moves 5 USDC from Perp (dex 0) to Spot wallet", async () => {
|
|
79
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) return;
|
|
80
|
+
const tx = await pool.perpToSpotHyperliquid(
|
|
81
|
+
0,
|
|
82
|
+
"5000000", // 5 USDC (6 decimals)
|
|
83
|
+
await getTxOptions(network)
|
|
84
|
+
);
|
|
85
|
+
await tx.wait(1);
|
|
86
|
+
expect(tx).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("withdraws USDC from Hyperliquid Spot Wallet", async () => {
|
|
90
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) return;
|
|
91
|
+
const tx = await pool.withdrawHyperliquid(
|
|
92
|
+
"784577548", // 784.577548 USDC (6 decimals)
|
|
93
|
+
await getTxOptions(network)
|
|
94
|
+
);
|
|
95
|
+
await tx.wait(1);
|
|
96
|
+
expect(tx).toBeDefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("opens a XAUT0 spot buy order", async () => {
|
|
100
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) return;
|
|
101
|
+
const tx = await pool.openMarketOrderHyperliquid(
|
|
102
|
+
10182, // XAUT0/USDC spot asset id (10000 + spot index 182)
|
|
103
|
+
true, // long
|
|
104
|
+
25, // $25 notional
|
|
105
|
+
1, // 1% slippage
|
|
106
|
+
await getTxOptions(network)
|
|
107
|
+
);
|
|
108
|
+
await tx.wait(1);
|
|
109
|
+
expect(tx).toBeDefined();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("closes 50% of ETH perp position", async () => {
|
|
113
|
+
if (!process.env.PRIVATE_KEY || !process.env.HYPERLIQUID_URL) return;
|
|
114
|
+
const tx = await pool.closePositionHyperliquid(
|
|
115
|
+
1, // ETH Perp asset id
|
|
116
|
+
50, // 50% to close
|
|
117
|
+
1, // 1% slippage
|
|
118
|
+
await getTxOptions(network)
|
|
119
|
+
);
|
|
120
|
+
await tx.wait(1);
|
|
121
|
+
expect(tx).toBeDefined();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Requires live chain — cannot run on fork
|
|
127
|
+
testingHelper({
|
|
128
|
+
network: Network.HYPERLIQUID,
|
|
129
|
+
testingRun: testHyperliquid,
|
|
130
|
+
onFork: false
|
|
131
|
+
});
|