@dhedge/v2-sdk 2.1.3 → 2.1.5

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.
@@ -11,5 +11,18 @@
11
11
  ],
12
12
  "stateMutability": "view",
13
13
  "type": "function"
14
+ },
15
+ {
16
+ "inputs": [],
17
+ "name": "YT",
18
+ "outputs": [
19
+ {
20
+ "internalType": "address",
21
+ "name": "",
22
+ "type": "address"
23
+ }
24
+ ],
25
+ "stateMutability": "view",
26
+ "type": "function"
14
27
  }
15
28
  ]
package/src/config.ts CHANGED
@@ -33,7 +33,7 @@ export const routerAddress: AddressDappNetworkMap = {
33
33
  [Dapp.UNISWAPV3]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
34
34
  [Dapp.ARRAKIS]: "0xc73fb100a995b33f9fa181d420f4c8d74506df66",
35
35
  [Dapp.TOROS]: "0x45b90480D6F643dE2f128db091A357C3c90399f2",
36
- [Dapp.ODOS]: "0x4e3288c9ca110bcc82bf38f09a7b425c095d92bf",
36
+ [Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
37
37
  [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
38
38
  },
39
39
  [Network.OPTIMISM]: {
@@ -46,7 +46,7 @@ export const routerAddress: AddressDappNetworkMap = {
46
46
  [Dapp.VELODROMEV2]: "0xa062ae8a9c5e11aaa026fc2670b0d65ccc8b2858",
47
47
  [Dapp.LYRA]: "0xCCE7819d65f348c64B7Beb205BA367b3fE33763B",
48
48
  [Dapp.ARRAKIS]: "0x9ce88a56d120300061593eF7AD074A1B710094d5",
49
- [Dapp.ODOS]: "0xca423977156bb05b13a2ba3b76bc5419e2fe9680",
49
+ [Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
50
50
  [Dapp.PENDLE]: "0x888888888889758F76e7103c6CbF23ABbF58F946",
51
51
  [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
52
52
  },
@@ -57,7 +57,7 @@ export const routerAddress: AddressDappNetworkMap = {
57
57
  [Dapp.BALANCER]: "0xBA12222222228d8Ba445958a75a0704d566BF2C8",
58
58
  [Dapp.RAMSES]: "0xaaa87963efeb6f7e0a2711f397663105acb1805e",
59
59
  [Dapp.TOROS]: "0xA5679C4272A056Bb83f039961fae7D99C48529F5",
60
- [Dapp.ODOS]: "0xa669e7A0d4b3e4Fa48af2dE86BD4CD7126Be4e13",
60
+ [Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
61
61
  [Dapp.PENDLE]: "0x888888888889758F76e7103c6CbF23ABbF58F946",
62
62
  [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
63
63
  },
@@ -66,13 +66,13 @@ export const routerAddress: AddressDappNetworkMap = {
66
66
  [Dapp.AERODROME]: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
67
67
  [Dapp.AAVEV3]: "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
68
68
  [Dapp.TOROS]: "0xf067575Eb60c7587C11e867907AA7284833704d1",
69
- [Dapp.ODOS]: "0x19cEeAd7105607Cd444F5ad10dd51356436095a1",
69
+ [Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
70
70
  [Dapp.PENDLE]: "0x888888888889758F76e7103c6CbF23ABbF58F946",
71
71
  [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
72
72
  },
73
73
  [Network.ETHEREUM]: {
74
74
  [Dapp.AAVEV3]: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
75
- [Dapp.ODOS]: "0xCf5540fFFCdC3d510B18bFcA6d2b9987b0772559",
75
+ [Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
76
76
  [Dapp.PENDLE]: "0x888888888889758F76e7103c6CbF23ABbF58F946",
77
77
  [Dapp.ONEINCH]: "0x111111125421ca6dc452d289314280a0f8842a65",
78
78
  [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
@@ -234,3 +234,12 @@ export const flatMoneyContractAddresses: Readonly<Partial<
234
234
  StableModule: "0xcD3657cB0E851b6a734c4D1e7FC2640Bcd9f6B2d"
235
235
  }
236
236
  };
237
+
238
+ export const OdosSwapFeeRecipient = {
239
+ [Network.POLYGON]: "0x090e7fbD87A673eE3D0B6ccACf0e1d94fB90DA59",
240
+ [Network.OPTIMISM]: "0x813123A13d01d3F07d434673Fdc89cBBA523f14d",
241
+ [Network.ARBITRUM]: "0xfbD2B4216f422DC1eEe1Cff4Fb64B726F099dEF5",
242
+ [Network.BASE]: "0x5619AD05b0253a7e647Bd2E4C01c7f40CEaB0879",
243
+ [Network.ETHEREUM]: "0xfbD2B4216f422DC1eEe1Cff4Fb64B726F099dEF5",
244
+ [Network.PLASMA]: ""
245
+ };
@@ -84,7 +84,7 @@ import {
84
84
  getPancakeUnStakeTxData
85
85
  } from "../services/pancake/staking";
86
86
  import { getOdosSwapTxData } from "../services/odos";
87
- import { getPendleSwapTxData } from "../services/pendle";
87
+ import { getPendleMintTxData, getPendleSwapTxData } from "../services/pendle";
88
88
  import { getCompleteWithdrawalTxData } from "../services/toros/completeWithdrawal";
89
89
  import { getKyberSwapTxData } from "../services/kyberSwap";
90
90
 
@@ -2107,4 +2107,44 @@ export class Pool {
2107
2107
  );
2108
2108
  return tx;
2109
2109
  }
2110
+
2111
+ /**
2112
+ * Mint PT and YT tokens on Pendle
2113
+ * @param {string} assetFrom Asset to mint from (only underlying asset)
2114
+ * @param {string} pt PT address
2115
+ * @param {BigNumber | string} amountIn Amount underlying asset
2116
+ * @param {number} slippage Slippage tolerance in %
2117
+ * @param {any} options Transaction options
2118
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2119
+ * @returns {Promise<any>} Transaction
2120
+ */
2121
+ async mintPendle(
2122
+ assetFrom: string,
2123
+ pt: string,
2124
+ amountIn: BigNumber | string,
2125
+ slippage = 0.5,
2126
+ options: any = null,
2127
+ sdkOptions: SDKOptions = {
2128
+ estimateGas: false
2129
+ }
2130
+ ): Promise<any> {
2131
+ const { swapTxData, minAmountOut } = await getPendleMintTxData(
2132
+ this,
2133
+ assetFrom,
2134
+ pt,
2135
+ amountIn,
2136
+ slippage
2137
+ );
2138
+ const tx = await getPoolTxOrGasEstimate(
2139
+ this,
2140
+ [
2141
+ routerAddress[this.network][Dapp.PENDLE],
2142
+ swapTxData,
2143
+ options,
2144
+ minAmountOut
2145
+ ],
2146
+ sdkOptions
2147
+ );
2148
+ return tx;
2149
+ }
2110
2150
  }
@@ -1,10 +1,29 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import axios from "axios";
3
3
  import { ApiError, ethers } from "../..";
4
- import { networkChainIdMap } from "../../config";
4
+ import { networkChainIdMap, OdosSwapFeeRecipient } from "../../config";
5
5
  import { Pool } from "../../entities";
6
+ import OdosRouterV3Abi from "../../abi/odos/OdosRouterV3.json";
7
+ import BigNumber from "bignumber.js";
6
8
 
7
- export const odosBaseUrl = "https://api.odos.xyz/sor";
9
+ export const odosBaseUrl = "https://enterprise-api.odos.xyz/sor";
10
+
11
+ // Types for Odos Router V3 swap function parameters
12
+ export interface SwapTokenInfo {
13
+ inputToken: string;
14
+ inputAmount: ethers.BigNumber;
15
+ inputReceiver: string;
16
+ outputToken: string;
17
+ outputQuote: ethers.BigNumber;
18
+ outputMin: ethers.BigNumber;
19
+ outputReceiver: string;
20
+ }
21
+
22
+ export interface SwapReferralInfo {
23
+ code: ethers.BigNumber;
24
+ fee: ethers.BigNumber;
25
+ feeRecipient: string;
26
+ }
8
27
 
9
28
  export async function getOdosSwapTxData(
10
29
  pool: Pool,
@@ -13,13 +32,13 @@ export async function getOdosSwapTxData(
13
32
  amountIn: ethers.BigNumber | string,
14
33
  slippage: number
15
34
  ): Promise<{ swapTxData: string; minAmountOut: string }> {
16
- let referralCode = 0; // Defaults to 0 for unregistered activity.
17
- if (
18
- process.env.ODOS_REFERAL_CODE &&
19
- Number(process.env.ODOS_REFERAL_CODE) > 0
20
- ) {
21
- referralCode = Number(process.env.ODOS_REFERAL_CODE);
35
+ if (!process.env.ODOS_API_KEY) {
36
+ throw new Error("ODOS_API_KEY is not set");
22
37
  }
38
+ const ODOS_API_KEY = process.env.ODOS_API_KEY;
39
+
40
+ const referralFeeBips = 2; // 2 basis points = 0.02%
41
+
23
42
  const quoteParams = {
24
43
  chainId: networkChainIdMap[pool.network],
25
44
  inputTokens: [
@@ -36,12 +55,20 @@ export async function getOdosSwapTxData(
36
55
  ],
37
56
  slippageLimitPercent: slippage,
38
57
  userAddr: pool.address,
39
- referralCode
58
+ compact: false,
59
+ referralFeeRecipient: OdosSwapFeeRecipient[pool.network],
60
+ referralFee: referralFeeBips // 0.02% fee
40
61
  };
41
62
  try {
42
63
  const quoteResult = await axios.post(
43
- `${odosBaseUrl}/quote/v2`,
44
- quoteParams
64
+ `${odosBaseUrl}/quote/v3`,
65
+ quoteParams,
66
+ {
67
+ headers: {
68
+ "Content-Type": "application/json",
69
+ "x-api-key": ODOS_API_KEY
70
+ }
71
+ }
45
72
  );
46
73
 
47
74
  const assembleParams = {
@@ -51,10 +78,67 @@ export async function getOdosSwapTxData(
51
78
 
52
79
  const assembleResult = await axios.post(
53
80
  `${odosBaseUrl}/assemble`,
54
- assembleParams
81
+ assembleParams,
82
+ {
83
+ headers: {
84
+ "Content-Type": "application/json",
85
+ "x-api-key": ODOS_API_KEY
86
+ }
87
+ }
55
88
  );
89
+
90
+ const txData = assembleResult.data.transaction.data;
91
+
92
+ // Decode the transaction data
93
+ const iface = new ethers.utils.Interface(OdosRouterV3Abi.abi);
94
+ const decodedData = iface.parseTransaction({ data: txData });
95
+
96
+ const tokenInfo = decodedData.args[0] as SwapTokenInfo;
97
+ const pathDefinition = decodedData.args[1] as string;
98
+ const executor = decodedData.args[2] as string;
99
+ const referralInfo = decodedData.args[3] as SwapReferralInfo;
100
+
101
+ if (
102
+ referralInfo.fee.lte(
103
+ ethers.BigNumber.from((referralFeeBips * 1e18) / 10000)
104
+ )
105
+ ) {
106
+ // Referral fee is already correct, return original txData
107
+ return {
108
+ swapTxData: assembleResult.data.transaction.data,
109
+ minAmountOut: assembleResult.data.outputTokens[0].amount
110
+ };
111
+ }
112
+
113
+ const FEE_DENOM = new BigNumber(1e18);
114
+ const correctedFee = new BigNumber((referralFeeBips * 1e18) / 10000);
115
+ const factor = 1.1;
116
+ const correctedOutputQuote = new BigNumber(tokenInfo.outputQuote.toString())
117
+ .times(
118
+ FEE_DENOM.minus(correctedFee).div(
119
+ FEE_DENOM.minus(referralInfo.fee.toString())
120
+ )
121
+ )
122
+ .times(factor);
123
+
124
+ // example referralInfo.fee could be 0.0005 * 1e18 = 500000000000000, which is 0.05%
125
+ // Create corrected referral info
126
+ const correctedTxData = iface.encodeFunctionData(decodedData.name, [
127
+ {
128
+ ...tokenInfo,
129
+ outputQuote: correctedOutputQuote.toFixed(0)
130
+ },
131
+ pathDefinition,
132
+ executor,
133
+ {
134
+ code: referralInfo.code,
135
+ fee: correctedFee.toFixed(0), // align with referralFeeBips
136
+ feeRecipient: referralInfo.feeRecipient
137
+ }
138
+ ]);
139
+
56
140
  return {
57
- swapTxData: assembleResult.data.transaction.data,
141
+ swapTxData: correctedTxData,
58
142
  minAmountOut: assembleResult.data.outputTokens[0].amount
59
143
  };
60
144
  } catch (e) {
@@ -56,6 +56,39 @@ export async function getPendleSwapTxData(
56
56
  }
57
57
  }
58
58
 
59
+ export async function getPendleMintTxData(
60
+ pool: Pool,
61
+ tokenIn: string,
62
+ pt: string,
63
+ amountIn: ethers.BigNumber | string,
64
+ slippage: number
65
+ ): Promise<{ swapTxData: string; minAmountOut: string | null }> {
66
+ const PTcontract = new ethers.Contract(pt, PTAbi, pool.signer);
67
+ const ytAddress = await PTcontract.YT();
68
+ const params = {
69
+ receiver: pool.address,
70
+ tokensIn: tokenIn,
71
+ tokensOut: `${pt},${ytAddress}`,
72
+ amountsIn: amountIn.toString(),
73
+ slippage: slippage / 100
74
+ };
75
+ try {
76
+ const swapResult = await axios.get(
77
+ `${pendleBaseUrl}/v2/sdk/${networkChainIdMap[pool.network]}/convert`,
78
+ { params }
79
+ );
80
+ return {
81
+ swapTxData: swapResult.data.routes[0].tx.data,
82
+ minAmountOut: swapResult.data.routes[0].outputs.filter(
83
+ (e: { token: string }) => e.token === pt.toLowerCase()
84
+ )[0].amount
85
+ };
86
+ } catch (e) {
87
+ console.error("Error in Pendle API request:", e);
88
+ throw new ApiError("Pendle api request failed");
89
+ }
90
+ }
91
+
59
92
  const checkUnderlying = (market: any, token: string, networkId: number) => {
60
93
  if (market.underlyingAsset !== `${networkId}-${token.toLocaleLowerCase()}`) {
61
94
  throw new Error("Can only trade in or out of the underlying asset");
@@ -25,7 +25,7 @@ const getSwapWithdrawData = async (
25
25
  swapDestMinDestAmount: BigNumber
26
26
  ) => {
27
27
  const srcData = [];
28
- const routerKey = ethers.utils.formatBytes32String("ODOS_V2");
28
+ const routerKey = ethers.utils.formatBytes32String("ODOS_V3");
29
29
  // const destData
30
30
  for (const { token, balance } of trackedAssets) {
31
31
  if (token.toLowerCase() === receiveToken.toLowerCase()) {
@@ -46,7 +46,7 @@ const getAaveAssetWithdrawData = async (
46
46
  const { srcData, dstData } = swapDataParams;
47
47
 
48
48
  const srcDataToEncode: unknown[] = [];
49
- const routerKey = ethers.utils.formatBytes32String("ODOS_V2");
49
+ const routerKey = ethers.utils.formatBytes32String("ODOS_V3");
50
50
  for (const { asset, amount } of srcData) {
51
51
  const swapData = await retry({
52
52
  fn: () => {
@@ -1,6 +1,9 @@
1
1
  import axios from "axios";
2
2
  import BigNumber from "bignumber.js";
3
- import { odosBaseUrl } from "../odos";
3
+ import { ethers } from "ethers";
4
+ import { odosBaseUrl, SwapReferralInfo, SwapTokenInfo } from "../odos";
5
+ import { networkChainIdMap, OdosSwapFeeRecipient } from "../../config";
6
+ import OdosRouterV3Abi from "../../abi/odos/OdosRouterV3.json";
4
7
 
5
8
  export const SWAPPER_ADDERSS = "0x4F754e0F0924afD74980886b0B479Fa1D7C58D0D";
6
9
 
@@ -22,13 +25,19 @@ export const getSwapDataViaOdos = async ({
22
25
  from,
23
26
  slippage
24
27
  }: SwapParams): Promise<string> => {
25
- let referralCode = 0; // Defaults to 0 for unregistered activity.
26
- if (
27
- process.env.ODOS_REFERAL_CODE &&
28
- Number(process.env.ODOS_REFERAL_CODE) > 0
29
- ) {
30
- referralCode = Number(process.env.ODOS_REFERAL_CODE);
28
+ if (!process.env.ODOS_API_KEY) {
29
+ throw new Error("ODOS_API_KEY is not set");
31
30
  }
31
+ const ODOS_API_KEY = process.env.ODOS_API_KEY;
32
+ const network = (Object.keys(networkChainIdMap) as Array<
33
+ keyof typeof networkChainIdMap
34
+ >).find(key => networkChainIdMap[key] === chainId);
35
+ if (!network) {
36
+ throw new Error(`Unsupported chainId: ${chainId}`);
37
+ }
38
+
39
+ const referralFeeBips = 2; // 2 basis points = 0.02%
40
+
32
41
  const quoteParams = {
33
42
  chainId: chainId,
34
43
  inputTokens: [
@@ -45,12 +54,20 @@ export const getSwapDataViaOdos = async ({
45
54
  ],
46
55
  slippageLimitPercent: new BigNumber(slippage).div(100).toString(), // Convert basis points to percentage
47
56
  userAddr: from,
48
- referralCode
57
+ referralFee: referralFeeBips, // 0.02% fee
58
+ referralFeeRecipient: OdosSwapFeeRecipient[network],
59
+ compact: false
49
60
  };
50
61
  try {
51
62
  const quoteResult = await axios.post(
52
- `${odosBaseUrl}/quote/v2`,
53
- quoteParams
63
+ `${odosBaseUrl}/quote/v3`,
64
+ quoteParams,
65
+ {
66
+ headers: {
67
+ "Content-Type": "application/json",
68
+ "x-api-key": ODOS_API_KEY
69
+ }
70
+ }
54
71
  );
55
72
 
56
73
  const assembleParams = {
@@ -60,9 +77,63 @@ export const getSwapDataViaOdos = async ({
60
77
 
61
78
  const assembleResult = await axios.post(
62
79
  `${odosBaseUrl}/assemble`,
63
- assembleParams
80
+ assembleParams,
81
+ {
82
+ headers: {
83
+ "Content-Type": "application/json",
84
+ "x-api-key": ODOS_API_KEY
85
+ }
86
+ }
64
87
  );
65
- return assembleResult.data.transaction.data;
88
+
89
+ const txData = assembleResult.data.transaction.data;
90
+
91
+ // Decode the transaction data
92
+ const iface = new ethers.utils.Interface(OdosRouterV3Abi.abi);
93
+ const decodedData = iface.parseTransaction({ data: txData });
94
+
95
+ const tokenInfo = decodedData.args[0] as SwapTokenInfo;
96
+ const pathDefinition = decodedData.args[1] as string;
97
+ const executor = decodedData.args[2] as string;
98
+ const referralInfo = decodedData.args[3] as SwapReferralInfo;
99
+
100
+ if (
101
+ referralInfo.fee.lte(
102
+ ethers.BigNumber.from((referralFeeBips * 1e18) / 10000)
103
+ )
104
+ ) {
105
+ // Referral fee is already correct, return original txData
106
+ return txData;
107
+ }
108
+
109
+ const FEE_DENOM = new BigNumber(1e18);
110
+ const correctedFee = new BigNumber((referralFeeBips * 1e18) / 10000);
111
+ const factor = 1.1;
112
+ const correctedOutputQuote = new BigNumber(tokenInfo.outputQuote.toString())
113
+ .times(
114
+ FEE_DENOM.minus(correctedFee).div(
115
+ FEE_DENOM.minus(referralInfo.fee.toString())
116
+ )
117
+ )
118
+ .times(factor);
119
+
120
+ // example referralInfo.fee could be 0.0005 * 1e18 = 500000000000000, which is 0.05%
121
+ // Create corrected referral info
122
+ const correctedTxData = iface.encodeFunctionData(decodedData.name, [
123
+ {
124
+ ...tokenInfo,
125
+ outputQuote: correctedOutputQuote.toFixed(0)
126
+ },
127
+ pathDefinition,
128
+ executor,
129
+ {
130
+ code: referralInfo.code,
131
+ fee: correctedFee.toFixed(0), // align with referralFeeBips
132
+ feeRecipient: referralInfo.feeRecipient
133
+ }
134
+ ]);
135
+
136
+ return correctedTxData;
66
137
  } catch (e) {
67
138
  console.error("Error in Odos API request:", e);
68
139
  throw new Error("Swap api request of Odos failed");
@@ -170,7 +170,8 @@ export const CONTRACT_ADDRESS = {
170
170
  USDC: "",
171
171
  WETH: "0x9895d81bb462a195b4922ed7de0e3acd007c32cb",
172
172
  USDT: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
173
- USDE: "0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34"
173
+ USDE: "0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34",
174
+ TOROS: ""
174
175
  }
175
176
  };
176
177
 
@@ -13,7 +13,7 @@ import {
13
13
  import { allowanceDelta, balanceDelta } from "./utils/token";
14
14
  import { getTxOptions } from "./txOptions";
15
15
  import BigNumber from "bignumber.js";
16
- import { routerAddress } from "../config";
16
+ import { OdosSwapFeeRecipient, routerAddress } from "../config";
17
17
 
18
18
  const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
19
19
  const USDC = CONTRACT_ADDRESS[network].USDC;
@@ -35,7 +35,7 @@ const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
35
35
  await provider.send("evm_mine", []);
36
36
  // top up USDC
37
37
  await setUSDCAmount({
38
- amount: new BigNumber(2).times(1e6).toFixed(0),
38
+ amount: new BigNumber(20).times(1e6).toFixed(0),
39
39
  userAddress: pool.address,
40
40
  network,
41
41
  provider
@@ -53,12 +53,12 @@ const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
53
53
  await expect(usdcAllowanceDelta.gt(0));
54
54
  });
55
55
 
56
- it("gets gas estimation for 2 USDC into WETH on Odos", async () => {
56
+ it("gets gas estimation for 10 USDC into WETH on Odos", async () => {
57
57
  const gasEstimate = await pool.trade(
58
58
  Dapp.ODOS,
59
59
  USDC,
60
60
  WETH,
61
- "2000000",
61
+ "10000000",
62
62
  1,
63
63
  await getTxOptions(network),
64
64
  true
@@ -67,13 +67,13 @@ const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
67
67
  expect(gasEstimate.minAmountOut).not.toBeNull();
68
68
  });
69
69
 
70
- it("trades 2 USDC into WETH on Odos", async () => {
70
+ it("trades 10 USDC into WETH on Odos", async () => {
71
71
  await wait(1);
72
72
  await pool.trade(
73
73
  Dapp.ODOS,
74
74
  USDC,
75
75
  WETH,
76
- "2000000",
76
+ "10000000",
77
77
  0.5,
78
78
  await getTxOptions(network)
79
79
  );
@@ -83,20 +83,51 @@ const testOdos = ({ wallet, network, provider }: TestingRunParams) => {
83
83
  pool.signer
84
84
  );
85
85
  expect(wethBalanceDelta.gt(0));
86
+ const wethBalanceDeltaForFeeRecipient = await balanceDelta(
87
+ OdosSwapFeeRecipient[network],
88
+ WETH,
89
+ pool.signer
90
+ );
91
+
92
+ // diffRatio = (1 - fee) / (0.8 * fee)
93
+ // 0.8 is the split percentage for fee recipient
94
+ // e.g. for 0.02% fee, diffRatio = 0.9998 / 0.00016 = 6248.75
95
+ // e.g. for 0.03% fee, diffRatio = 0.9997 / 0.00024 = 4165.42
96
+ // e.g. for 0.04% fee, diffRatio = 0.9996 / 0.00032 = 3123.75
97
+ // e.g. for 0.05% fee, diffRatio = 0.9995 / 0.00040 = 2498.75
98
+ const diffRatio = wethBalanceDelta.div(wethBalanceDeltaForFeeRecipient);
99
+ console.log("diff ratio:", diffRatio.toString());
100
+ expect(diffRatio.gt(6200)).toBe(true);
101
+ expect(diffRatio.lt(6260)).toBe(true);
102
+ const wethBalanceDeltaForRouter = await balanceDelta(
103
+ routerAddress[network]["odos"]!,
104
+ WETH,
105
+ pool.signer
106
+ );
107
+ // diffRatio = (1 - fee) / (0.2 * fee)
108
+ // 0.2 is the split percentage for router
109
+ // e.g. for 0.02% fee, diffRatio = 0.9998 / 0.00004 = 24995
110
+ // e.g. for 0.03% fee, diffRatio = 0.9997 / 0.00006 = 16661.67
111
+ // e.g. for 0.04% fee, diffRatio = 0.9996 / 0.00008 = 12495
112
+ // e.g. for 0.05% fee, diffRatio = 0.9995 / 0.00010 = 9995
113
+ const diffRatioRouter = wethBalanceDelta.div(wethBalanceDeltaForRouter);
114
+ console.log("diff ratio router:", diffRatioRouter.toString());
115
+ expect(diffRatioRouter.gt(24000)).toBe(true);
116
+ expect(diffRatioRouter.lt(26000)).toBe(true);
86
117
  });
87
118
  });
88
119
  };
89
120
 
90
- testingHelper({
91
- network: Network.OPTIMISM,
92
- testingRun: testOdos
93
- });
94
-
95
121
  // testingHelper({
96
- // network: Network.ARBITRUM,
122
+ // network: Network.OPTIMISM,
97
123
  // testingRun: testOdos
98
124
  // });
99
125
 
126
+ testingHelper({
127
+ network: Network.ARBITRUM,
128
+ testingRun: testOdos
129
+ });
130
+
100
131
  // testingHelper({
101
132
  // network: Network.POLYGON,
102
133
  // onFork: false,
@@ -0,0 +1,59 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+
3
+ import { Dhedge, Pool } from "..";
4
+
5
+ import { Network } from "../types";
6
+ import { CONTRACT_ADDRESS } from "./constants";
7
+ import { getTxOptions } from "./txOptions";
8
+ import { TestingRunParams, testingHelper } from "./utils/testingHelper";
9
+
10
+ const testPendle = ({ wallet, network }: TestingRunParams) => {
11
+ const USDE = CONTRACT_ADDRESS[network].USDE;
12
+ const PTJan26Usde = "0x93b544c330f60a2aa05ced87aeeffb8d38fd8c9a";
13
+
14
+ let dhedge: Dhedge;
15
+ let pool: Pool;
16
+ jest.setTimeout(100000);
17
+
18
+ describe(`pool on ${network}`, () => {
19
+ beforeAll(async () => {
20
+ dhedge = new Dhedge(wallet, network);
21
+ pool = await dhedge.loadPool(
22
+ "0xdad21646ebb0997eb59de1f6a68a67059daf4c31"
23
+ );
24
+ });
25
+
26
+ it("can get TX Data for mint PT and SY", async () => {
27
+ const usdeBalance = await pool.utils.getBalance(USDE, pool.address);
28
+ const { txData, minAmountOut } = await pool.mintPendle(
29
+ USDE,
30
+ PTJan26Usde,
31
+ usdeBalance,
32
+ 0.5,
33
+ null,
34
+ { onlyGetTxData: true, estimateGas: true }
35
+ );
36
+ expect(txData).not.toBeNull();
37
+ expect(minAmountOut).not.toBeNull();
38
+ });
39
+
40
+ it("can get for mint PT and SY", async () => {
41
+ const usdeBalance = await pool.utils.getBalance(USDE, pool.address);
42
+ await pool.mintPendle(
43
+ USDE,
44
+ PTJan26Usde,
45
+ usdeBalance,
46
+ 0.5,
47
+ await getTxOptions(network)
48
+ );
49
+ const ptBalance = await pool.utils.getBalance(PTJan26Usde, pool.address);
50
+ expect(ptBalance.gt(0)).toBe(true);
51
+ });
52
+ });
53
+ };
54
+
55
+ testingHelper({
56
+ network: Network.PLASMA,
57
+ onFork: false,
58
+ testingRun: testPendle
59
+ });