@dhedge/v2-sdk 1.10.15 → 1.11.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.
@@ -0,0 +1,141 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import axios from "axios";
3
+ import { ApiError, ethers } from "../..";
4
+ import { networkChainIdMap } from "../../config";
5
+ import { Pool } from "../../entities";
6
+ import ActionMiscV3Abi from "../../abi/pendle/ActionMiscV3.json";
7
+
8
+ const pendleBaseUrl = "https://api-v2.pendle.finance/core/v1";
9
+
10
+ export async function getPendleSwapTxData(
11
+ pool: Pool,
12
+ tokenIn: string,
13
+ tokenOut: string,
14
+ amountIn: ethers.BigNumber | string,
15
+ slippage: number
16
+ ): Promise<string> {
17
+ const expiredMarket = await checkExitPostExpPT(pool, tokenIn, tokenOut);
18
+ if (expiredMarket) {
19
+ return getExitExpPTTxData(pool, tokenOut, amountIn, expiredMarket);
20
+ }
21
+ const params = {
22
+ receiver: pool.address,
23
+ tokenIn,
24
+ tokenOut,
25
+ amountIn: amountIn.toString(),
26
+ slippage
27
+ };
28
+ const market = await getMarket(pool, tokenIn, tokenOut);
29
+ try {
30
+ const swapResult = await axios.get(
31
+ `${pendleBaseUrl}/sdk/${
32
+ networkChainIdMap[pool.network]
33
+ }/markets/${market}/swap`,
34
+ { params }
35
+ );
36
+
37
+ return swapResult.data.tx.data;
38
+ } catch (e) {
39
+ console.error("Error in Pendle API request:", e);
40
+ throw new ApiError("Pendle api request failed");
41
+ }
42
+ }
43
+
44
+ const checkUnderlying = (market: any, token: string, networkId: number) => {
45
+ if (market.underlyingAsset !== `${networkId}-${token.toLocaleLowerCase()}`) {
46
+ throw new Error("Can only trade in or out of the underlying asset");
47
+ }
48
+ };
49
+
50
+ export async function getMarket(
51
+ pool: Pool,
52
+ tokenIn: string,
53
+ tokenOut: string
54
+ ): Promise<string> {
55
+ const networkId = networkChainIdMap[pool.network];
56
+ let marketResult;
57
+ try {
58
+ marketResult = await axios.get(
59
+ `${pendleBaseUrl}/${networkId}/markets/active`
60
+ );
61
+ } catch (e) {
62
+ console.error("Error in Pendle API request:", e);
63
+ throw new ApiError("Pendle api request failed");
64
+ }
65
+
66
+ const allMarkets = marketResult.data.markets;
67
+ const markets = [tokenIn, tokenOut].map(token =>
68
+ allMarkets.find(
69
+ (market: any) => market.pt === `${networkId}-${token.toLocaleLowerCase()}`
70
+ )
71
+ );
72
+ if (markets[0]) {
73
+ checkUnderlying(markets[0], tokenOut, networkId);
74
+ return markets[0].address;
75
+ } else if (markets[1]) {
76
+ checkUnderlying(markets[1], tokenIn, networkId);
77
+ return markets[1].address;
78
+ } else {
79
+ throw new Error("Can only trade PT assets");
80
+ }
81
+ }
82
+
83
+ const checkExitPostExpPT = async (
84
+ pool: Pool,
85
+ tokenIn: string,
86
+ tokenOut: string
87
+ ): Promise<string | null> => {
88
+ const networkId = networkChainIdMap[pool.network];
89
+ let inactiveMarketResult;
90
+ try {
91
+ inactiveMarketResult = await axios.get(
92
+ `${pendleBaseUrl}/${networkId}/markets/inactive`
93
+ );
94
+ } catch (e) {
95
+ console.error("Error in Pendle API request:", e);
96
+ throw new ApiError("Pendle api request failed");
97
+ }
98
+ const allInactiveMarkets = inactiveMarketResult.data.markets;
99
+ const markets = [tokenIn, tokenOut].map(token =>
100
+ allInactiveMarkets.find(
101
+ (market: any) => market.pt === `${networkId}-${token.toLocaleLowerCase()}`
102
+ )
103
+ );
104
+ if (markets[0]) {
105
+ checkUnderlying(markets[0], tokenOut, networkId);
106
+ return markets[0].address;
107
+ } else if (markets[1]) {
108
+ throw new Error("Can not trade to expired PT asset");
109
+ } else {
110
+ return null;
111
+ }
112
+ };
113
+
114
+ const getExitExpPTTxData = (
115
+ pool: Pool,
116
+ tokenOut: string,
117
+ amountIn: ethers.BigNumber | string,
118
+ market: string
119
+ ) => {
120
+ const actionMiscV3 = new ethers.utils.Interface(ActionMiscV3Abi);
121
+ const txData = actionMiscV3.encodeFunctionData("exitPostExpToToken", [
122
+ pool.address, // receiver
123
+ market, // market
124
+ amountIn.toString(), // netPtIn
125
+ 0, // netLpIn
126
+ [
127
+ tokenOut,
128
+ 0, // minTokenOut
129
+ tokenOut, // tokenRedeemSy,
130
+ ethers.constants.AddressZero, //pendleSwap;
131
+ // swapData
132
+ [
133
+ 0, // swapType
134
+ ethers.constants.AddressZero, // extRouter
135
+ ethers.constants.HashZero, // extCalldata
136
+ false // needScale
137
+ ]
138
+ ]
139
+ ]);
140
+ return txData;
141
+ };
@@ -19,7 +19,6 @@ import {
19
19
  } from "../../config";
20
20
  import INonfungiblePositionManager from "../../abi/INonfungiblePositionManager.json";
21
21
  import IVeldodromePositionManager from "../../abi/IVelodromeNonfungiblePositionManager.json";
22
- import IShadowNonfungiblePositionManager from "../../abi/IShadowNonfungiblePositionManager.json";
23
22
  import IRamsesPositionManager from "../../abi/IRamsesNonfungiblePositionManager.json";
24
23
  import IArrakisV1RouterStaking from "../../abi/IArrakisV1RouterStaking.json";
25
24
  import IPancakeMasterChef from "../../abi/IPancakeMasterChefV3.json";
@@ -78,8 +77,8 @@ export async function getUniswapV3MintTxData(
78
77
  | Dapp.VELODROMECL
79
78
  | Dapp.AERODROMECL
80
79
  | Dapp.RAMSESCL
81
- | Dapp.PANCAKECL
82
- | Dapp.SHADOWCL,
80
+ | Dapp.PANCAKECL,
81
+
83
82
  pool: Pool,
84
83
  assetA: string,
85
84
  assetB: string,
@@ -170,12 +169,6 @@ export async function getUniswapV3MintTxData(
170
169
  mintParams.push(0);
171
170
  }
172
171
 
173
- if (dapp === Dapp.SHADOWCL) {
174
- iNonfungiblePositionManager = new ethers.utils.Interface(
175
- IShadowNonfungiblePositionManager
176
- );
177
- }
178
-
179
172
  return iNonfungiblePositionManager.encodeFunctionData(Transaction.MINT, [
180
173
  mintParams
181
174
  ]);
@@ -196,9 +189,7 @@ export async function getUniswapV3Liquidity(
196
189
  const iNonfungiblePositionManager = new ethers.Contract(
197
190
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
198
191
  nonfungiblePositionManagerAddress[pool.network][dapp]!,
199
- dapp === Dapp.SHADOWCL
200
- ? IShadowNonfungiblePositionManager
201
- : INonfungiblePositionManager.abi,
192
+ INonfungiblePositionManager.abi,
202
193
  pool.signer
203
194
  );
204
195
  const result = await iNonfungiblePositionManager.positions(tokenId);
@@ -218,8 +209,7 @@ export async function getIncreaseLiquidityTxData(
218
209
  dapp === Dapp.VELODROMECL ||
219
210
  dapp === Dapp.AERODROMECL ||
220
211
  dapp === Dapp.RAMSESCL ||
221
- dapp === Dapp.PANCAKECL ||
222
- dapp === Dapp.SHADOWCL
212
+ dapp === Dapp.PANCAKECL
223
213
  ) {
224
214
  const abi = new ethers.utils.Interface(INonfungiblePositionManager.abi);
225
215
  txData = abi.encodeFunctionData(Transaction.INCREASE_LIQUIDITY, [
@@ -256,8 +246,7 @@ export async function getDecreaseLiquidityTxData(
256
246
  dapp === Dapp.VELODROMECL ||
257
247
  dapp === Dapp.AERODROMECL ||
258
248
  dapp === Dapp.RAMSESCL ||
259
- dapp === Dapp.PANCAKECL ||
260
- dapp === Dapp.SHADOWCL
249
+ dapp === Dapp.PANCAKECL
261
250
  ) {
262
251
  const abi = new ethers.utils.Interface(INonfungiblePositionManager.abi);
263
252
  const liquidity = (await getUniswapV3Liquidity(dapp, tokenId, pool))
@@ -43,7 +43,7 @@ export const TEST_POOL = {
43
43
  [Network.OPTIMISM]: "0x12573bfdf764ab9d52aca20e2827497a66829716",
44
44
  [Network.ARBITRUM]: "0x0b5f6591c8eb23e5a68102d3d39ebbb464ee5c14",
45
45
  [Network.BASE]: "0x4842b42F68524383F609aa46eAfc18c1459cE3cD",
46
- [Network.SONIC]: ""
46
+ [Network.ETHEREUM]: "0xe8e74f664d2d6a919a18b911990db0979789b6f7"
47
47
  };
48
48
 
49
49
  export const CONTRACT_ADDRESS = {
@@ -135,11 +135,11 @@ export const CONTRACT_ADDRESS = {
135
135
  COMPOUNDV3_WETH: "",
136
136
  TOROS: ""
137
137
  },
138
- [Network.SONIC]: {
139
- USDC: "0x29219dd400f2bf60e5a23d13be72b486d4038894",
138
+ [Network.ETHEREUM]: {
139
+ USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
140
140
  USDT: "",
141
141
  SUSD: "",
142
- WETH: "0x50c42deacd8fc9773493ed674b675be577f2634b",
142
+ WETH: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
143
143
  WBTC: "",
144
144
  SWETH: "",
145
145
  uniswapV3: {
@@ -164,7 +164,7 @@ export const USDC_BALANCEOF_SLOT = {
164
164
  [Network.ARBITRUM]: 9,
165
165
  [Network.POLYGON]: 0,
166
166
  [Network.BASE]: 9,
167
- [Network.SONIC]: 9
167
+ [Network.ETHEREUM]: 9
168
168
  };
169
169
 
170
170
  export const WETH_BALANCEOF_SLOT = {
@@ -172,5 +172,5 @@ export const WETH_BALANCEOF_SLOT = {
172
172
  [Network.ARBITRUM]: 51,
173
173
  [Network.POLYGON]: 0,
174
174
  [Network.BASE]: 0,
175
- [Network.SONIC]: 0
175
+ [Network.ETHEREUM]: 3
176
176
  };
@@ -34,6 +34,13 @@ const testOneInch = ({ wallet, network, provider }: TestingRunParams) => {
34
34
  "0x10000000000000000"
35
35
  ]);
36
36
  await provider.send("evm_mine", []);
37
+
38
+ const newAssets = [
39
+ { asset: USDC, isDeposit: true },
40
+ { asset: WETH, isDeposit: true }
41
+ ];
42
+
43
+ await pool.managerLogic.changeAssets(newAssets, []);
37
44
  // top up USDC
38
45
  await setUSDCAmount({
39
46
  amount: new BigNumber(2).times(1e6).toFixed(0),
@@ -104,10 +111,10 @@ const testOneInch = ({ wallet, network, provider }: TestingRunParams) => {
104
111
  });
105
112
  };
106
113
 
107
- testingHelper({
108
- network: Network.OPTIMISM,
109
- testingRun: testOneInch
110
- });
114
+ // testingHelper({
115
+ // network: Network.OPTIMISM,
116
+ // testingRun: testOneInch
117
+ // });
111
118
 
112
119
  // testingHelper({
113
120
  // network: Network.POLYGON,
@@ -120,3 +127,8 @@ testingHelper({
120
127
  // onFork: false,
121
128
  // testingRun: testOneInch
122
129
  // });
130
+
131
+ testingHelper({
132
+ network: Network.ETHEREUM,
133
+ testingRun: testOneInch
134
+ });
@@ -0,0 +1,132 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+
3
+ import { Dhedge, Pool } from "..";
4
+
5
+ import { Dapp, Network } from "../types";
6
+ import { CONTRACT_ADDRESS, MAX_AMOUNT } from "./constants";
7
+ import {
8
+ TestingRunParams,
9
+ setTokenAmount,
10
+ setUSDCAmount,
11
+ testingHelper,
12
+ wait
13
+ } from "./utils/testingHelper";
14
+
15
+ import { getTxOptions } from "./txOptions";
16
+ import BigNumber from "bignumber.js";
17
+ import { balanceDelta } from "./utils/token";
18
+
19
+ const testPendle = ({ wallet, network, provider }: TestingRunParams) => {
20
+ const USDC = CONTRACT_ADDRESS[network].USDC;
21
+ const weETH = "0x35751007a407ca6feffe80b3cb397736d2cf4dbe";
22
+ const PTweETH = "0xb33808ea0e883138680ba29311a220a7377cdb92";
23
+ const PTweETH_matured = "0xe2b2d203577c7cb3d043e89ccf90b5e24d19b66f";
24
+
25
+ let dhedge: Dhedge;
26
+ let pool: Pool;
27
+ jest.setTimeout(100000);
28
+
29
+ describe(`pool on ${network}`, () => {
30
+ beforeAll(async () => {
31
+ dhedge = new Dhedge(wallet, network);
32
+ pool = await dhedge.loadPool(wallet.address, false);
33
+ // top up gas
34
+ await provider.send("hardhat_setBalance", [
35
+ wallet.address,
36
+ "0x10000000000000000"
37
+ ]);
38
+ await provider.send("evm_mine", []);
39
+ // top up USDC
40
+ await setUSDCAmount({
41
+ amount: new BigNumber(2000).times(1e6).toFixed(0),
42
+ userAddress: pool.address,
43
+ network,
44
+ provider
45
+ });
46
+ await pool.approve(Dapp.ODOS, USDC, MAX_AMOUNT);
47
+ await pool.trade(
48
+ Dapp.ODOS,
49
+ USDC,
50
+ weETH,
51
+ "2000000000",
52
+ 0.5,
53
+ await getTxOptions(network)
54
+ );
55
+ });
56
+
57
+ it("swaps weETH to PTweETH on Pendle", async () => {
58
+ await pool.approve(Dapp.PENDLE, weETH, MAX_AMOUNT);
59
+ const weEthBalance = await pool.utils.getBalance(weETH, pool.address);
60
+ await pool.trade(
61
+ Dapp.PENDLE,
62
+ weETH,
63
+ PTweETH,
64
+ weEthBalance,
65
+ 0.5,
66
+ await getTxOptions(network)
67
+ );
68
+ const ptWeEthBalanceDelta = await balanceDelta(
69
+ pool.address,
70
+ PTweETH,
71
+ pool.signer
72
+ );
73
+ expect(ptWeEthBalanceDelta.gt(0));
74
+ });
75
+
76
+ it("swaps PTweETH to weETH on Pendle", async () => {
77
+ await pool.approve(Dapp.PENDLE, PTweETH, MAX_AMOUNT);
78
+ const PTweEthBalance = await pool.utils.getBalance(PTweETH, pool.address);
79
+ console.log("PTweEthBalance", PTweEthBalance.toString());
80
+ await wait(3);
81
+ await pool.trade(
82
+ Dapp.PENDLE,
83
+ PTweETH,
84
+ weETH,
85
+ PTweEthBalance,
86
+ 0.5,
87
+ await getTxOptions(network)
88
+ );
89
+ const weEthBalanceDelta = await balanceDelta(
90
+ pool.address,
91
+ weETH,
92
+ pool.signer
93
+ );
94
+ expect(weEthBalanceDelta.gt(0));
95
+ });
96
+
97
+ it("exit matured PTweETH to weETH on Pendle", async () => {
98
+ await setTokenAmount({
99
+ amount: new BigNumber(1).times(1e18).toString(),
100
+ provider,
101
+ tokenAddress: PTweETH_matured,
102
+ slot: 0,
103
+ userAddress: pool.address
104
+ });
105
+ await pool.approve(Dapp.PENDLE, PTweETH_matured, MAX_AMOUNT);
106
+ const PTweEthBalance = await pool.utils.getBalance(
107
+ PTweETH_matured,
108
+ pool.address
109
+ );
110
+ await wait(3);
111
+ await pool.trade(
112
+ Dapp.PENDLE,
113
+ PTweETH_matured,
114
+ weETH,
115
+ PTweEthBalance,
116
+ 0.5,
117
+ await getTxOptions(network)
118
+ );
119
+ const weEthBalanceDelta = await balanceDelta(
120
+ pool.address,
121
+ weETH,
122
+ pool.signer
123
+ );
124
+ expect(weEthBalanceDelta.eq(PTweEthBalance));
125
+ });
126
+ });
127
+ };
128
+
129
+ testingHelper({
130
+ network: Network.ARBITRUM,
131
+ testingRun: testPendle
132
+ });
@@ -8,7 +8,7 @@ export const networkPortMap = {
8
8
  [Network.OPTIMISM]: 8544,
9
9
  [Network.ARBITRUM]: 8540,
10
10
  [Network.BASE]: 8546,
11
- [Network.SONIC]: 8547
11
+ [Network.ETHEREUM]: 8547
12
12
  };
13
13
 
14
14
  export const getWalletData = (
package/src/types.ts CHANGED
@@ -6,7 +6,7 @@ export enum Network {
6
6
  OPTIMISM = "optimism",
7
7
  ARBITRUM = "arbitrum",
8
8
  BASE = "base",
9
- SONIC = "sonic"
9
+ ETHEREUM = "ethereum"
10
10
  }
11
11
 
12
12
  export enum Dapp {
@@ -31,7 +31,7 @@ export enum Dapp {
31
31
  PANCAKECL = "pancakeCL",
32
32
  COMPOUNDV3 = "compoundV3",
33
33
  ODOS = "odos",
34
- SHADOWCL = "shadowCL"
34
+ PENDLE = "pendle"
35
35
  }
36
36
 
37
37
  export enum Transaction {