@dhedge/v2-sdk 1.11.1 → 2.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhedge/v2-sdk",
3
- "version": "1.11.1",
3
+ "version": "2.0.0",
4
4
  "license": "MIT",
5
5
  "description": "🛠 An SDK for building applications on top of dHEDGE V2",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,15 @@
1
+ [
2
+ {
3
+ "inputs": [],
4
+ "name": "SY",
5
+ "outputs": [
6
+ {
7
+ "internalType": "address",
8
+ "name": "",
9
+ "type": "address"
10
+ }
11
+ ],
12
+ "stateMutability": "view",
13
+ "type": "function"
14
+ }
15
+ ]
@@ -0,0 +1 @@
1
+ [{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
@@ -372,9 +372,10 @@ export class Pool {
372
372
  estimateGas = false
373
373
  ): Promise<any> {
374
374
  let swapTxData: string;
375
+ let minAmountOut: string | null = null;
375
376
  switch (dapp) {
376
377
  case Dapp.ONEINCH:
377
- ({ swapTxData } = await getOneInchSwapTxData(
378
+ ({ swapTxData, dstAmount: minAmountOut } = await getOneInchSwapTxData(
378
379
  this,
379
380
  assetFrom,
380
381
  assetTo,
@@ -415,28 +416,28 @@ export class Pool {
415
416
  );
416
417
  break;
417
418
  case Dapp.ODOS:
418
- swapTxData = await getOdosSwapTxData(
419
+ ({ swapTxData, minAmountOut } = await getOdosSwapTxData(
419
420
  this,
420
421
  assetFrom,
421
422
  assetTo,
422
423
  amountIn,
423
424
  slippage
424
- );
425
+ ));
425
426
  break;
426
427
  case Dapp.PENDLE:
427
- swapTxData = await getPendleSwapTxData(
428
+ ({ swapTxData, minAmountOut } = await getPendleSwapTxData(
428
429
  this,
429
430
  assetFrom,
430
431
  assetTo,
431
432
  amountIn,
432
433
  slippage
433
- );
434
+ ));
434
435
  break;
435
436
  default:
436
437
  const iUniswapV2Router = new ethers.utils.Interface(
437
438
  IUniswapV2Router.abi
438
439
  );
439
- const minAmountOut = await this.utils.getMinAmountOut(
440
+ const calculatedMinAmountOut = await this.utils.getMinAmountOut(
440
441
  dapp,
441
442
  assetFrom,
442
443
  assetTo,
@@ -445,7 +446,7 @@ export class Pool {
445
446
  );
446
447
  swapTxData = iUniswapV2Router.encodeFunctionData(Transaction.SWAP, [
447
448
  amountIn,
448
- minAmountOut,
449
+ calculatedMinAmountOut,
449
450
  [assetFrom, assetTo],
450
451
  this.address,
451
452
  await getDeadline(this)
@@ -453,7 +454,7 @@ export class Pool {
453
454
  }
454
455
  const tx = await getPoolTxOrGasEstimate(
455
456
  this,
456
- [routerAddress[this.network][dapp], swapTxData, options],
457
+ [routerAddress[this.network][dapp], swapTxData, options, minAmountOut],
457
458
  estimateGas
458
459
  );
459
460
  return tx;
@@ -12,7 +12,7 @@ export async function getOdosSwapTxData(
12
12
  assetTo: string,
13
13
  amountIn: ethers.BigNumber | string,
14
14
  slippage: number
15
- ): Promise<string> {
15
+ ): Promise<{ swapTxData: string; minAmountOut: string }> {
16
16
  let referralCode = 0; // Defaults to 0 for unregistered activity.
17
17
  if (
18
18
  process.env.ODOS_REFERAL_CODE &&
@@ -53,7 +53,10 @@ export async function getOdosSwapTxData(
53
53
  `${odosBaseUrl}/assemble`,
54
54
  assembleParams
55
55
  );
56
- return assembleResult.data.transaction.data;
56
+ return {
57
+ swapTxData: assembleResult.data.transaction.data,
58
+ minAmountOut: assembleResult.data.outputTokens[0].amount
59
+ };
57
60
  } catch (e) {
58
61
  console.error("Error in Odos API request:", e);
59
62
  throw new ApiError("Swap api request of Odos failed");
@@ -4,6 +4,9 @@ import { ApiError, ethers } from "../..";
4
4
  import { networkChainIdMap } from "../../config";
5
5
  import { Pool } from "../../entities";
6
6
  import ActionMiscV3Abi from "../../abi/pendle/ActionMiscV3.json";
7
+ import PTAbi from "../../abi/pendle/PT.json";
8
+ import SYAbi from "../../abi/pendle/SY.json";
9
+ import BigNumber from "bignumber.js";
7
10
 
8
11
  const pendleBaseUrl = "https://api-v2.pendle.finance/core/v1";
9
12
 
@@ -13,17 +16,27 @@ export async function getPendleSwapTxData(
13
16
  tokenOut: string,
14
17
  amountIn: ethers.BigNumber | string,
15
18
  slippage: number
16
- ): Promise<string> {
19
+ ): Promise<{ swapTxData: string; minAmountOut: string | null }> {
17
20
  const expiredMarket = await checkExitPostExpPT(pool, tokenIn, tokenOut);
18
21
  if (expiredMarket) {
19
- return getExitExpPTTxData(pool, tokenOut, amountIn, expiredMarket);
22
+ const result = await getExitExpPTTxData(
23
+ pool,
24
+ tokenIn,
25
+ tokenOut,
26
+ amountIn,
27
+ expiredMarket
28
+ );
29
+ return {
30
+ swapTxData: result.txData,
31
+ minAmountOut: result.minAmountOut
32
+ };
20
33
  }
21
34
  const params = {
22
35
  receiver: pool.address,
23
36
  tokenIn,
24
37
  tokenOut,
25
38
  amountIn: amountIn.toString(),
26
- slippage
39
+ slippage: slippage / 100
27
40
  };
28
41
  const market = await getMarket(pool, tokenIn, tokenOut);
29
42
  try {
@@ -33,8 +46,10 @@ export async function getPendleSwapTxData(
33
46
  }/markets/${market}/swap`,
34
47
  { params }
35
48
  );
36
-
37
- return swapResult.data.tx.data;
49
+ return {
50
+ swapTxData: swapResult.data.tx.data,
51
+ minAmountOut: swapResult.data.data.amountOut
52
+ };
38
53
  } catch (e) {
39
54
  console.error("Error in Pendle API request:", e);
40
55
  throw new ApiError("Pendle api request failed");
@@ -111,12 +126,13 @@ const checkExitPostExpPT = async (
111
126
  }
112
127
  };
113
128
 
114
- const getExitExpPTTxData = (
129
+ const getExitExpPTTxData = async (
115
130
  pool: Pool,
131
+ tokenIn: string,
116
132
  tokenOut: string,
117
133
  amountIn: ethers.BigNumber | string,
118
134
  market: string
119
- ) => {
135
+ ): Promise<{ txData: string; minAmountOut: string | null }> => {
120
136
  const actionMiscV3 = new ethers.utils.Interface(ActionMiscV3Abi);
121
137
  const txData = actionMiscV3.encodeFunctionData("exitPostExpToToken", [
122
138
  pool.address, // receiver
@@ -137,5 +153,24 @@ const getExitExpPTTxData = (
137
153
  ]
138
154
  ]
139
155
  ]);
140
- return txData;
156
+
157
+ // Get the PT contract instance
158
+ const PTcontract = new ethers.Contract(tokenIn, PTAbi, pool.signer);
159
+ // Get the SY contract instance
160
+ const SYcontract = new ethers.Contract(
161
+ await PTcontract.SY(),
162
+ SYAbi,
163
+ pool.signer
164
+ );
165
+
166
+ const exchangeRate = await SYcontract.exchangeRate();
167
+ const minAmountOut = new BigNumber(amountIn.toString())
168
+ .times(1e18)
169
+ .div(exchangeRate.toString())
170
+ .decimalPlaces(0, BigNumber.ROUND_DOWN)
171
+ .toFixed(0);
172
+ return {
173
+ txData,
174
+ minAmountOut
175
+ };
141
176
  };
@@ -63,7 +63,8 @@ const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
63
63
  await getTxOptions(network),
64
64
  true
65
65
  );
66
- expect(gasEstimate.gt(0));
66
+ expect(gasEstimate.gas.gt(0));
67
+ expect(gasEstimate.minAmountOut).not.toBeNull();
67
68
  });
68
69
 
69
70
  it("trades 2 USDC into WETH on Odos", async () => {
@@ -86,16 +87,16 @@ const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
86
87
  });
87
88
  };
88
89
 
89
- // testingHelper({
90
- // network: Network.OPTIMISM,
91
- // testingRun: testOdos
92
- // });
93
-
94
90
  testingHelper({
95
- network: Network.ARBITRUM,
91
+ network: Network.OPTIMISM,
96
92
  testingRun: testOdos
97
93
  });
98
94
 
95
+ // testingHelper({
96
+ // network: Network.ARBITRUM,
97
+ // testingRun: testOdos
98
+ // });
99
+
99
100
  // testingHelper({
100
101
  // network: Network.POLYGON,
101
102
  // onFork: false,
@@ -71,24 +71,22 @@ const testOneInch = ({ wallet, network, provider }: TestingRunParams) => {
71
71
  await getTxOptions(network),
72
72
  true
73
73
  );
74
- expect(gasEstimate.gt(0));
74
+ expect(gasEstimate.gas.gt(0));
75
+ expect(gasEstimate.minAmountOut).not.toBeNull();
75
76
  });
76
77
 
77
78
  it("gets error on gas estimation for 200 USDC into WETH on 1Inch", async () => {
78
79
  await wait(1);
79
- let gasEstimate = null;
80
- try {
81
- gasEstimate = await pool.trade(
82
- Dapp.ONEINCH,
83
- USDC,
84
- WETH,
85
- "200000000",
86
- 1,
87
- await getTxOptions(network),
88
- true
89
- );
90
- } catch (err) {}
91
- expect(gasEstimate).toBeNull();
80
+ const gasEstimate = await pool.trade(
81
+ Dapp.ONEINCH,
82
+ USDC,
83
+ WETH,
84
+ "200000000",
85
+ 1,
86
+ await getTxOptions(network),
87
+ true
88
+ );
89
+ expect(gasEstimate.gasEstimationError).not.toBeNull();
92
90
  });
93
91
 
94
92
  it("trades 2 USDC into WETH on 1Inch", async () => {
@@ -111,10 +109,10 @@ const testOneInch = ({ wallet, network, provider }: TestingRunParams) => {
111
109
  });
112
110
  };
113
111
 
114
- // testingHelper({
115
- // network: Network.OPTIMISM,
116
- // testingRun: testOneInch
117
- // });
112
+ testingHelper({
113
+ network: Network.OPTIMISM,
114
+ testingRun: testOneInch
115
+ });
118
116
 
119
117
  // testingHelper({
120
118
  // network: Network.POLYGON,
@@ -128,7 +126,7 @@ const testOneInch = ({ wallet, network, provider }: TestingRunParams) => {
128
126
  // testingRun: testOneInch
129
127
  // });
130
128
 
131
- testingHelper({
132
- network: Network.ETHEREUM,
133
- testingRun: testOneInch
134
- });
129
+ // testingHelper({
130
+ // network: Network.ETHEREUM,
131
+ // testingRun: testOneInch
132
+ // });
@@ -8,8 +8,7 @@ import {
8
8
  TestingRunParams,
9
9
  setTokenAmount,
10
10
  setUSDCAmount,
11
- testingHelper,
12
- wait
11
+ testingHelper
13
12
  } from "./utils/testingHelper";
14
13
 
15
14
  import { getTxOptions } from "./txOptions";
@@ -19,7 +18,7 @@ import { balanceDelta } from "./utils/token";
19
18
  const testPendle = ({ wallet, network, provider }: TestingRunParams) => {
20
19
  const USDC = CONTRACT_ADDRESS[network].USDC;
21
20
  const weETH = "0x35751007a407ca6feffe80b3cb397736d2cf4dbe";
22
- const PTweETH = "0xb33808ea0e883138680ba29311a220a7377cdb92";
21
+ // const PTweETH = "0xb33808ea0e883138680ba29311a220a7377cdb92";
23
22
  const PTweETH_matured = "0xe2b2d203577c7cb3d043e89ccf90b5e24d19b66f";
24
23
 
25
24
  let dhedge: Dhedge;
@@ -54,33 +53,62 @@ const testPendle = ({ wallet, network, provider }: TestingRunParams) => {
54
53
  );
55
54
  });
56
55
 
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
- });
56
+ // it("swaps weETH to PTweETH on Pendle", async () => {
57
+ // await pool.approve(Dapp.PENDLE, weETH, MAX_AMOUNT);
58
+ // const weEthBalance = await pool.utils.getBalance(weETH, pool.address);
59
+ // await pool.trade(
60
+ // Dapp.PENDLE,
61
+ // weETH,
62
+ // PTweETH,
63
+ // weEthBalance,
64
+ // 0.5,
65
+ // await getTxOptions(network)
66
+ // );
67
+ // const ptWeEthBalanceDelta = await balanceDelta(
68
+ // pool.address,
69
+ // PTweETH,
70
+ // pool.signer
71
+ // );
72
+ // expect(ptWeEthBalanceDelta.gt(0));
73
+ // });
74
+
75
+ // it("swaps PTweETH to weETH on Pendle", async () => {
76
+ // await pool.approve(Dapp.PENDLE, PTweETH, MAX_AMOUNT);
77
+ // const PTweEthBalance = await pool.utils.getBalance(PTweETH, pool.address);
78
+ // console.log("PTweEthBalance", PTweEthBalance.toString());
79
+ // await wait(3);
80
+ // await pool.trade(
81
+ // Dapp.PENDLE,
82
+ // PTweETH,
83
+ // weETH,
84
+ // PTweEthBalance,
85
+ // 0.5,
86
+ // await getTxOptions(network)
87
+ // );
88
+ // const weEthBalanceDelta = await balanceDelta(
89
+ // pool.address,
90
+ // weETH,
91
+ // pool.signer
92
+ // );
93
+ // expect(weEthBalanceDelta.gt(0));
94
+ // });
75
95
 
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);
96
+ it("exit matured PTweETH to weETH on Pendle", async () => {
97
+ await setTokenAmount({
98
+ amount: new BigNumber(1).times(1e18).toString(),
99
+ provider,
100
+ tokenAddress: PTweETH_matured,
101
+ slot: 0,
102
+ userAddress: pool.address
103
+ });
104
+ await pool.approve(Dapp.PENDLE, PTweETH_matured, MAX_AMOUNT);
105
+ const PTweEthBalance = await pool.utils.getBalance(
106
+ PTweETH_matured,
107
+ pool.address
108
+ );
81
109
  await pool.trade(
82
110
  Dapp.PENDLE,
83
- PTweETH,
111
+ PTweETH_matured,
84
112
  weETH,
85
113
  PTweEthBalance,
86
114
  0.5,
@@ -91,7 +119,7 @@ const testPendle = ({ wallet, network, provider }: TestingRunParams) => {
91
119
  weETH,
92
120
  pool.signer
93
121
  );
94
- expect(weEthBalanceDelta.gt(0));
122
+ expect(weEthBalanceDelta.eq(PTweEthBalance));
95
123
  });
96
124
 
97
125
  it("exit matured PTweETH to weETH on Pendle", async () => {
@@ -107,21 +135,19 @@ const testPendle = ({ wallet, network, provider }: TestingRunParams) => {
107
135
  PTweETH_matured,
108
136
  pool.address
109
137
  );
110
- await wait(3);
111
- await pool.trade(
138
+ const result = await pool.trade(
112
139
  Dapp.PENDLE,
113
140
  PTweETH_matured,
114
141
  weETH,
115
142
  PTweEthBalance,
116
143
  0.5,
117
- await getTxOptions(network)
118
- );
119
- const weEthBalanceDelta = await balanceDelta(
120
- pool.address,
121
- weETH,
122
- pool.signer
144
+ await getTxOptions(network),
145
+ true
123
146
  );
124
- expect(weEthBalanceDelta.eq(PTweEthBalance));
147
+
148
+ expect(result.gas).not.toBeNull();
149
+ expect(result.minAmountOut).not.toBeNull();
150
+ expect(result.gasEstimationError).toBeNull();
125
151
  });
126
152
  });
127
153
  };
@@ -101,17 +101,43 @@ export const getPoolTxOrGasEstimate = async (
101
101
  ): Promise<any> => {
102
102
  if (pool.isDhedge) {
103
103
  if (estimateGas) {
104
- return await pool.poolLogic.estimateGas.execTransaction(
105
- args[0],
106
- args[1],
107
- args[2]
108
- );
104
+ let gas = null;
105
+ let gasEstimationError = null;
106
+ try {
107
+ gas = await pool.poolLogic.estimateGas.execTransaction(
108
+ args[0],
109
+ args[1],
110
+ args[2]
111
+ );
112
+ } catch (e) {
113
+ gasEstimationError = e;
114
+ }
115
+ return {
116
+ gas,
117
+ txData: args[1],
118
+ to: args[0],
119
+ gasEstimationError,
120
+ minAmountOut: args[3] || null
121
+ };
109
122
  } else {
110
123
  return await pool.poolLogic.execTransaction(args[0], args[1], args[2]);
111
124
  }
112
125
  } else {
113
126
  if (estimateGas) {
114
- return await pool.signer.estimateGas({ to: args[0], data: args[1] });
127
+ let gas = null;
128
+ let gasEstimationError = null;
129
+ try {
130
+ gas = await pool.signer.estimateGas({ to: args[0], data: args[1] });
131
+ } catch (e) {
132
+ gasEstimationError = e;
133
+ }
134
+ return {
135
+ gas,
136
+ txData: args[1],
137
+ to: args[0],
138
+ gasEstimationError,
139
+ minAmountOut: args[3] || null
140
+ };
115
141
  } else {
116
142
  return await pool.signer.sendTransaction({
117
143
  to: args[0],