@dhedge/v2-sdk 1.9.0 → 1.9.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.
- package/dist/entities/pool.d.ts +22 -1
- package/dist/errors.d.ts +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/services/velodrome/staking.d.ts +2 -2
- package/dist/services/zeroEx/zeroExTrade.d.ts +3 -0
- package/dist/types.d.ts +3 -1
- package/dist/v2-sdk.cjs.development.js +672 -134
- 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 +672 -135
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/IVelodromeGaugeV2.json +191 -0
- package/src/config.ts +5 -2
- package/src/entities/pool.ts +92 -5
- package/src/errors.ts +10 -0
- package/src/index.ts +1 -0
- package/src/services/velodrome/staking.ts +33 -20
- package/src/services/zeroEx/zeroExTrade.ts +52 -0
- package/src/test/txOptions.ts +1 -1
- package/src/test/velodromeV2.test.ts +114 -0
- package/src/test/zeroEx.test.ts +46 -0
- package/src/types.ts +3 -1
package/package.json
CHANGED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
{
|
|
2
|
+
"abi": [
|
|
3
|
+
{
|
|
4
|
+
"inputs": [
|
|
5
|
+
{
|
|
6
|
+
"internalType": "address",
|
|
7
|
+
"name": "user",
|
|
8
|
+
"type": "address"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"name": "balanceOf",
|
|
12
|
+
"outputs": [
|
|
13
|
+
{
|
|
14
|
+
"internalType": "uint256",
|
|
15
|
+
"name": "",
|
|
16
|
+
"type": "uint256"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"stateMutability": "view",
|
|
20
|
+
"type": "function"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"inputs": [
|
|
24
|
+
{
|
|
25
|
+
"internalType": "uint256",
|
|
26
|
+
"name": "_amount",
|
|
27
|
+
"type": "uint256"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"internalType": "address",
|
|
31
|
+
"name": "_recipient",
|
|
32
|
+
"type": "address"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"name": "deposit",
|
|
36
|
+
"outputs": [],
|
|
37
|
+
"stateMutability": "nonpayable",
|
|
38
|
+
"type": "function"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"inputs": [
|
|
42
|
+
{
|
|
43
|
+
"internalType": "uint256",
|
|
44
|
+
"name": "_amount",
|
|
45
|
+
"type": "uint256"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"name": "deposit",
|
|
49
|
+
"outputs": [],
|
|
50
|
+
"stateMutability": "nonpayable",
|
|
51
|
+
"type": "function"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"inputs": [
|
|
55
|
+
{
|
|
56
|
+
"internalType": "address",
|
|
57
|
+
"name": "_account",
|
|
58
|
+
"type": "address"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"name": "earned",
|
|
62
|
+
"outputs": [
|
|
63
|
+
{
|
|
64
|
+
"internalType": "uint256",
|
|
65
|
+
"name": "_earned",
|
|
66
|
+
"type": "uint256"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"stateMutability": "view",
|
|
70
|
+
"type": "function"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"inputs": [
|
|
74
|
+
{
|
|
75
|
+
"internalType": "address",
|
|
76
|
+
"name": "_account",
|
|
77
|
+
"type": "address"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"name": "getReward",
|
|
81
|
+
"outputs": [],
|
|
82
|
+
"stateMutability": "nonpayable",
|
|
83
|
+
"type": "function"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"inputs": [],
|
|
87
|
+
"name": "isPool",
|
|
88
|
+
"outputs": [
|
|
89
|
+
{
|
|
90
|
+
"internalType": "bool",
|
|
91
|
+
"name": "_isPool",
|
|
92
|
+
"type": "bool"
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"stateMutability": "view",
|
|
96
|
+
"type": "function"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"inputs": [],
|
|
100
|
+
"name": "lastTimeRewardApplicable",
|
|
101
|
+
"outputs": [
|
|
102
|
+
{
|
|
103
|
+
"internalType": "uint256",
|
|
104
|
+
"name": "_time",
|
|
105
|
+
"type": "uint256"
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"stateMutability": "view",
|
|
109
|
+
"type": "function"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"inputs": [],
|
|
113
|
+
"name": "left",
|
|
114
|
+
"outputs": [
|
|
115
|
+
{
|
|
116
|
+
"internalType": "uint256",
|
|
117
|
+
"name": "_left",
|
|
118
|
+
"type": "uint256"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"stateMutability": "view",
|
|
122
|
+
"type": "function"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"inputs": [
|
|
126
|
+
{
|
|
127
|
+
"internalType": "uint256",
|
|
128
|
+
"name": "amount",
|
|
129
|
+
"type": "uint256"
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"name": "notifyRewardAmount",
|
|
133
|
+
"outputs": [],
|
|
134
|
+
"stateMutability": "nonpayable",
|
|
135
|
+
"type": "function"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"inputs": [],
|
|
139
|
+
"name": "rewardPerToken",
|
|
140
|
+
"outputs": [
|
|
141
|
+
{
|
|
142
|
+
"internalType": "uint256",
|
|
143
|
+
"name": "_rewardPerToken",
|
|
144
|
+
"type": "uint256"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"stateMutability": "view",
|
|
148
|
+
"type": "function"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"inputs": [],
|
|
152
|
+
"name": "rewardToken",
|
|
153
|
+
"outputs": [
|
|
154
|
+
{
|
|
155
|
+
"internalType": "address",
|
|
156
|
+
"name": "_token",
|
|
157
|
+
"type": "address"
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"stateMutability": "view",
|
|
161
|
+
"type": "function"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"inputs": [],
|
|
165
|
+
"name": "stakingToken",
|
|
166
|
+
"outputs": [
|
|
167
|
+
{
|
|
168
|
+
"internalType": "address",
|
|
169
|
+
"name": "_pool",
|
|
170
|
+
"type": "address"
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"stateMutability": "view",
|
|
174
|
+
"type": "function"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"inputs": [
|
|
178
|
+
{
|
|
179
|
+
"internalType": "uint256",
|
|
180
|
+
"name": "_amount",
|
|
181
|
+
"type": "uint256"
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"name": "withdraw",
|
|
185
|
+
"outputs": [],
|
|
186
|
+
"stateMutability": "nonpayable",
|
|
187
|
+
"type": "function"
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -29,7 +29,8 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
29
29
|
[Dapp.BALANCER]: "0xBA12222222228d8Ba445958a75a0704d566BF2C8",
|
|
30
30
|
[Dapp.UNISWAPV3]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
|
|
31
31
|
[Dapp.ARRAKIS]: "0xc73fb100a995b33f9fa181d420f4c8d74506df66",
|
|
32
|
-
[Dapp.TOROS]: "0xB2F1498983bf9c9442c35F772e6C1AdE66a8DeDE"
|
|
32
|
+
[Dapp.TOROS]: "0xB2F1498983bf9c9442c35F772e6C1AdE66a8DeDE",
|
|
33
|
+
[Dapp.ZEROEX]: "0xdef1c0ded9bec7f1a1670819833240f027b25eff"
|
|
33
34
|
},
|
|
34
35
|
[Network.OPTIMISM]: {
|
|
35
36
|
[Dapp.UNISWAPV3]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
|
|
@@ -38,8 +39,10 @@ export const routerAddress: AddressDappNetworkMap = {
|
|
|
38
39
|
[Dapp.ONEINCH]: "0x1111111254EEB25477B68fb85Ed929f73A960582",
|
|
39
40
|
[Dapp.TOROS]: "0x3988513793bCE39f0167064A9F7fC3617FaF35AB",
|
|
40
41
|
[Dapp.VELODROME]: "0x9c12939390052919aF3155f41Bf4160Fd3666A6f",
|
|
42
|
+
[Dapp.VELODROMEV2]: "0xa062ae8a9c5e11aaa026fc2670b0d65ccc8b2858",
|
|
41
43
|
[Dapp.LYRA]: "0xCCE7819d65f348c64B7Beb205BA367b3fE33763B",
|
|
42
|
-
[Dapp.ARRAKIS]: "0x9ce88a56d120300061593eF7AD074A1B710094d5"
|
|
44
|
+
[Dapp.ARRAKIS]: "0x9ce88a56d120300061593eF7AD074A1B710094d5",
|
|
45
|
+
[Dapp.ZEROEX]: "0xdef1abe32c034e558cdd535791643c58a13acc10"
|
|
43
46
|
},
|
|
44
47
|
[Network.ARBITRUM]: {
|
|
45
48
|
[Dapp.ONEINCH]: "0x1111111254EEB25477B68fb85Ed929f73A960582",
|
package/src/entities/pool.ts
CHANGED
|
@@ -60,6 +60,8 @@ import {
|
|
|
60
60
|
getFuturesChangeMarginTxData
|
|
61
61
|
} from "../services/futures";
|
|
62
62
|
import { getFuturesCancelOrderTxData } from "../services/futures/trade";
|
|
63
|
+
import { getZeroExTradeTxData } from "../services/zeroEx/zeroExTrade";
|
|
64
|
+
import { ApiError } from "../errors";
|
|
63
65
|
|
|
64
66
|
export class Pool {
|
|
65
67
|
public readonly poolLogic: Contract;
|
|
@@ -286,6 +288,16 @@ export class Pool {
|
|
|
286
288
|
): Promise<any> {
|
|
287
289
|
let swapTxData: string;
|
|
288
290
|
switch (dapp) {
|
|
291
|
+
case Dapp.ZEROEX:
|
|
292
|
+
swapTxData = await getZeroExTradeTxData(
|
|
293
|
+
this.network,
|
|
294
|
+
assetFrom,
|
|
295
|
+
assetTo,
|
|
296
|
+
amountIn,
|
|
297
|
+
slippage,
|
|
298
|
+
this.address
|
|
299
|
+
);
|
|
300
|
+
break;
|
|
289
301
|
case Dapp.ONEINCH:
|
|
290
302
|
const chainId = networkChainIdMap[this.network];
|
|
291
303
|
const protocols = await getOneInchProtocols(chainId);
|
|
@@ -298,8 +310,13 @@ export class Pool {
|
|
|
298
310
|
}&destReceiver=${
|
|
299
311
|
this.address
|
|
300
312
|
}&slippage=${slippage.toString()}&disableEstimate=true${protocols}`;
|
|
301
|
-
|
|
302
|
-
|
|
313
|
+
try {
|
|
314
|
+
const response = await axios.get(apiUrl);
|
|
315
|
+
swapTxData = response.data.tx.data;
|
|
316
|
+
} catch (e) {
|
|
317
|
+
throw new ApiError("Swap api request of 1inch failed");
|
|
318
|
+
}
|
|
319
|
+
|
|
303
320
|
break;
|
|
304
321
|
case Dapp.BALANCER:
|
|
305
322
|
swapTxData = await this.utils.getBalancerSwapTx(
|
|
@@ -483,7 +500,10 @@ export class Pool {
|
|
|
483
500
|
]);
|
|
484
501
|
break;
|
|
485
502
|
case Dapp.VELODROME:
|
|
486
|
-
stakeTxData = getVelodromeStakeTxData(amount);
|
|
503
|
+
stakeTxData = getVelodromeStakeTxData(amount, false);
|
|
504
|
+
break;
|
|
505
|
+
case Dapp.VELODROMEV2:
|
|
506
|
+
stakeTxData = getVelodromeStakeTxData(amount, true);
|
|
487
507
|
break;
|
|
488
508
|
default:
|
|
489
509
|
throw new Error("dapp not supported");
|
|
@@ -526,7 +546,7 @@ export class Pool {
|
|
|
526
546
|
}
|
|
527
547
|
|
|
528
548
|
/**
|
|
529
|
-
* Unstake liquidity pool tokens from gauge
|
|
549
|
+
* Unstake liquidity pool tokens from Velodrome or Balancer gauge
|
|
530
550
|
* @param {string} gauge Gauge contract address
|
|
531
551
|
* @param {BigNumber | string} amount Amount of liquidity pool tokens
|
|
532
552
|
* @param {any} options Transaction options
|
|
@@ -1051,7 +1071,11 @@ export class Pool {
|
|
|
1051
1071
|
break;
|
|
1052
1072
|
case Dapp.VELODROME:
|
|
1053
1073
|
contractAddress = tokenId;
|
|
1054
|
-
txData = getVelodromeClaimTxData(this, tokenId);
|
|
1074
|
+
txData = getVelodromeClaimTxData(this, tokenId, false);
|
|
1075
|
+
break;
|
|
1076
|
+
case Dapp.VELODROMEV2:
|
|
1077
|
+
contractAddress = tokenId;
|
|
1078
|
+
txData = getVelodromeClaimTxData(this, tokenId, true);
|
|
1055
1079
|
break;
|
|
1056
1080
|
default:
|
|
1057
1081
|
throw new Error("dapp not supported");
|
|
@@ -1162,6 +1186,69 @@ export class Pool {
|
|
|
1162
1186
|
return tx;
|
|
1163
1187
|
}
|
|
1164
1188
|
|
|
1189
|
+
/**
|
|
1190
|
+
* Add liquidity to Velodrome V2 pool
|
|
1191
|
+
* @param {string} assetA First asset
|
|
1192
|
+
* @param {string} assetB Second asset
|
|
1193
|
+
* @param {BigNumber | string} amountA Amount first asset
|
|
1194
|
+
* @param {BigNumber | string} amountB Amount second asset
|
|
1195
|
+
* @param { boolean } isStable Is stable pool
|
|
1196
|
+
* @param {any} options Transaction options
|
|
1197
|
+
* @returns {Promise<any>} Transaction
|
|
1198
|
+
*/
|
|
1199
|
+
async addLiquidityVelodromeV2(
|
|
1200
|
+
assetA: string,
|
|
1201
|
+
assetB: string,
|
|
1202
|
+
amountA: BigNumber | string,
|
|
1203
|
+
amountB: BigNumber | string,
|
|
1204
|
+
isStable: boolean,
|
|
1205
|
+
options: any = null
|
|
1206
|
+
): Promise<any> {
|
|
1207
|
+
const tx = await this.poolLogic.execTransaction(
|
|
1208
|
+
routerAddress[this.network][Dapp.VELODROMEV2],
|
|
1209
|
+
await getVelodromeAddLiquidityTxData(
|
|
1210
|
+
this,
|
|
1211
|
+
assetA,
|
|
1212
|
+
assetB,
|
|
1213
|
+
amountA,
|
|
1214
|
+
amountB,
|
|
1215
|
+
isStable
|
|
1216
|
+
),
|
|
1217
|
+
options
|
|
1218
|
+
);
|
|
1219
|
+
return tx;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Remove liquidity from Velodrome V2 pool
|
|
1224
|
+
* @param {string} assetA First asset
|
|
1225
|
+
* @param {string} assetB Second asset
|
|
1226
|
+
* @param {BigNumber | string} amount Amount of LP tokens
|
|
1227
|
+
* @param { boolean } isStable Is stable pool
|
|
1228
|
+
* @param {any} options Transaction options
|
|
1229
|
+
* @returns {Promise<any>} Transaction
|
|
1230
|
+
*/
|
|
1231
|
+
async removeLiquidityVelodromeV2(
|
|
1232
|
+
assetA: string,
|
|
1233
|
+
assetB: string,
|
|
1234
|
+
amount: BigNumber | string,
|
|
1235
|
+
isStable: boolean,
|
|
1236
|
+
options: any = null
|
|
1237
|
+
): Promise<any> {
|
|
1238
|
+
const tx = await this.poolLogic.execTransaction(
|
|
1239
|
+
routerAddress[this.network][Dapp.VELODROMEV2],
|
|
1240
|
+
await getVelodromeRemoveLiquidityTxData(
|
|
1241
|
+
this,
|
|
1242
|
+
assetA,
|
|
1243
|
+
assetB,
|
|
1244
|
+
amount,
|
|
1245
|
+
isStable
|
|
1246
|
+
),
|
|
1247
|
+
options
|
|
1248
|
+
);
|
|
1249
|
+
return tx;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1165
1252
|
/**
|
|
1166
1253
|
* Trade options on lyra
|
|
1167
1254
|
* @param {LyraOptionMarket} market Underlying market e.g. eth
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// see https://stackoverflow.com/a/41102306
|
|
2
|
+
const CAN_SET_PROTOTYPE = "setPrototypeOf" in Object;
|
|
3
|
+
|
|
4
|
+
export class ApiError extends Error {
|
|
5
|
+
public constructor(message?: string) {
|
|
6
|
+
super(message ?? "Api request failed");
|
|
7
|
+
this.name = this.constructor.name;
|
|
8
|
+
if (CAN_SET_PROTOTYPE) Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,31 +1,44 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { BigNumber, ethers } from "ethers";
|
|
3
|
-
import
|
|
3
|
+
import IVelodromeGaugeV1 from "../../abi/IVelodromeGauge.json";
|
|
4
|
+
import IVelodromeGaugeV2 from "../../abi/IVelodromeGaugeV2.json";
|
|
4
5
|
import { Pool } from "../../entities";
|
|
5
|
-
import { Transaction } from "../../types";
|
|
6
6
|
import { call } from "../../utils/contract";
|
|
7
|
-
const
|
|
7
|
+
const iVelodromeGaugeV1 = new ethers.utils.Interface(IVelodromeGaugeV1.abi);
|
|
8
|
+
const iVelodromeGaugeV2 = new ethers.utils.Interface(IVelodromeGaugeV2.abi);
|
|
8
9
|
|
|
9
|
-
export function getVelodromeStakeTxData(
|
|
10
|
-
|
|
10
|
+
export function getVelodromeStakeTxData(
|
|
11
|
+
amount: BigNumber | string,
|
|
12
|
+
v2: boolean
|
|
13
|
+
): any {
|
|
14
|
+
const depositParams: [string, unknown[]] = v2
|
|
15
|
+
? ["deposit(uint256)", [amount]]
|
|
16
|
+
: ["deposit", [amount, 0]];
|
|
17
|
+
const iVelodromeGauge = v2 ? iVelodromeGaugeV2 : iVelodromeGaugeV1;
|
|
18
|
+
return iVelodromeGauge.encodeFunctionData(...depositParams);
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
export async function getVelodromeClaimTxData(
|
|
14
22
|
pool: Pool,
|
|
15
|
-
gauge: string
|
|
23
|
+
gauge: string,
|
|
24
|
+
v2: boolean
|
|
16
25
|
): Promise<any> {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
[
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
if (v2) {
|
|
27
|
+
return iVelodromeGaugeV2.encodeFunctionData("getReward", [pool.address]);
|
|
28
|
+
} else {
|
|
29
|
+
const rewardAssetCount = await call(pool.signer, IVelodromeGaugeV1.abi, [
|
|
30
|
+
gauge,
|
|
31
|
+
"rewardsListLength",
|
|
32
|
+
[]
|
|
33
|
+
]);
|
|
34
|
+
const rewardAssets = await Promise.all(
|
|
35
|
+
Array.from(Array(rewardAssetCount.toNumber()).keys()).map(e =>
|
|
36
|
+
call(pool.signer, IVelodromeGaugeV1.abi, [gauge, "rewards", [e]])
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
return iVelodromeGaugeV1.encodeFunctionData("getReward", [
|
|
40
|
+
pool.address,
|
|
41
|
+
rewardAssets
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
31
44
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { BigNumber } from "ethers";
|
|
3
|
+
import { Network } from "../../types";
|
|
4
|
+
import { ApiError } from "../../errors";
|
|
5
|
+
|
|
6
|
+
// slippage of 0x is different from that of 1Inch
|
|
7
|
+
// in 0x, e.g. 0.03 for 3% slippage allowed
|
|
8
|
+
// 1inch slippage 0.5% represented by 0.5
|
|
9
|
+
// 0x slippage 0.5% represented by 0.005
|
|
10
|
+
const getZeroExSlippage = (slippage: number): number => {
|
|
11
|
+
return Number(slippage) / 100;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const getZeroExTradeTxData = async (
|
|
15
|
+
network: Network,
|
|
16
|
+
assetFrom: string,
|
|
17
|
+
assetTo: string,
|
|
18
|
+
amountIn: BigNumber | string,
|
|
19
|
+
slippage = 0.5,
|
|
20
|
+
takerAddress: string
|
|
21
|
+
): Promise<string> => {
|
|
22
|
+
if (!process.env.ZEROEX_API_KEY)
|
|
23
|
+
throw new Error("ZEROEX_API_KEY not configured in .env file");
|
|
24
|
+
try {
|
|
25
|
+
const slippagePercentage = getZeroExSlippage(slippage);
|
|
26
|
+
const params = {
|
|
27
|
+
buyToken: assetTo,
|
|
28
|
+
sellToken: assetFrom,
|
|
29
|
+
sellAmount: amountIn.toString(),
|
|
30
|
+
// necessary to skip quote validation is that in which the takerAddress refers to a smart contract
|
|
31
|
+
skipValidation: true,
|
|
32
|
+
// Used to enable RFQ-T liquidity
|
|
33
|
+
intentOnFilling: true,
|
|
34
|
+
takerAddress,
|
|
35
|
+
slippagePercentage
|
|
36
|
+
// excludedSourcesParam
|
|
37
|
+
};
|
|
38
|
+
const response = await axios.get(
|
|
39
|
+
`https://${network}.api.0x.org/swap/v1/quote`,
|
|
40
|
+
{
|
|
41
|
+
params,
|
|
42
|
+
headers: {
|
|
43
|
+
"0x-api-key": process.env.ZEROEX_API_KEY
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return response.data.data;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
throw new ApiError("Swap api request of 0x failed");
|
|
51
|
+
}
|
|
52
|
+
};
|
package/src/test/txOptions.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Network } from "../types";
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
6
|
export const getTxOptions = async (network: Network): Promise<any> => {
|
|
7
7
|
if (network === Network.POLYGON) {
|
|
8
|
-
const result = await axios("https://gasstation
|
|
8
|
+
const result = await axios("https://gasstation.polygon.technology/v2");
|
|
9
9
|
return {
|
|
10
10
|
gasLimit: "3000000",
|
|
11
11
|
maxPriorityFeePerGas: new BigNumber(result.data.fast.maxPriorityFee)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
import { Dhedge, Pool } from "..";
|
|
4
|
+
import { routerAddress } from "../config";
|
|
5
|
+
import { Dapp, Network } from "../types";
|
|
6
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
7
|
+
import { allowanceDelta, balanceDelta } from "./utils/token";
|
|
8
|
+
|
|
9
|
+
import { wallet } from "./wallet";
|
|
10
|
+
|
|
11
|
+
const USDC_SUSD_Lp = "0x6d5BA400640226e24b50214d2bBb3D4Db8e6e15a";
|
|
12
|
+
const USDC_SUSD_Gauge = "0x55a272304456355242f6690863b5c8d5c512ff71";
|
|
13
|
+
const network = Network.OPTIMISM;
|
|
14
|
+
const SUSD = CONTRACT_ADDRESS[network].SUSD;
|
|
15
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
16
|
+
|
|
17
|
+
let dhedge: Dhedge;
|
|
18
|
+
let pool: Pool;
|
|
19
|
+
jest.setTimeout(100000);
|
|
20
|
+
|
|
21
|
+
describe("pool", () => {
|
|
22
|
+
beforeAll(async () => {
|
|
23
|
+
dhedge = new Dhedge(wallet, network);
|
|
24
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("approves unlimited sUSD and USDC on for Velodrome", async () => {
|
|
28
|
+
await pool.approve(Dapp.VELODROMEV2, SUSD, MAX_AMOUNT);
|
|
29
|
+
await pool.approve(Dapp.VELODROMEV2, USDC, MAX_AMOUNT);
|
|
30
|
+
const UsdcAllowanceDelta = await allowanceDelta(
|
|
31
|
+
pool.address,
|
|
32
|
+
USDC,
|
|
33
|
+
routerAddress[network].velodromeV2!,
|
|
34
|
+
pool.signer
|
|
35
|
+
);
|
|
36
|
+
await expect(UsdcAllowanceDelta.gt(0));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("adds USDC and SUSD to a Velodrome stable pool", async () => {
|
|
40
|
+
await pool.addLiquidityVelodromeV2(
|
|
41
|
+
USDC,
|
|
42
|
+
SUSD,
|
|
43
|
+
(5 * 1e6).toString(),
|
|
44
|
+
(5 * 1e18).toString(),
|
|
45
|
+
true
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const lpTokenDelta = await balanceDelta(
|
|
49
|
+
pool.address,
|
|
50
|
+
USDC_SUSD_Lp,
|
|
51
|
+
pool.signer
|
|
52
|
+
);
|
|
53
|
+
expect(lpTokenDelta.gt(0));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should stake USDC-sUSD LP in a gauge", async () => {
|
|
57
|
+
const balance = await dhedge.utils.getBalance(USDC_SUSD_Lp, pool.address);
|
|
58
|
+
await pool.approveSpender(USDC_SUSD_Gauge, USDC_SUSD_Lp, MAX_AMOUNT);
|
|
59
|
+
await pool.stakeInGauge(Dapp.VELODROMEV2, USDC_SUSD_Gauge, balance);
|
|
60
|
+
const gaugeBalance = await balanceDelta(
|
|
61
|
+
pool.address,
|
|
62
|
+
USDC_SUSD_Lp,
|
|
63
|
+
pool.signer
|
|
64
|
+
);
|
|
65
|
+
expect(gaugeBalance.gt(0));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should claim rewards from Gauge", async () => {
|
|
69
|
+
const tx = await pool.claimFees(Dapp.VELODROMEV2, USDC_SUSD_Gauge);
|
|
70
|
+
expect(tx).not.toBe(null);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should unStake USDC-sUSD LP from a gauge", async () => {
|
|
74
|
+
const gaugeBalance = await dhedge.utils.getBalance(
|
|
75
|
+
USDC_SUSD_Gauge,
|
|
76
|
+
pool.address
|
|
77
|
+
);
|
|
78
|
+
await pool.unstakeFromGauge(USDC_SUSD_Gauge, gaugeBalance);
|
|
79
|
+
const lpTokenDelta = await balanceDelta(
|
|
80
|
+
pool.address,
|
|
81
|
+
USDC_SUSD_Lp,
|
|
82
|
+
pool.signer
|
|
83
|
+
);
|
|
84
|
+
expect(lpTokenDelta.gt(0));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("approves unlimited wETH/stwETH LP for Velodrome", async () => {
|
|
88
|
+
await pool.approve(Dapp.VELODROMEV2, USDC_SUSD_Lp, MAX_AMOUNT);
|
|
89
|
+
const lpAllowanceDelta = await allowanceDelta(
|
|
90
|
+
pool.address,
|
|
91
|
+
USDC_SUSD_Lp,
|
|
92
|
+
routerAddress[network].velodrome!,
|
|
93
|
+
pool.signer
|
|
94
|
+
);
|
|
95
|
+
expect(lpAllowanceDelta.gt(0));
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should remove all liquidity from an existing pool ", async () => {
|
|
99
|
+
const balance = await dhedge.utils.getBalance(USDC_SUSD_Lp, pool.address);
|
|
100
|
+
await pool.removeLiquidityVelodromeV2(USDC, SUSD, balance, true);
|
|
101
|
+
const usdcBalanceDelta = await balanceDelta(
|
|
102
|
+
pool.address,
|
|
103
|
+
USDC,
|
|
104
|
+
pool.signer
|
|
105
|
+
);
|
|
106
|
+
const susdBalanceDelta = await balanceDelta(
|
|
107
|
+
pool.address,
|
|
108
|
+
SUSD,
|
|
109
|
+
pool.signer
|
|
110
|
+
);
|
|
111
|
+
expect(usdcBalanceDelta.gt(0));
|
|
112
|
+
expect(susdBalanceDelta.gt(0));
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { Dhedge, Pool } from "..";
|
|
3
|
+
import { routerAddress } from "../config";
|
|
4
|
+
import { Dapp, Network } from "../types";
|
|
5
|
+
import { CONTRACT_ADDRESS, MAX_AMOUNT, TEST_POOL } from "./constants";
|
|
6
|
+
import { allowanceDelta, balanceDelta } from "./utils/token";
|
|
7
|
+
|
|
8
|
+
import { wallet } from "./wallet";
|
|
9
|
+
|
|
10
|
+
//const network = Network.OPTIMISM;
|
|
11
|
+
const network = Network.POLYGON;
|
|
12
|
+
// const network = Network.ARBITRUM;
|
|
13
|
+
const USDC = CONTRACT_ADDRESS[network].USDC;
|
|
14
|
+
const WETH = CONTRACT_ADDRESS[network].WETH;
|
|
15
|
+
|
|
16
|
+
let dhedge: Dhedge;
|
|
17
|
+
let pool: Pool;
|
|
18
|
+
jest.setTimeout(100000);
|
|
19
|
+
|
|
20
|
+
describe("pool", () => {
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
dhedge = new Dhedge(wallet, network);
|
|
23
|
+
pool = await dhedge.loadPool(TEST_POOL[network]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("approves unlimited USDC on 0x", async () => {
|
|
27
|
+
await pool.approve(Dapp.ZEROEX, USDC, MAX_AMOUNT);
|
|
28
|
+
const usdcAllowanceDelta = await allowanceDelta(
|
|
29
|
+
pool.address,
|
|
30
|
+
USDC,
|
|
31
|
+
routerAddress[network]["0x"]!,
|
|
32
|
+
pool.signer
|
|
33
|
+
);
|
|
34
|
+
await expect(usdcAllowanceDelta.gt(0));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("trades 2 USDC into WETH on 0x", async () => {
|
|
38
|
+
await pool.trade(Dapp.ZEROEX, USDC, WETH, "2000000", 0.5);
|
|
39
|
+
const wethBalanceDelta = await balanceDelta(
|
|
40
|
+
pool.address,
|
|
41
|
+
WETH,
|
|
42
|
+
pool.signer
|
|
43
|
+
);
|
|
44
|
+
expect(wethBalanceDelta.gt(0));
|
|
45
|
+
});
|
|
46
|
+
});
|