@dhedge/v2-sdk 2.1.8 → 2.2.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 (95) hide show
  1. package/README.md +404 -54
  2. package/dist/config.d.ts +13 -2
  3. package/dist/entities/pool.d.ts +25 -86
  4. package/dist/entities/utils.d.ts +15 -0
  5. package/dist/services/hyperliquid/index.d.ts +22 -0
  6. package/dist/services/kyberSwap/index.d.ts +1 -1
  7. package/dist/services/ondo/index.d.ts +5 -0
  8. package/dist/services/oneInch/index.d.ts +1 -1
  9. package/dist/services/toros/easySwapper.d.ts +14 -0
  10. package/dist/services/toros/swapData.d.ts +5 -5
  11. package/dist/services/uniswap/V3Liquidity.d.ts +2 -2
  12. package/dist/services/velodrome/liquidity.d.ts +3 -0
  13. package/dist/test/constants.d.ts +48 -3
  14. package/dist/test/utils/testingHelper.d.ts +4 -0
  15. package/dist/types.d.ts +21 -5
  16. package/dist/utils/contract.d.ts +20 -0
  17. package/dist/v2-sdk.cjs.development.js +5133 -6641
  18. package/dist/v2-sdk.cjs.development.js.map +1 -1
  19. package/dist/v2-sdk.cjs.production.min.js +1 -1
  20. package/dist/v2-sdk.cjs.production.min.js.map +1 -1
  21. package/dist/v2-sdk.esm.js +5138 -6641
  22. package/dist/v2-sdk.esm.js.map +1 -1
  23. package/package.json +1 -1
  24. package/src/abi/PoolFactory.json +414 -204
  25. package/src/abi/PoolLogic.json +160 -134
  26. package/src/abi/ondo/IOndoGMSwap.json +30 -0
  27. package/src/config.ts +15 -9
  28. package/src/entities/pool.ts +56 -253
  29. package/src/entities/utils.ts +15 -0
  30. package/src/services/hyperliquid/index.ts +22 -0
  31. package/src/services/kyberSwap/index.ts +5 -3
  32. package/src/services/ondo/index.ts +142 -0
  33. package/src/services/oneInch/index.ts +5 -4
  34. package/src/services/toros/completeWithdrawal.ts +57 -40
  35. package/src/services/toros/easySwapper.ts +15 -1
  36. package/src/services/toros/initWithdrawal.ts +39 -31
  37. package/src/services/toros/swapData.ts +45 -131
  38. package/src/services/uniswap/V3Liquidity.ts +3 -24
  39. package/src/services/velodrome/liquidity.ts +3 -0
  40. package/src/test/aave.test.ts +99 -70
  41. package/src/test/aerodrome.test.ts +53 -24
  42. package/src/test/aerodromeCL.test.ts +64 -30
  43. package/src/test/arrakis.test.ts +23 -35
  44. package/src/test/balancer.test.ts +114 -106
  45. package/src/test/compoundV3.test.ts +45 -29
  46. package/src/test/constants.ts +56 -11
  47. package/src/test/cowswap.test.ts +33 -35
  48. package/src/test/dhedge.test.ts +45 -12
  49. package/src/test/flatmoney.test.ts +25 -39
  50. package/src/test/fluid.test.ts +33 -24
  51. package/src/test/hyperliquid.onchain.test.ts +131 -0
  52. package/src/test/kyberSwap.test.ts +37 -16
  53. package/src/test/lyra.test.ts +159 -150
  54. package/src/test/odos.test.ts +2 -2
  55. package/src/test/ondo.onchain.test.ts +132 -0
  56. package/src/test/oneInch.test.ts +36 -22
  57. package/src/test/pancakeCL.test.ts +72 -31
  58. package/src/test/pendle.test.ts +94 -54
  59. package/src/test/{pendleMint.test.ts → pendleMint.onchain.test.ts} +22 -8
  60. package/src/test/pool.test.ts +152 -95
  61. package/src/test/toros.onchain.test.ts +92 -0
  62. package/src/test/toros.test.ts +74 -20
  63. package/src/test/torosLimitOrder.test.ts +87 -42
  64. package/src/test/uniswap.test.ts +77 -128
  65. package/src/test/utils/testingHelper.ts +120 -0
  66. package/src/test/velodrome.test.ts +126 -92
  67. package/src/test/velodromeCL.test.ts +43 -31
  68. package/src/test/velodromeV2.test.ts +153 -95
  69. package/src/types.ts +22 -6
  70. package/src/utils/contract.ts +20 -0
  71. package/dist/services/futures/constants.d.ts +0 -1
  72. package/dist/services/futures/index.d.ts +0 -2
  73. package/dist/services/futures/margin.d.ts +0 -2
  74. package/dist/services/futures/trade.d.ts +0 -3
  75. package/dist/services/ramses/vesting.d.ts +0 -4
  76. package/dist/services/uniswap/V3Trade.d.ts +0 -3
  77. package/dist/test/utils/futures.d.ts +0 -2
  78. package/src/abi/IRamsesNonfungiblePositionManager.json +0 -486
  79. package/src/abi/ISynthetiXFuturesMarketV2.json +0 -531
  80. package/src/abi/ISynthetix.json +0 -139
  81. package/src/abi/IUniswapV3Quoter.json +0 -195
  82. package/src/abi/IUniswapV3Router.json +0 -221
  83. package/src/abi/IXRam.json +0 -99
  84. package/src/services/futures/constants.ts +0 -1
  85. package/src/services/futures/index.ts +0 -2
  86. package/src/services/futures/margin.ts +0 -10
  87. package/src/services/futures/trade.ts +0 -32
  88. package/src/services/ramses/vesting.ts +0 -24
  89. package/src/services/uniswap/V3Trade.ts +0 -46
  90. package/src/test/futures.test.ts +0 -51
  91. package/src/test/hyperliquid.test.ts +0 -107
  92. package/src/test/ramses.test.ts +0 -190
  93. package/src/test/ramsesCL.test.ts +0 -155
  94. package/src/test/synthetix.test.ts +0 -36
  95. package/src/test/utils/futures.ts +0 -14
@@ -1,12 +1,26 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
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
+
3
14
  import { Dhedge, Pool } from "..";
4
15
 
5
16
  import { Dapp, Network } from "../types";
6
- import { CONTRACT_ADDRESS, TEST_POOL } from "./constants";
17
+ import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
7
18
  import { getTxOptions } from "./txOptions";
8
19
  import { TestingRunParams, testingHelper } from "./utils/testingHelper";
9
- import { balanceDelta } from "./utils/token";
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";
10
24
 
11
25
  const testCowswap = ({ wallet, network }: TestingRunParams) => {
12
26
  const USDC = CONTRACT_ADDRESS[network].USDC;
@@ -16,44 +30,27 @@ const testCowswap = ({ wallet, network }: TestingRunParams) => {
16
30
  let pool: Pool;
17
31
  jest.setTimeout(100000);
18
32
 
19
- describe(`pool on ${network}`, () => {
33
+ describe(`[${network}] cowswap tests`, () => {
20
34
  beforeAll(async () => {
21
35
  dhedge = new Dhedge(wallet, network);
22
36
  pool = await dhedge.loadPool(TEST_POOL[network]);
23
37
  });
24
38
 
25
- // it("approves unlimited USDC on Cowswap", async () => {
26
- // await pool.approveSpender(
27
- // "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", //Vault relayer
28
- // USDC,
29
- // MAX_AMOUNT,
30
- // await getTxOptions(network)
31
- // );
32
- // const usdcAllowanceDelta = await allowanceDelta(
33
- // pool.address,
34
- // USDC,
35
- // "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", //Vault relayer
36
- // pool.signer
37
- // );
38
- // await expect(usdcAllowanceDelta.gt(0).toBe(true));
39
- // });
40
-
41
- // it("gets gas estimation for 2 USDC into WETH on Cowswap", async () => {
42
- // const gasEstimate = await pool.trade(
43
- // Dapp.COWSWAP,
44
- // USDC,
45
- // WETH,
46
- // "2000000",
47
- // 1,
48
- // await getTxOptions(network),
49
- // true
50
- // );
51
- // console.log(
52
- // "Gas estimate for trading 2 USDC to WETH on Cowswap:",
53
- // gasEstimate
54
- // );
55
- // expect(gasEstimate.minAmountOut).not.toBeNull();
56
- // });
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
+ });
57
54
 
58
55
  it("trades 2 USDC into WETH on Cowswap", async () => {
59
56
  await pool.trade(
@@ -74,6 +71,7 @@ const testCowswap = ({ wallet, network }: TestingRunParams) => {
74
71
  });
75
72
  };
76
73
 
74
+ // CowSwap requires live chain — cannot run on fork
77
75
  testingHelper({
78
76
  network: Network.POLYGON,
79
77
  testingRun: testCowswap,
@@ -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
- import { testingHelper, TestingRunParams } from "./utils/testingHelper";
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
- it("create a pool", async () => {
17
- const pool = await dhedge.createPool("Test", "Test", "TEST", [
18
- ["0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34", true],
19
- ["0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb", false],
20
- ["0x925a2A7214Ed92428B5b1B090F80b25700095e12", false]
21
- ]);
22
- console.log(pool.address);
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.PLASMA,
30
- onFork: false,
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 { AssetEnabled, Network } from "../types";
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
- // top up gas
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 collateralAllowanceDelta = await allowanceDelta(
113
- pool.address,
95
+ const iERC20 = new ethers.Contract(
114
96
  COLLATERAL,
115
- delayOrderContract.address,
97
+ ["function allowance(address,address) view returns (uint256)"],
116
98
  pool.signer
117
99
  );
118
- await expect(collateralAllowanceDelta.gt(0));
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(
@@ -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 { AssetEnabled, Network } from "../types";
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 { allowanceDelta, balanceDelta } from "./utils/token";
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}] compound V3 tests`, () => {
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
- "0x100000000000000"
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
- const newAssets: AssetEnabled[] = [
42
- { asset: WETH, isDeposit: true },
43
- {
44
- asset: FLUID_WETH,
45
- isDeposit: false
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
- const wethAllowanceDelta = await allowanceDelta(
55
- pool.address,
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
- FLUID_WETH,
61
+ ["function allowance(address,address) view returns (uint256)"],
58
62
  pool.signer
59
63
  );
60
- await expect(wethAllowanceDelta.gt(0));
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("withdraw WETH from Fluid WETH market", async () => {
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 wethBalance = await balanceDelta(pool.address, WETH, pool.signer);
82
- expect(wethBalance.gt(0));
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
+ });
@@ -1,19 +1,22 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
2
 
3
+ import BigNumber from "bignumber.js";
4
+ import { ethers } from "ethers";
3
5
  import { Dhedge, Pool } from "..";
4
6
 
7
+ import { routerAddress } from "../config";
5
8
  import { Dapp, Network } from "../types";
6
9
  import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
7
10
  import {
8
11
  TestingRunParams,
12
+ fixOracleAggregatorStaleness,
13
+ runWithImpersonateAccount,
14
+ setChainlinkTimeout,
9
15
  setUSDCAmount,
10
16
  testingHelper,
11
17
  wait
12
18
  } from "./utils/testingHelper";
13
-
14
- import { allowanceDelta, balanceDelta } from "./utils/token";
15
- import { routerAddress } from "../config";
16
- import BigNumber from "bignumber.js";
19
+ import { balanceDelta } from "./utils/token";
17
20
 
18
21
  const testKyberSwap = ({ wallet, network, provider }: TestingRunParams) => {
19
22
  const USDC = CONTRACT_ADDRESS[network].USDC;
@@ -25,15 +28,30 @@ const testKyberSwap = ({ wallet, network, provider }: TestingRunParams) => {
25
28
 
26
29
  describe(`kyberswap on ${network}`, () => {
27
30
  beforeAll(async () => {
28
- dhedge = new Dhedge(wallet, network);
29
- pool = await dhedge.loadPool(TEST_POOL[network]);
30
- // top up gas
31
31
  await provider.send("hardhat_setBalance", [
32
32
  wallet.address,
33
33
  "0x10000000000000000"
34
34
  ]);
35
- await provider.send("evm_mine", []);
36
- // top up USDC
35
+ dhedge = new Dhedge(wallet, network);
36
+ pool = await dhedge.loadPool(TEST_POOL[network]);
37
+
38
+ await setChainlinkTimeout({ pool, provider }, 86400 * 365);
39
+ await fixOracleAggregatorStaleness({ pool, provider });
40
+
41
+ await runWithImpersonateAccount(
42
+ { provider, account: await pool.managerLogic.manager() },
43
+ async ({ signer }) => {
44
+ await pool.managerLogic.connect(signer).setTrader(wallet.address);
45
+ await pool.managerLogic.connect(signer).changeAssets(
46
+ [
47
+ [USDC, true],
48
+ [WETH, true]
49
+ ],
50
+ []
51
+ );
52
+ }
53
+ );
54
+
37
55
  await setUSDCAmount({
38
56
  amount: new BigNumber(2).times(1e6).toFixed(0),
39
57
  userAddress: pool.address,
@@ -44,13 +62,16 @@ const testKyberSwap = ({ wallet, network, provider }: TestingRunParams) => {
44
62
 
45
63
  it("approves unlimited USDC on KyberSwap", async () => {
46
64
  await pool.approve(Dapp.KYBERSWAP, USDC, MAX_AMOUNT);
47
- const usdcAllowanceDelta = await allowanceDelta(
48
- pool.address,
65
+ const iERC20 = new ethers.Contract(
49
66
  USDC,
50
- routerAddress[network]["kyberswap"]!,
67
+ ["function allowance(address,address) view returns (uint256)"],
51
68
  pool.signer
52
69
  );
53
- await expect(usdcAllowanceDelta.gt(0));
70
+ const usdcAllowance = await iERC20.allowance(
71
+ pool.address,
72
+ routerAddress[network][Dapp.KYBERSWAP]!
73
+ );
74
+ expect(usdcAllowance.gt(0)).toBe(true);
54
75
  });
55
76
 
56
77
  it("gets only amount and txData for 2 USDC into WETH on KyberSwap", async () => {
@@ -77,7 +98,7 @@ const testKyberSwap = ({ wallet, network, provider }: TestingRunParams) => {
77
98
  WETH,
78
99
  pool.signer
79
100
  );
80
- expect(wethBalanceDelta.gt(0));
101
+ expect(wethBalanceDelta.gt(0)).toBe(true);
81
102
  });
82
103
  });
83
104
  };
@@ -96,11 +117,11 @@ testingHelper({
96
117
  // testingHelper({
97
118
  // network: Network.POLYGON,
98
119
  // onFork: false,
99
- // testingRun: testOdos
120
+ // testingRun: testKyberSwap
100
121
  // });
101
122
 
102
123
  // testingHelper({
103
124
  // network: Network.BASE,
104
125
  // onFork: false,
105
- // testingRun: testOdos
126
+ // testingRun: testKyberSwap
106
127
  // });