@dhedge/v2-sdk 1.5.3 → 1.5.4

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.
@@ -43,6 +43,14 @@ import { getUniswapV3SwapTxData } from "../services/uniswap/V3Trade";
43
43
  import { getEasySwapperTxData } from "../services/toros/easySwapper";
44
44
  import { getOneInchProtocols } from "../services/oneInch/protocols";
45
45
  import { getAaveV3ClaimTxData } from "../services/aave/incentives";
46
+ import {
47
+ getVelodromeAddLiquidityTxData,
48
+ getVelodromeRemoveLiquidityTxData
49
+ } from "../services/velodrome/liquidity";
50
+ import {
51
+ getVelodromeClaimTxData,
52
+ getVelodromeStakeTxData
53
+ } from "../services/velodrome/staking";
46
54
 
47
55
  export class Pool {
48
56
  public readonly poolLogic: Contract;
@@ -430,20 +438,34 @@ export class Pool {
430
438
 
431
439
  /**
432
440
  * Stake liquidity pool tokens in gauge contract
441
+ * @param {Dapp} dapp Platform like Balancer or Velodrome
433
442
  * @param {string} gauge Gauge contract address
434
443
  * @param {BigNumber | string} amount Amount of liquidity pool tokens
435
444
  * @param {any} options Transaction options
436
445
  * @returns {Promise<any>} Transaction
437
446
  */
438
447
  async stakeInGauge(
448
+ dapp: Dapp,
439
449
  gauge: string,
440
450
  amount: BigNumber | string,
441
451
  options: any = null
442
452
  ): Promise<any> {
443
- const rewardsGauge = new ethers.utils.Interface(IBalancerRewardsGauge.abi);
444
- const stakeTxData = rewardsGauge.encodeFunctionData("deposit(uint256)", [
445
- amount
446
- ]);
453
+ let stakeTxData;
454
+ switch (dapp) {
455
+ case Dapp.BALANCER:
456
+ const rewardsGauge = new ethers.utils.Interface(
457
+ IBalancerRewardsGauge.abi
458
+ );
459
+ stakeTxData = rewardsGauge.encodeFunctionData("deposit(uint256)", [
460
+ amount
461
+ ]);
462
+ break;
463
+ case Dapp.VELODROME:
464
+ stakeTxData = getVelodromeStakeTxData(amount);
465
+ break;
466
+ default:
467
+ throw new Error("dapp not supported");
468
+ }
447
469
  const tx = await this.poolLogic.execTransaction(
448
470
  gauge,
449
471
  stakeTxData,
@@ -1020,21 +1042,29 @@ export class Pool {
1020
1042
  ): Promise<any> {
1021
1043
  let txData;
1022
1044
  let contractAddress;
1023
- if (dapp === Dapp.UNISWAPV3) {
1024
- contractAddress = nonfungiblePositionManagerAddress[this.network];
1025
- const iNonfungiblePositionManager = new ethers.utils.Interface(
1026
- INonfungiblePositionManager.abi
1027
- );
1028
- txData = iNonfungiblePositionManager.encodeFunctionData(
1029
- Transaction.COLLECT,
1030
- [[tokenId, this.address, MaxUint128, MaxUint128]]
1031
- );
1032
- } else if (dapp === Dapp.ARRAKIS || dapp === Dapp.BALANCER) {
1033
- contractAddress = tokenId;
1034
- const abi = new ethers.utils.Interface(ILiquidityGaugeV4.abi);
1035
- txData = abi.encodeFunctionData("claim_rewards()", []);
1036
- } else {
1037
- throw new Error("dapp not supported");
1045
+ switch (dapp) {
1046
+ case Dapp.UNISWAPV3:
1047
+ contractAddress = nonfungiblePositionManagerAddress[this.network];
1048
+ const iNonfungiblePositionManager = new ethers.utils.Interface(
1049
+ INonfungiblePositionManager.abi
1050
+ );
1051
+ txData = iNonfungiblePositionManager.encodeFunctionData(
1052
+ Transaction.COLLECT,
1053
+ [[tokenId, this.address, MaxUint128, MaxUint128]]
1054
+ );
1055
+ break;
1056
+ case Dapp.ARRAKIS:
1057
+ case Dapp.BALANCER:
1058
+ contractAddress = tokenId;
1059
+ const abi = new ethers.utils.Interface(ILiquidityGaugeV4.abi);
1060
+ txData = abi.encodeFunctionData("claim_rewards()", []);
1061
+ break;
1062
+ case Dapp.VELODROME:
1063
+ contractAddress = tokenId;
1064
+ txData = getVelodromeClaimTxData(this, tokenId);
1065
+ break;
1066
+ default:
1067
+ throw new Error("dapp not supported");
1038
1068
  }
1039
1069
  const tx = await this.poolLogic.execTransaction(
1040
1070
  contractAddress,
@@ -1078,4 +1108,61 @@ export class Pool {
1078
1108
  );
1079
1109
  return tx;
1080
1110
  }
1111
+
1112
+ /**
1113
+ * Add liquidity to Velodrome pool
1114
+ * @param {string} assetA First asset
1115
+ * @param {string} assetB Second asset
1116
+ * @param {BigNumber | string} amountA Amount first asset
1117
+ * @param {BigNumber | string} amountB Amount second asset
1118
+ * @param { boolean } isStable Is stable pool
1119
+ * @param {any} options Transaction options
1120
+ * @returns {Promise<any>} Transaction
1121
+ */
1122
+ async addLiquidityVelodrome(
1123
+ assetA: string,
1124
+ assetB: string,
1125
+ amountA: BigNumber | string,
1126
+ amountB: BigNumber | string,
1127
+ isStable: boolean,
1128
+ options: any = null
1129
+ ): Promise<any> {
1130
+ const tx = await this.poolLogic.execTransaction(
1131
+ routerAddress[this.network][Dapp.VELODROME],
1132
+ getVelodromeAddLiquidityTxData(
1133
+ this,
1134
+ assetA,
1135
+ assetB,
1136
+ amountA,
1137
+ amountB,
1138
+ isStable
1139
+ ),
1140
+ options
1141
+ );
1142
+ return tx;
1143
+ }
1144
+
1145
+ /**
1146
+ * Remove liquidity from Velodrome pool
1147
+ * @param {string} assetA First asset
1148
+ * @param {string} assetB Second asset
1149
+ * @param {BigNumber | string} amount Amount of LP tokens
1150
+ * @param { boolean } isStable Is stable pool
1151
+ * @param {any} options Transaction options
1152
+ * @returns {Promise<any>} Transaction
1153
+ */
1154
+ async removeLiquidityVelodrome(
1155
+ assetA: string,
1156
+ assetB: string,
1157
+ amount: BigNumber | string,
1158
+ isStable: boolean,
1159
+ options: any = null
1160
+ ): Promise<any> {
1161
+ const tx = await this.poolLogic.execTransaction(
1162
+ routerAddress[this.network][Dapp.VELODROME],
1163
+ getVelodromeRemoveLiquidityTxData(this, assetA, assetB, amount, isStable),
1164
+ options
1165
+ );
1166
+ return tx;
1167
+ }
1081
1168
  }
@@ -0,0 +1,48 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { BigNumber, ethers } from "ethers";
3
+ import IVelodromeRouter from "../../abi/IVeldodromeRouter.json";
4
+ import { deadline } from "../../config";
5
+ import { Pool } from "../../entities";
6
+ import { Transaction } from "../../types";
7
+
8
+ export function getVelodromeAddLiquidityTxData(
9
+ pool: Pool,
10
+ assetA: string,
11
+ assetB: string,
12
+ amountA: BigNumber | string,
13
+ amountB: BigNumber | string,
14
+ isStable: boolean
15
+ ): any {
16
+ const iVelodromeRouter = new ethers.utils.Interface(IVelodromeRouter.abi);
17
+ return iVelodromeRouter.encodeFunctionData(Transaction.ADD_LIQUIDITY, [
18
+ assetA,
19
+ assetB,
20
+ isStable,
21
+ amountA,
22
+ amountB,
23
+ "0",
24
+ "0",
25
+ pool.address,
26
+ deadline
27
+ ]);
28
+ }
29
+
30
+ export function getVelodromeRemoveLiquidityTxData(
31
+ pool: Pool,
32
+ assetA: string,
33
+ assetB: string,
34
+ amount: BigNumber | string,
35
+ isStable: boolean
36
+ ): any {
37
+ const iVelodromeRouter = new ethers.utils.Interface(IVelodromeRouter.abi);
38
+ return iVelodromeRouter.encodeFunctionData(Transaction.REMOVE_LIQUIDITY, [
39
+ assetA,
40
+ assetB,
41
+ isStable,
42
+ amount,
43
+ "0",
44
+ "0",
45
+ pool.address,
46
+ deadline
47
+ ]);
48
+ }
@@ -0,0 +1,31 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { BigNumber, ethers } from "ethers";
3
+ import IVelodromeGauge from "../../abi/IVelodromeGauge.json";
4
+ import { Pool } from "../../entities";
5
+ import { Transaction } from "../../types";
6
+ import { call } from "../../utils/contract";
7
+ const iVelodromeGauge = new ethers.utils.Interface(IVelodromeGauge.abi);
8
+
9
+ export function getVelodromeStakeTxData(amount: BigNumber | string): any {
10
+ return iVelodromeGauge.encodeFunctionData(Transaction.DEPOSIT, [amount, "0"]);
11
+ }
12
+
13
+ export async function getVelodromeClaimTxData(
14
+ pool: Pool,
15
+ gauge: string
16
+ ): Promise<any> {
17
+ const rewardAssetCount = await call(pool.signer, IVelodromeGauge.abi, [
18
+ gauge,
19
+ "rewardsListLength",
20
+ []
21
+ ]);
22
+ const rewardAssets = await Promise.all(
23
+ Array.from(Array(rewardAssetCount.toNumber()).keys()).map(e =>
24
+ call(pool.signer, IVelodromeGauge.abi, [gauge, "rewards", [e]])
25
+ )
26
+ );
27
+ return iVelodromeGauge.encodeFunctionData("getReward", [
28
+ pool.address,
29
+ rewardAssets
30
+ ]);
31
+ }
@@ -26,5 +26,7 @@ export const DAI = "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1";
26
26
  export const USDy = "0x1ec50880101022c11530a069690f5446d1464592";
27
27
  export const WBTC = "0x68f180fcCe6836688e9084f035309E29Bf0A2095";
28
28
  export const OP = "4200000000000000000000000000000000000042";
29
+ export const WSTETH = "0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb";
30
+ export const VEL = "0x3c8B650257cFb5f272f799F5e2b4e65093a11a05";
29
31
 
30
32
  export const TEST_POOL = "TEST_POOL";
@@ -0,0 +1,141 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Dhedge, ethers } from "..";
3
+ import { Dapp, Network } from "../types";
4
+ import { TEST_POOL, WETH, WSTETH } from "./constants";
5
+ import { getTxOptions } from "./txOptions";
6
+
7
+ import { wallet } from "./wallet";
8
+
9
+ const wETHwstETHLp = "0xBf205335De602ac38244F112d712ab04CB59A498";
10
+ const wETHwstETHGauge = "0x131Ae347E654248671Afc885F0767cB605C065d7";
11
+
12
+ let dhedge: Dhedge;
13
+ let options: any;
14
+ jest.setTimeout(100000);
15
+
16
+ describe("pool", () => {
17
+ beforeAll(async () => {
18
+ dhedge = new Dhedge(wallet, Network.OPTIMISM);
19
+ options = await getTxOptions(Network.OPTIMISM);
20
+ });
21
+
22
+ it("approves unlimited WETH on for Velodrome", async () => {
23
+ let result;
24
+ const pool = await dhedge.loadPool(TEST_POOL);
25
+ try {
26
+ result = await pool.approve(
27
+ Dapp.VELODROME,
28
+ WSTETH,
29
+ ethers.constants.MaxInt256,
30
+ options
31
+ );
32
+ console.log(result);
33
+ } catch (e) {
34
+ console.log(e);
35
+ }
36
+ expect(result).not.toBe(null);
37
+ });
38
+
39
+ it("adds WETH and wstETH to a Velodrome stable pool", async () => {
40
+ const pool = await dhedge.loadPool(TEST_POOL);
41
+ const wethBalance = await dhedge.utils.getBalance(WETH, pool.address);
42
+ const stwethBalance = await dhedge.utils.getBalance(WSTETH, pool.address);
43
+
44
+ const result = await pool.addLiquidityVelodrome(
45
+ WETH,
46
+ WSTETH,
47
+ wethBalance,
48
+ stwethBalance,
49
+ true,
50
+ options
51
+ );
52
+
53
+ result.wait(1);
54
+ const lpBalance = await dhedge.utils.getBalance(wETHwstETHLp, pool.address);
55
+ expect(lpBalance.gt(0));
56
+ });
57
+
58
+ it("should stake wETH/wStETH LP in a gauge", async () => {
59
+ const pool = await dhedge.loadPool(TEST_POOL);
60
+ const balance = await dhedge.utils.getBalance(wETHwstETHLp, pool.address);
61
+ const result = await pool.stakeInGauge(
62
+ Dapp.VELODROME,
63
+ wETHwstETHGauge,
64
+ balance,
65
+ options
66
+ );
67
+ result.wait(1);
68
+ const gaugeBalance = await dhedge.utils.getBalance(
69
+ wETHwstETHGauge,
70
+ pool.address
71
+ );
72
+ expect(gaugeBalance.gt(0));
73
+ });
74
+
75
+ it("should claim rewards from Gauge", async () => {
76
+ const pool = await dhedge.loadPool(TEST_POOL);
77
+ const result = await pool.claimFees(
78
+ Dapp.VELODROME,
79
+ wETHwstETHGauge,
80
+ options
81
+ );
82
+ result.wait(1);
83
+ const velBalance = await dhedge.utils.getBalance(VEL, pool.address);
84
+ expect(velBalance.gt(0));
85
+ });
86
+
87
+ it("should unStake wETH/wStETH LP from a gauge", async () => {
88
+ const pool = await dhedge.loadPool(TEST_POOL);
89
+ const gaugeBalance = await dhedge.utils.getBalance(
90
+ wETHwstETHGauge,
91
+ pool.address
92
+ );
93
+ const result = await pool.unstakeFromGauge(
94
+ wETHwstETHGauge,
95
+ gaugeBalance,
96
+ options
97
+ );
98
+ result.wait(1);
99
+ const lpBalance = await dhedge.utils.getBalance(wETHwstETHLp, pool.address);
100
+ expect(lpBalance.gt(0));
101
+ const gaugeBalanceAfter = await dhedge.utils.getBalance(
102
+ wETHwstETHGauge,
103
+ pool.address
104
+ );
105
+ expect(gaugeBalanceAfter.eq(0));
106
+ });
107
+
108
+ it("approves unlimited wETH/stwETH LP for Velodrome", async () => {
109
+ let result;
110
+ const pool = await dhedge.loadPool(TEST_POOL);
111
+ try {
112
+ result = await pool.approve(
113
+ Dapp.VELODROME,
114
+ wETHwstETHLp,
115
+ ethers.constants.MaxInt256,
116
+ options
117
+ );
118
+ console.log(result);
119
+ } catch (e) {
120
+ console.log(e);
121
+ }
122
+ expect(result).not.toBe(null);
123
+ });
124
+
125
+ it("should remove all liquidity from an existing pool ", async () => {
126
+ const pool = await dhedge.loadPool(TEST_POOL);
127
+ const balance = await dhedge.utils.getBalance(wETHwstETHLp, pool.address);
128
+ const result = await pool.removeLiquidityVelodrome(
129
+ WETH,
130
+ WSTETH,
131
+ balance,
132
+ options
133
+ );
134
+ result.wait(1);
135
+ const balanceAfter = await dhedge.utils.getBalance(
136
+ wETHwstETHLp,
137
+ pool.address
138
+ );
139
+ expect(balanceAfter.eq(0));
140
+ });
141
+ });
package/src/types.ts CHANGED
@@ -15,7 +15,8 @@ export enum Dapp {
15
15
  SYNTHETIX = "synthetix",
16
16
  AAVEV3 = "aavev3",
17
17
  ARRAKIS = "arrakis",
18
- TOROS = "toros"
18
+ TOROS = "toros",
19
+ VELODROME = "velodrome"
19
20
  }
20
21
 
21
22
  export enum Transaction {