@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
|
@@ -1,79 +1,125 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import BigNumber from "bignumber.js";
|
|
4
|
+
import { ethers } from "ethers";
|
|
4
5
|
import { Dhedge, Pool } from "..";
|
|
5
|
-
|
|
6
|
+
import { limitOrderAddress, routerAddress } from "../config";
|
|
7
|
+
|
|
8
|
+
import { Dapp, Network } from "../types";
|
|
9
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
10
|
+
import {
|
|
11
|
+
fixOracleAggregatorStaleness,
|
|
12
|
+
runWithImpersonateAccount,
|
|
13
|
+
setChainlinkTimeout,
|
|
14
|
+
setUSDCAmount,
|
|
15
|
+
testingHelper,
|
|
16
|
+
TestingRunParams
|
|
17
|
+
} from "./utils/testingHelper";
|
|
18
|
+
|
|
19
|
+
const TOROS_BTCBEAR2X = "0x3e63f81b3aa4e821392fccdabdd7d0c960c0235e";
|
|
20
|
+
const BTC_PRICING_ASSET = "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f"; // WBTC
|
|
21
|
+
|
|
22
|
+
const testTorosLimitOrder = ({
|
|
23
|
+
wallet,
|
|
24
|
+
network,
|
|
25
|
+
provider
|
|
26
|
+
}: TestingRunParams) => {
|
|
27
|
+
const ORDER_AMOUNT = ethers.utils.parseEther("0.001");
|
|
28
|
+
const STOP_LOSS = ethers.utils.parseEther("50000");
|
|
29
|
+
const TAKE_PROFIT = ethers.utils.parseEther("200000");
|
|
6
30
|
|
|
7
|
-
import { Network } from "../types";
|
|
8
|
-
// import { MAX_AMOUNT } from "./constants";
|
|
9
|
-
import { testingHelper, TestingRunParams } from "./utils/testingHelper";
|
|
10
|
-
|
|
11
|
-
// import { allowanceDelta } from "./utils/token";
|
|
12
|
-
|
|
13
|
-
// cspell:ignore goldbull
|
|
14
|
-
const TOROS_GOLDBULL2X = "0xc8e7e840ca82804c14061a27aaca1b97a5a592ab";
|
|
15
|
-
// const GOLD_PRICING_ASSET = "0x7624cccCc59361D583F28BEC40D37e7771d2ef5D";
|
|
16
|
-
|
|
17
|
-
const testTorosLimitOrder = ({ wallet, network }: TestingRunParams) => {
|
|
18
|
-
// const ORDER_AMOUNT = ethers.utils.parseEther("0.001");
|
|
19
|
-
// const STOP_LOSS = ethers.utils.parseEther("3000");
|
|
20
|
-
// const TAKE_PROFIT = ethers.utils.parseEther("6000");
|
|
21
|
-
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
31
|
let dhedge: Dhedge;
|
|
24
32
|
let pool: Pool;
|
|
25
33
|
jest.setTimeout(100000);
|
|
26
34
|
|
|
27
35
|
describe(`toros limit order on ${network}`, () => {
|
|
28
36
|
beforeAll(async () => {
|
|
37
|
+
// Top up gas
|
|
38
|
+
await provider.send("hardhat_setBalance", [
|
|
39
|
+
wallet.address,
|
|
40
|
+
"0x10000000000000000"
|
|
41
|
+
]);
|
|
42
|
+
await provider.send("evm_mine", []);
|
|
43
|
+
|
|
29
44
|
dhedge = new Dhedge(wallet, network);
|
|
30
|
-
pool = await dhedge.loadPool(
|
|
31
|
-
|
|
45
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
46
|
+
|
|
47
|
+
await setChainlinkTimeout({ pool, provider }, 86400 * 365);
|
|
48
|
+
await fixOracleAggregatorStaleness({ pool, provider });
|
|
49
|
+
|
|
50
|
+
// Impersonate pool manager to set trader and enable BTCBEAR2X asset
|
|
51
|
+
await runWithImpersonateAccount(
|
|
52
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
53
|
+
async ({ signer }) => {
|
|
54
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
55
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
56
|
+
const easySwapperV2 = routerAddress[network][Dapp.TOROS]!;
|
|
57
|
+
await pool.managerLogic.connect(signer).changeAssets(
|
|
58
|
+
[
|
|
59
|
+
[TOROS_BTCBEAR2X, false],
|
|
60
|
+
[USDC, true],
|
|
61
|
+
[easySwapperV2, false]
|
|
62
|
+
],
|
|
63
|
+
[]
|
|
64
|
+
);
|
|
65
|
+
}
|
|
32
66
|
);
|
|
67
|
+
|
|
68
|
+
// Fund pool with USDC and trade into BTCBEAR2X
|
|
69
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
70
|
+
const usdcAmount = new BigNumber(100).times(1e6).toFixed(0);
|
|
71
|
+
await setUSDCAmount({
|
|
72
|
+
amount: usdcAmount,
|
|
73
|
+
userAddress: pool.address,
|
|
74
|
+
network,
|
|
75
|
+
provider
|
|
76
|
+
});
|
|
77
|
+
await pool.approve(Dapp.TOROS, USDC, MAX_AMOUNT);
|
|
78
|
+
await pool.trade(Dapp.TOROS, USDC, TOROS_BTCBEAR2X, usdcAmount, 1.5);
|
|
33
79
|
});
|
|
34
80
|
|
|
35
81
|
it("approves Toros vault token for LimitOrderManager", async () => {
|
|
36
|
-
const tx = await pool.approveTorosLimitOrder(
|
|
37
|
-
TOROS_GOLDBULL2X,
|
|
38
|
-
MAX_AMOUNT
|
|
39
|
-
);
|
|
82
|
+
const tx = await pool.approveTorosLimitOrder(TOROS_BTCBEAR2X, MAX_AMOUNT);
|
|
40
83
|
await tx.wait(1);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
limitOrderAddress[network],
|
|
84
|
+
const iERC20 = new ethers.Contract(
|
|
85
|
+
TOROS_BTCBEAR2X,
|
|
86
|
+
["function allowance(address,address) view returns (uint256)"],
|
|
45
87
|
pool.signer
|
|
46
88
|
);
|
|
47
|
-
|
|
89
|
+
const allowance = await iERC20.allowance(
|
|
90
|
+
pool.address,
|
|
91
|
+
limitOrderAddress[network]
|
|
92
|
+
);
|
|
93
|
+
expect(allowance.gt(0)).toBe(true);
|
|
48
94
|
});
|
|
49
95
|
|
|
50
96
|
it("creates a limit order", async () => {
|
|
51
97
|
const tx = await pool.createTorosLimitOrder(
|
|
52
|
-
|
|
98
|
+
TOROS_BTCBEAR2X,
|
|
53
99
|
ORDER_AMOUNT,
|
|
54
100
|
STOP_LOSS,
|
|
55
101
|
TAKE_PROFIT,
|
|
56
|
-
|
|
102
|
+
BTC_PRICING_ASSET
|
|
57
103
|
);
|
|
58
104
|
await tx.wait(1);
|
|
59
105
|
const order = await pool.getTorosLimitOrder(
|
|
60
106
|
pool.address,
|
|
61
|
-
|
|
107
|
+
TOROS_BTCBEAR2X
|
|
62
108
|
);
|
|
63
109
|
expect(order).not.toBeNull();
|
|
64
110
|
expect(order!.amount.eq(ORDER_AMOUNT)).toBe(true);
|
|
65
111
|
expect(order!.stopLossPriceD18.eq(STOP_LOSS)).toBe(true);
|
|
66
112
|
expect(order!.takeProfitPriceD18.eq(TAKE_PROFIT)).toBe(true);
|
|
67
|
-
expect(order!.pool.toLowerCase()).toBe(
|
|
113
|
+
expect(order!.pool.toLowerCase()).toBe(TOROS_BTCBEAR2X.toLowerCase());
|
|
68
114
|
expect(order!.pricingAsset.toLowerCase()).toBe(
|
|
69
|
-
|
|
115
|
+
BTC_PRICING_ASSET.toLowerCase()
|
|
70
116
|
);
|
|
71
117
|
});
|
|
72
118
|
|
|
73
119
|
it("modifies a toros limit order", async () => {
|
|
74
120
|
const order = await pool.getTorosLimitOrder(
|
|
75
121
|
pool.address,
|
|
76
|
-
|
|
122
|
+
TOROS_BTCBEAR2X
|
|
77
123
|
);
|
|
78
124
|
if (!order) throw new Error("No existing order found");
|
|
79
125
|
|
|
@@ -87,7 +133,7 @@ const testTorosLimitOrder = ({ wallet, network }: TestingRunParams) => {
|
|
|
87
133
|
.toString();
|
|
88
134
|
|
|
89
135
|
const tx = await pool.modifyTorosLimitOrder(
|
|
90
|
-
|
|
136
|
+
TOROS_BTCBEAR2X,
|
|
91
137
|
order.amount,
|
|
92
138
|
newStopLoss,
|
|
93
139
|
newTakeProfit,
|
|
@@ -97,7 +143,7 @@ const testTorosLimitOrder = ({ wallet, network }: TestingRunParams) => {
|
|
|
97
143
|
|
|
98
144
|
const modifiedOrder = await pool.getTorosLimitOrder(
|
|
99
145
|
pool.address,
|
|
100
|
-
|
|
146
|
+
TOROS_BTCBEAR2X
|
|
101
147
|
);
|
|
102
148
|
expect(modifiedOrder).not.toBeNull();
|
|
103
149
|
expect(modifiedOrder!.stopLossPriceD18.toString()).toBe(newStopLoss);
|
|
@@ -107,16 +153,16 @@ const testTorosLimitOrder = ({ wallet, network }: TestingRunParams) => {
|
|
|
107
153
|
it("deletes a toros limit order", async () => {
|
|
108
154
|
const order = await pool.getTorosLimitOrder(
|
|
109
155
|
pool.address,
|
|
110
|
-
|
|
156
|
+
TOROS_BTCBEAR2X
|
|
111
157
|
);
|
|
112
158
|
if (!order) throw new Error("No existing order found");
|
|
113
159
|
|
|
114
|
-
const tx = await pool.deleteTorosLimitOrder(
|
|
160
|
+
const tx = await pool.deleteTorosLimitOrder(TOROS_BTCBEAR2X);
|
|
115
161
|
await tx.wait(1);
|
|
116
162
|
|
|
117
163
|
const deletedOrder = await pool.getTorosLimitOrder(
|
|
118
164
|
pool.address,
|
|
119
|
-
|
|
165
|
+
TOROS_BTCBEAR2X
|
|
120
166
|
);
|
|
121
167
|
expect(deletedOrder).toBeNull();
|
|
122
168
|
});
|
|
@@ -125,6 +171,5 @@ const testTorosLimitOrder = ({ wallet, network }: TestingRunParams) => {
|
|
|
125
171
|
|
|
126
172
|
testingHelper({
|
|
127
173
|
network: Network.ARBITRUM,
|
|
128
|
-
testingRun: testTorosLimitOrder
|
|
129
|
-
onFork: false
|
|
174
|
+
testingRun: testTorosLimitOrder
|
|
130
175
|
});
|
package/src/test/uniswap.test.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { Dhedge, ethers, Pool } from "..";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { nonfungiblePositionManagerAddress } from "../config";
|
|
4
|
+
import { Dapp, Network } from "../types";
|
|
5
5
|
import { CONTRACT_ADDRESS, TEST_POOL } from "./constants";
|
|
6
|
-
import { allowanceDelta, balanceDelta } from "./utils/token";
|
|
7
6
|
import {
|
|
8
7
|
setUSDCAmount,
|
|
8
|
+
setWETHAmount,
|
|
9
|
+
runWithImpersonateAccount,
|
|
9
10
|
testingHelper,
|
|
10
11
|
TestingRunParams
|
|
11
12
|
} from "./utils/testingHelper";
|
|
@@ -30,22 +31,37 @@ const testUniswapV3 = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
30
31
|
"0x10000000000000000"
|
|
31
32
|
]);
|
|
32
33
|
await provider.send("evm_mine", []);
|
|
34
|
+
|
|
35
|
+
// Fund pool with USDC and WETH
|
|
33
36
|
await setUSDCAmount({
|
|
34
|
-
amount: new BigNumber(
|
|
37
|
+
amount: new BigNumber(10000).times(1e6).toFixed(0),
|
|
38
|
+
userAddress: pool.address,
|
|
39
|
+
network,
|
|
40
|
+
provider
|
|
41
|
+
});
|
|
42
|
+
await setWETHAmount({
|
|
43
|
+
amount: new BigNumber(5).times(1e18).toFixed(0),
|
|
35
44
|
userAddress: pool.address,
|
|
36
45
|
network,
|
|
37
46
|
provider
|
|
38
47
|
});
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
// Impersonate the pool manager to set trader and configure assets
|
|
50
|
+
await runWithImpersonateAccount(
|
|
51
|
+
{ provider, account: await pool.managerLogic.manager() },
|
|
52
|
+
async ({ signer }) => {
|
|
53
|
+
await pool.managerLogic.connect(signer).setTrader(wallet.address);
|
|
54
|
+
const newAssets = [
|
|
55
|
+
[CONTRACT_ADDRESS[network].USDC, true],
|
|
56
|
+
[CONTRACT_ADDRESS[network].WETH, true],
|
|
57
|
+
[
|
|
58
|
+
CONTRACT_ADDRESS[network].uniswapV3.nonfungiblePositionManager,
|
|
59
|
+
false
|
|
60
|
+
]
|
|
61
|
+
];
|
|
62
|
+
await pool.managerLogic.connect(signer).changeAssets(newAssets, []);
|
|
46
63
|
}
|
|
47
|
-
|
|
48
|
-
await pool.changeAssets(newAssets);
|
|
64
|
+
);
|
|
49
65
|
|
|
50
66
|
nonfungiblePositionManager = new ethers.Contract(
|
|
51
67
|
CONTRACT_ADDRESS[network].uniswapV3.nonfungiblePositionManager,
|
|
@@ -54,60 +70,42 @@ const testUniswapV3 = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
54
70
|
);
|
|
55
71
|
});
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Dapp.UNISWAPV3,
|
|
60
|
-
CONTRACT_ADDRESS[network].USDC,
|
|
61
|
-
ethers.constants.MaxUint256
|
|
62
|
-
);
|
|
63
|
-
const UsdcAllowanceDelta = await allowanceDelta(
|
|
64
|
-
pool.address,
|
|
65
|
-
CONTRACT_ADDRESS[network].USDC,
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
67
|
-
routerAddress[network].uniswapV3!,
|
|
68
|
-
pool.signer
|
|
69
|
-
);
|
|
70
|
-
expect(UsdcAllowanceDelta.gte(0));
|
|
71
|
-
});
|
|
73
|
+
// Note: tradeUniswapV3 (UniswapV3RouterGuard) is deprecated on all chains.
|
|
74
|
+
// Swap tests removed. Use Dapp.ONEINCH or Dapp.KYBERSWAP for trading instead.
|
|
72
75
|
|
|
73
|
-
it("
|
|
74
|
-
await pool.
|
|
75
|
-
CONTRACT_ADDRESS[network].USDC,
|
|
76
|
-
CONTRACT_ADDRESS[network].WETH,
|
|
77
|
-
new BigNumber(5000).times(1e6).toFixed(0),
|
|
78
|
-
500,
|
|
79
|
-
0.5
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const wethAllowanceDelta = await balanceDelta(
|
|
83
|
-
pool.address,
|
|
84
|
-
CONTRACT_ADDRESS[network].WETH,
|
|
85
|
-
pool.signer
|
|
86
|
-
);
|
|
87
|
-
expect(wethAllowanceDelta.gt(0));
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("approves unlimited WETH on for UniswapV3 LP", async () => {
|
|
91
|
-
await pool.approveUniswapV3Liquidity(
|
|
76
|
+
it("approves unlimited USDC and WETH for UniswapV3 LP", async () => {
|
|
77
|
+
const usdcTx = await pool.approveUniswapV3Liquidity(
|
|
92
78
|
CONTRACT_ADDRESS[network].USDC,
|
|
93
79
|
ethers.constants.MaxInt256
|
|
94
80
|
);
|
|
95
|
-
await
|
|
81
|
+
await usdcTx.wait(1);
|
|
82
|
+
const wethTx = await pool.approveUniswapV3Liquidity(
|
|
96
83
|
CONTRACT_ADDRESS[network].WETH,
|
|
97
84
|
ethers.constants.MaxInt256
|
|
98
85
|
);
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
await wethTx.wait(1);
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
88
|
+
const positionManager = nonfungiblePositionManagerAddress[network][
|
|
89
|
+
Dapp.UNISWAPV3
|
|
90
|
+
]!;
|
|
91
|
+
const allowanceAbi = [
|
|
92
|
+
"function allowance(address,address) view returns (uint256)"
|
|
93
|
+
];
|
|
94
|
+
const usdcAllowance = await new ethers.Contract(
|
|
101
95
|
CONTRACT_ADDRESS[network].USDC,
|
|
102
|
-
|
|
96
|
+
allowanceAbi,
|
|
103
97
|
pool.signer
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
).allowance(pool.address, positionManager);
|
|
99
|
+
const wethAllowance = await new ethers.Contract(
|
|
100
|
+
CONTRACT_ADDRESS[network].WETH,
|
|
101
|
+
allowanceAbi,
|
|
102
|
+
pool.signer
|
|
103
|
+
).allowance(pool.address, positionManager);
|
|
104
|
+
expect(usdcAllowance.gt(0)).toBe(true);
|
|
105
|
+
expect(wethAllowance.gt(0)).toBe(true);
|
|
107
106
|
});
|
|
108
107
|
|
|
109
108
|
it("adds WETH and USDC to a new V3 pool", async () => {
|
|
110
|
-
let result = null;
|
|
111
109
|
const pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
112
110
|
const usdcBalance = await dhedge.utils.getBalance(
|
|
113
111
|
CONTRACT_ADDRESS[network].USDC,
|
|
@@ -118,39 +116,33 @@ const testUniswapV3 = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
118
116
|
pool.address
|
|
119
117
|
);
|
|
120
118
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
0
|
|
140
|
-
);
|
|
141
|
-
} catch (e) {
|
|
142
|
-
console.log("e", e);
|
|
143
|
-
}
|
|
119
|
+
const result = await pool.addLiquidityUniswapV3(
|
|
120
|
+
Dapp.UNISWAPV3,
|
|
121
|
+
CONTRACT_ADDRESS[network].WETH,
|
|
122
|
+
CONTRACT_ADDRESS[network].USDC,
|
|
123
|
+
wethBalance,
|
|
124
|
+
usdcBalance,
|
|
125
|
+
3500,
|
|
126
|
+
4000,
|
|
127
|
+
null,
|
|
128
|
+
null,
|
|
129
|
+
500
|
|
130
|
+
);
|
|
131
|
+
await result.wait(1);
|
|
132
|
+
|
|
133
|
+
tokenId = await nonfungiblePositionManager.tokenOfOwnerByIndex(
|
|
134
|
+
pool.address,
|
|
135
|
+
0
|
|
136
|
+
);
|
|
144
137
|
expect(result).not.toBe(null);
|
|
145
138
|
});
|
|
146
139
|
|
|
147
|
-
it("should remove liquidity from an existing pool
|
|
140
|
+
it("should remove 50% liquidity from an existing pool", async () => {
|
|
148
141
|
const result = await pool.decreaseLiquidity(
|
|
149
142
|
Dapp.UNISWAPV3,
|
|
150
143
|
tokenId.toString(),
|
|
151
|
-
50 //
|
|
144
|
+
50 // percent
|
|
152
145
|
);
|
|
153
|
-
// console.log("result", result);
|
|
154
146
|
expect(result).not.toBe(null);
|
|
155
147
|
});
|
|
156
148
|
|
|
@@ -168,63 +160,20 @@ const testUniswapV3 = ({ wallet, network, provider }: TestingRunParams) => {
|
|
|
168
160
|
Dapp.UNISWAPV3,
|
|
169
161
|
tokenId.toString(),
|
|
170
162
|
wethBalance,
|
|
171
|
-
usdcBalance
|
|
163
|
+
usdcBalance
|
|
172
164
|
);
|
|
173
|
-
// console.log("result", result);
|
|
174
165
|
expect(result).not.toBe(null);
|
|
175
166
|
});
|
|
176
167
|
|
|
177
|
-
it("should claim fees an existing pool", async () => {
|
|
168
|
+
it("should claim fees from an existing pool", async () => {
|
|
178
169
|
const result = await pool.claimFees(Dapp.UNISWAPV3, tokenId.toString());
|
|
179
|
-
// console.log("result", result);
|
|
180
170
|
expect(result).not.toBe(null);
|
|
181
171
|
});
|
|
182
|
-
|
|
183
|
-
// it("approves unlimited USDC to swap on UniswapV3", async () => {
|
|
184
|
-
// let result;
|
|
185
|
-
// const pool = await dhedge.loadPool(TEST_POOL);
|
|
186
|
-
// try {
|
|
187
|
-
// result = await pool.approve(
|
|
188
|
-
// Dapp.UNISWAPV3,
|
|
189
|
-
// USDC,
|
|
190
|
-
// ethers.constants.MaxInt256,
|
|
191
|
-
// options
|
|
192
|
-
// );
|
|
193
|
-
// console.log(result);
|
|
194
|
-
// } catch (e) {
|
|
195
|
-
// console.log(e);
|
|
196
|
-
// }
|
|
197
|
-
// expect(result).not.toBe(null);
|
|
198
|
-
// });
|
|
199
|
-
|
|
200
|
-
// it("should swap USDC into WETH on UniswapV3 pool", async () => {
|
|
201
|
-
// const pool = await dhedge.loadPool(TEST_POOL);
|
|
202
|
-
// const result = await pool.tradeUniswapV3(
|
|
203
|
-
// USDC,
|
|
204
|
-
// WETH,
|
|
205
|
-
// "1000000",
|
|
206
|
-
// FeeAmount.LOW,
|
|
207
|
-
// 1,
|
|
208
|
-
// options
|
|
209
|
-
// );
|
|
210
|
-
|
|
211
|
-
// console.log(result);
|
|
212
|
-
// expect(result).not.toBe(null);
|
|
213
|
-
// });
|
|
214
172
|
});
|
|
215
173
|
};
|
|
216
174
|
|
|
217
175
|
testingHelper({
|
|
218
|
-
network: Network.
|
|
219
|
-
testingRun: testUniswapV3
|
|
176
|
+
network: Network.ARBITRUM,
|
|
177
|
+
testingRun: testUniswapV3,
|
|
178
|
+
onFork: true
|
|
220
179
|
});
|
|
221
|
-
|
|
222
|
-
// testingHelper({
|
|
223
|
-
// network: Network.POLYGON,
|
|
224
|
-
// testingRun: testUniswapV3
|
|
225
|
-
// });
|
|
226
|
-
|
|
227
|
-
// testingHelper({
|
|
228
|
-
// network: Network.ARBITRUM,
|
|
229
|
-
// testingRun: testUniswapV3
|
|
230
|
-
// });
|
|
@@ -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,
|