@dhedge/v2-sdk 2.1.6 → 2.1.8

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": "2.1.6",
3
+ "version": "2.1.8",
4
4
  "license": "MIT",
5
5
  "description": "🛠 An SDK for building applications on top of dHEDGE V2",
6
6
  "main": "dist/index.js",
package/src/config.ts CHANGED
@@ -35,7 +35,8 @@ export const routerAddress: AddressDappNetworkMap = {
35
35
  [Dapp.ARRAKIS]: "0xc73fb100a995b33f9fa181d420f4c8d74506df66",
36
36
  [Dapp.TOROS]: "0x45b90480D6F643dE2f128db091A357C3c90399f2",
37
37
  [Dapp.ODOS]: "0x0D05a7D3448512B78fa8A9e46c4872C88C4a0D05",
38
- [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5"
38
+ [Dapp.KYBERSWAP]: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5",
39
+ [Dapp.COWSWAP]: "0x893223Be4e941fAA8A8DB93D0C097fCac37801ce"
39
40
  },
40
41
  [Network.OPTIMISM]: {
41
42
  [Dapp.UNISWAPV3]: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
@@ -88,6 +89,10 @@ export const routerAddress: AddressDappNetworkMap = {
88
89
  }
89
90
  };
90
91
 
92
+ export const gpv2SettlementAddress: Partial<Record<Network, string>> = {
93
+ [Network.POLYGON]: "0x9008D19f58AAbD9eD0D60971565AA8510560ab41"
94
+ };
95
+
91
96
  export const dappFactoryAddress: AddressDappNetworkMap = {
92
97
  [Network.POLYGON]: {
93
98
  [Dapp.SUSHISWAP]: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
@@ -18,6 +18,7 @@ import {
18
18
  MaxUint128,
19
19
  nonfungiblePositionManagerAddress,
20
20
  routerAddress,
21
+ gpv2SettlementAddress,
21
22
  stakingAddress,
22
23
  SYNTHETIX_TRACKING_CODE,
23
24
  limitOrderAddress
@@ -69,7 +70,7 @@ import {
69
70
  getExitVestTxData,
70
71
  getRewardsTxDta
71
72
  } from "../services/ramses/vesting";
72
- import { getPoolTxOrGasEstimate } from "../utils/contract";
73
+ import { getPoolTxOrGasEstimate, isSdkOptionsBoolean } from "../utils/contract";
73
74
  import {
74
75
  cancelOrderViaFlatMoney,
75
76
  mintUnitViaFlatMoney,
@@ -96,14 +97,18 @@ import {
96
97
  hasActiveTorosLimitOrder
97
98
  } from "../services/toros/limitOrder";
98
99
  import { getKyberSwapTxData } from "../services/kyberSwap";
100
+ import { getCowSwapTxData } from "../services/cowSwap";
99
101
  import {
100
102
  getClosePositionHyperliquidTxData,
101
103
  getDepositHyperliquidTxData,
102
104
  getLimitOrderHyperliquidTxData,
103
- getPerpToSpotHyperliquidTxData,
105
+ getSendAssetHyperliquidTxData,
104
106
  getWithdrawSpotHyperliquidTxData
105
107
  } from "../services/hyperliquid";
106
- import { CORE_WRITER_ADDRESS } from "../services/hyperliquid/constants";
108
+ import {
109
+ CORE_WRITER_ADDRESS,
110
+ SPOT_DEX_ID
111
+ } from "../services/hyperliquid/constants";
107
112
 
108
113
  export class Pool {
109
114
  public readonly poolLogic: Contract;
@@ -471,6 +476,60 @@ export class Pool {
471
476
  slippage
472
477
  ));
473
478
  break;
479
+ case Dapp.COWSWAP: {
480
+ const cowSwapEstimateGas = isSdkOptionsBoolean(sdkOptions)
481
+ ? sdkOptions
482
+ : sdkOptions.estimateGas;
483
+ if (
484
+ cowSwapEstimateGas ||
485
+ (!isSdkOptionsBoolean(sdkOptions) && sdkOptions.onlyGetTxData)
486
+ ) {
487
+ throw new Error(
488
+ "CowSwap requires two sequential transactions (submit + preSign) and does not support estimateGas or onlyGetTxData"
489
+ );
490
+ }
491
+ const {
492
+ encodedTypedData,
493
+ preSignTxData,
494
+ minAmountOut: cowMinOut
495
+ } = await getCowSwapTxData(
496
+ this,
497
+ assetFrom,
498
+ assetTo,
499
+ amountIn,
500
+ slippage
501
+ );
502
+ // Tx 1: manager calls submit() directly on TypedStructuredDataValidator (not via pool.execTransaction)
503
+ const validatorContract = new Contract(
504
+ routerAddress[this.network][dapp] as string,
505
+ [
506
+ "function submit(address _poolLogic, uint8 _dataType, bytes memory _structuredData) external"
507
+ ],
508
+ this.signer
509
+ );
510
+ const submitTx = await validatorContract.submit(
511
+ this.address,
512
+ 1 /* COWSWAP_ORDER */,
513
+ encodedTypedData,
514
+ ...(options ? [options] : [])
515
+ );
516
+ const submitReceipt = await submitTx.wait(3);
517
+ if (submitReceipt.status === 0) {
518
+ return submitReceipt;
519
+ }
520
+
521
+ // Tx 2: pool.execTransaction → setPreSignature() on GPv2Settlement — guard checks stored digest, solvers execute
522
+ return getPoolTxOrGasEstimate(
523
+ this,
524
+ [
525
+ gpv2SettlementAddress[this.network],
526
+ preSignTxData,
527
+ options,
528
+ cowMinOut
529
+ ],
530
+ sdkOptions
531
+ );
532
+ }
474
533
  default:
475
534
  const iUniswapV2Router = new ethers.utils.Interface(
476
535
  IUniswapV2Router.abi
@@ -2220,7 +2279,38 @@ export class Pool {
2220
2279
  this,
2221
2280
  [
2222
2281
  CORE_WRITER_ADDRESS,
2223
- getPerpToSpotHyperliquidTxData(dexId, this.address, amount),
2282
+ getSendAssetHyperliquidTxData(dexId, SPOT_DEX_ID, this.address, amount),
2283
+ options
2284
+ ],
2285
+ sdkOptions
2286
+ );
2287
+ return tx;
2288
+ }
2289
+
2290
+ /** Move USDC from HyperCore spot wallet to a trading dex.
2291
+ *
2292
+ * @param {number} dexId Destination dex ID where USDC will be moved to
2293
+ * - 0: Core Perp dex (standard perps like BTC, ETH)
2294
+ * - 1: xyz HIP-3 dex (builder perps like TSLA, GOLD)
2295
+ * @param {BigNumber | string} amount USDC amount to transfer (6 decimals, e.g. "1000000" = 1 USDC)
2296
+ * @param {any} options Transaction options
2297
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2298
+ * @returns {Promise<any>} Transaction
2299
+ */
2300
+
2301
+ async spotToPerpHyperliquid(
2302
+ dexId: number,
2303
+ amount: BigNumber | string,
2304
+ options: any = null,
2305
+ sdkOptions: SDKOptions = {
2306
+ estimateGas: false
2307
+ }
2308
+ ): Promise<any> {
2309
+ const tx = await getPoolTxOrGasEstimate(
2310
+ this,
2311
+ [
2312
+ CORE_WRITER_ADDRESS,
2313
+ getSendAssetHyperliquidTxData(SPOT_DEX_ID, dexId, this.address, amount),
2224
2314
  options
2225
2315
  ],
2226
2316
  sdkOptions
@@ -0,0 +1,281 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import axios from "axios";
3
+ import { ethers } from "ethers";
4
+ import { ApiError } from "../..";
5
+ import { networkChainIdMap, gpv2SettlementAddress } from "../../config";
6
+ import { Pool } from "../../entities";
7
+ import BN from "bignumber.js";
8
+
9
+ export const KIND_SELL = ethers.utils.keccak256(
10
+ ethers.utils.toUtf8Bytes("sell")
11
+ );
12
+ export const KIND_BUY = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("buy"));
13
+ export const BALANCE_ERC20 = ethers.utils.keccak256(
14
+ ethers.utils.toUtf8Bytes("erc20")
15
+ );
16
+
17
+ // Matches CowSwapOrderTypeHashLib.ORDER_TYPE_HASH exactly:
18
+ // kind/sellTokenBalance/buyTokenBalance are "string" in the type string
19
+ // but encoded as bytes32 values in abi.encode — must replicate this exactly
20
+ const ORDER_TYPE_HASH = ethers.utils.keccak256(
21
+ ethers.utils.toUtf8Bytes(
22
+ "Order(" +
23
+ "address sellToken," +
24
+ "address buyToken," +
25
+ "address receiver," +
26
+ "uint256 sellAmount," +
27
+ "uint256 buyAmount," +
28
+ "uint32 validTo," +
29
+ "bytes32 appData," +
30
+ "uint256 feeAmount," +
31
+ "string kind," +
32
+ "bool partiallyFillable," +
33
+ "string sellTokenBalance," +
34
+ "string buyTokenBalance" +
35
+ ")"
36
+ )
37
+ );
38
+
39
+ // Matches CowSwapOrderTypeHashLib.EIP712_DOMAIN_TYPEHASH
40
+ const EIP712_DOMAIN_TYPEHASH = ethers.utils.keccak256(
41
+ ethers.utils.toUtf8Bytes(
42
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
43
+ )
44
+ );
45
+
46
+ const cowSwapApiNetworkMap: Record<string, string> = {
47
+ polygon: "polygon"
48
+ };
49
+
50
+ const GPv2Settlement_ABI = [
51
+ "function setPreSignature(bytes calldata orderUid, bool signed) external"
52
+ ];
53
+
54
+ // Replicates CowSwapOrderTypeHashLib.hashOrder
55
+ function hashOrder(order: {
56
+ sellToken: string;
57
+ buyToken: string;
58
+ receiver: string;
59
+ sellAmount: string;
60
+ buyAmount: string;
61
+ validTo: number;
62
+ appData: string;
63
+ feeAmount: string;
64
+ kind: string;
65
+ partiallyFillable: boolean;
66
+ sellTokenBalance: string;
67
+ buyTokenBalance: string;
68
+ }): string {
69
+ return ethers.utils.keccak256(
70
+ ethers.utils.defaultAbiCoder.encode(
71
+ [
72
+ "bytes32",
73
+ "address",
74
+ "address",
75
+ "address",
76
+ "uint256",
77
+ "uint256",
78
+ "uint32",
79
+ "bytes32",
80
+ "uint256",
81
+ "bytes32",
82
+ "bool",
83
+ "bytes32",
84
+ "bytes32"
85
+ ],
86
+ [
87
+ ORDER_TYPE_HASH,
88
+ order.sellToken,
89
+ order.buyToken,
90
+ order.receiver,
91
+ order.sellAmount,
92
+ order.buyAmount,
93
+ order.validTo,
94
+ order.appData,
95
+ order.feeAmount,
96
+ order.kind,
97
+ order.partiallyFillable,
98
+ order.sellTokenBalance,
99
+ order.buyTokenBalance
100
+ ]
101
+ )
102
+ );
103
+ }
104
+
105
+ // Replicates CowSwapOrderTypeHashLib.domainSeparator
106
+ function computeDomainSeparator(
107
+ name: string,
108
+ version: string,
109
+ chainId: number,
110
+ verifyingContract: string
111
+ ): string {
112
+ return ethers.utils.keccak256(
113
+ ethers.utils.defaultAbiCoder.encode(
114
+ ["bytes32", "bytes32", "bytes32", "uint256", "address"],
115
+ [
116
+ EIP712_DOMAIN_TYPEHASH,
117
+ ethers.utils.keccak256(ethers.utils.toUtf8Bytes(name)),
118
+ ethers.utils.keccak256(ethers.utils.toUtf8Bytes(version)),
119
+ chainId,
120
+ verifyingContract
121
+ ]
122
+ )
123
+ );
124
+ }
125
+
126
+ // Replicates CowSwapOrderTypeHashLib.getDigest
127
+ function computeOrderDigest(domainSep: string, orderHash: string): string {
128
+ return ethers.utils.keccak256(
129
+ ethers.utils.solidityPack(
130
+ ["bytes2", "bytes32", "bytes32"],
131
+ ["0x1901", domainSep, orderHash]
132
+ )
133
+ );
134
+ }
135
+
136
+ export async function getCowSwapTxData(
137
+ pool: Pool,
138
+ assetFrom: string,
139
+ assetTo: string,
140
+ amountIn: ethers.BigNumber | string,
141
+ slippage: number,
142
+ kind: "sell" | "buy" = "sell"
143
+ ): Promise<{
144
+ encodedTypedData: string;
145
+ preSignTxData: string;
146
+ minAmountOut: string;
147
+ }> {
148
+ const chainId = networkChainIdMap[pool.network];
149
+ const network = cowSwapApiNetworkMap[pool.network];
150
+ if (!network) {
151
+ throw new Error(`CowSwap is not supported on network: ${pool.network}`);
152
+ }
153
+
154
+ const gpv2Settlement = gpv2SettlementAddress[pool.network];
155
+ if (!gpv2Settlement) {
156
+ throw new Error(
157
+ `GPv2Settlement address not configured for network: ${pool.network}`
158
+ );
159
+ }
160
+
161
+ const baseUrl = `https://api.cow.fi/${network}/api/v1`;
162
+
163
+ // 1. Get quote
164
+ let quoteResponse: any;
165
+ try {
166
+ const quoteResult = await axios.post(`${baseUrl}/quote`, {
167
+ sellToken: assetFrom,
168
+ buyToken: assetTo,
169
+ ...(kind === "sell"
170
+ ? { sellAmountBeforeFee: amountIn.toString() }
171
+ : { buyAmountAfterFee: amountIn.toString() }),
172
+ from: pool.address,
173
+ receiver: pool.address,
174
+ kind,
175
+ signingScheme: "presign",
176
+ partiallyFillable: false,
177
+ sellTokenBalance: "erc20",
178
+ buyTokenBalance: "erc20"
179
+ });
180
+ quoteResponse = quoteResult.data;
181
+ } catch (e) {
182
+ throw new ApiError("CowSwap quote request failed");
183
+ }
184
+
185
+ const { sellAmount, buyAmount, validTo } = quoteResponse.quote;
186
+
187
+ const buyAmountWithSlippage = ethers.BigNumber.from(
188
+ new BN(buyAmount.toString())
189
+ .times(new BN(1).minus(new BN(slippage).div(100)))
190
+ .toFixed(0, BN.ROUND_DOWN)
191
+ );
192
+
193
+ const orderValues = {
194
+ sellToken: assetFrom,
195
+ buyToken: assetTo,
196
+ receiver: pool.address,
197
+ sellAmount,
198
+ buyAmount: buyAmountWithSlippage.toString(),
199
+ validTo,
200
+ appData: ethers.constants.HashZero,
201
+ feeAmount: "0",
202
+ kind: kind === "sell" ? KIND_SELL : KIND_BUY,
203
+ partiallyFillable: false,
204
+ sellTokenBalance: BALANCE_ERC20,
205
+ buyTokenBalance: BALANCE_ERC20
206
+ };
207
+
208
+ // 2. Compute digest matching CowSwapOrderTypeHashLib.getDigest exactly
209
+ const domainSep = computeDomainSeparator(
210
+ "Gnosis Protocol",
211
+ "v2",
212
+ chainId,
213
+ gpv2Settlement
214
+ );
215
+ const orderHash = hashOrder(orderValues);
216
+ const orderDigest = computeOrderDigest(domainSep, orderHash);
217
+
218
+ // orderUid = abi.encodePacked(orderDigest, owner, validTo) — 32 + 20 + 4 = 56 bytes
219
+ const orderUid = ethers.utils.solidityPack(
220
+ ["bytes32", "address", "uint32"],
221
+ [orderDigest, pool.address, validTo]
222
+ );
223
+
224
+ // 3. Submit order to CowSwap API — solver waits for on-chain presign before executing
225
+ try {
226
+ await axios.post(`${baseUrl}/orders`, {
227
+ sellToken: assetFrom,
228
+ buyToken: assetTo,
229
+ receiver: pool.address,
230
+ sellAmount,
231
+ buyAmount: buyAmountWithSlippage.toString(),
232
+ validTo,
233
+ appData: ethers.constants.HashZero,
234
+ feeAmount: "0",
235
+ kind,
236
+ partiallyFillable: false,
237
+ signingScheme: "presign",
238
+ signature: pool.address,
239
+ sellTokenBalance: "erc20",
240
+ buyTokenBalance: "erc20",
241
+ from: pool.address,
242
+ quoteId: quoteResponse.id
243
+ });
244
+ } catch (e) {
245
+ throw new ApiError("CowSwap order submission failed");
246
+ }
247
+
248
+ // 4. Encode CowSwapTypedData for submit() on TypedStructuredDataValidator
249
+ const typedData = {
250
+ domain: {
251
+ name: "Gnosis Protocol",
252
+ version: "v2",
253
+ chainId,
254
+ verifyingContract: gpv2Settlement
255
+ },
256
+ order: orderValues
257
+ };
258
+
259
+ const encodedTypedData = ethers.utils.defaultAbiCoder.encode(
260
+ [
261
+ "tuple(" +
262
+ "tuple(string name, string version, uint256 chainId, address verifyingContract) domain," +
263
+ "tuple(address sellToken, address buyToken, address receiver, uint256 sellAmount, uint256 buyAmount, uint32 validTo, bytes32 appData, uint256 feeAmount, bytes32 kind, bool partiallyFillable, bytes32 sellTokenBalance, bytes32 buyTokenBalance) order" +
264
+ ")"
265
+ ],
266
+ [typedData]
267
+ );
268
+
269
+ // 5. Encode setPreSignature() — guard checks isValidatedHash(pool, orderDigest)
270
+ const settlementIface = new ethers.utils.Interface(GPv2Settlement_ABI);
271
+ const preSignTxData = settlementIface.encodeFunctionData("setPreSignature", [
272
+ orderUid,
273
+ true
274
+ ]);
275
+
276
+ return {
277
+ encodedTypedData,
278
+ preSignTxData,
279
+ minAmountOut: buyAmountWithSlippage.toString()
280
+ };
281
+ }
@@ -6,7 +6,6 @@ import {
6
6
  LIMIT_ORDER_ACTION,
7
7
  LIMIT_ORDER_TIF_IOC,
8
8
  SEND_ASSET_ACTION,
9
- SPOT_DEX_ID,
10
9
  SPOT_SEND_ACTION,
11
10
  USDC_CORE_ADDRESS,
12
11
  USDC_TOKEN_ID
@@ -50,12 +49,15 @@ export const getWithdrawSpotHyperliquidTxData = (
50
49
  );
51
50
  return coreWriter.encodeFunctionData("sendRawAction", [rawTXData]);
52
51
  };
53
- export const getPerpToSpotHyperliquidTxData = (
54
- dexId: number,
52
+ export const getSendAssetHyperliquidTxData = (
53
+ sourceDex: number,
54
+ destinationDex: number,
55
55
  receiver: string,
56
56
  amount: ethers.BigNumber | string
57
57
  ): string => {
58
- const coreAmount = ethers.BigNumber.from(amount).mul(100); //USDC on Core has two more decimals
58
+ // Convert 6-decimal EVM USDC to 8-decimal HyperCore USDC (spot, main perp, and xyz)
59
+ // Transfer USDC between dexes (perp, spot, xyz)
60
+ const coreAmount = ethers.BigNumber.from(amount).mul(100);
59
61
  //From Perp to Spot
60
62
  const innerEncoded = ethers.utils.defaultAbiCoder.encode(
61
63
  //destination, subAccount, sourceDex, destinationDex, token, amount
@@ -63,8 +65,8 @@ export const getPerpToSpotHyperliquidTxData = (
63
65
  [
64
66
  receiver,
65
67
  ethers.constants.AddressZero,
66
- dexId,
67
- SPOT_DEX_ID,
68
+ sourceDex,
69
+ destinationDex,
68
70
  USDC_TOKEN_ID,
69
71
  coreAmount
70
72
  ]
@@ -50,7 +50,7 @@ export const TEST_POOL = {
50
50
 
51
51
  export const CONTRACT_ADDRESS = {
52
52
  [Network.POLYGON]: {
53
- USDC: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
53
+ USDC: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
54
54
  USDT: "",
55
55
  USDE: "",
56
56
  SUSD: "",
@@ -0,0 +1,81 @@
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, TEST_POOL } from "./constants";
7
+ import { getTxOptions } from "./txOptions";
8
+ import { TestingRunParams, testingHelper } from "./utils/testingHelper";
9
+ import { balanceDelta } from "./utils/token";
10
+
11
+ const testCowswap = ({ wallet, network }: TestingRunParams) => {
12
+ const USDC = CONTRACT_ADDRESS[network].USDC;
13
+ const WETH = CONTRACT_ADDRESS[network].WETH;
14
+
15
+ let dhedge: Dhedge;
16
+ let pool: Pool;
17
+ jest.setTimeout(100000);
18
+
19
+ describe(`pool on ${network}`, () => {
20
+ beforeAll(async () => {
21
+ dhedge = new Dhedge(wallet, network);
22
+ pool = await dhedge.loadPool(TEST_POOL[network]);
23
+ });
24
+
25
+ // it("approves unlimited USDC on Cowswap", async () => {
26
+ // await pool.approveSpender(
27
+ // "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", //Vault relayer
28
+ // USDC,
29
+ // MAX_AMOUNT,
30
+ // await getTxOptions(network)
31
+ // );
32
+ // const usdcAllowanceDelta = await allowanceDelta(
33
+ // pool.address,
34
+ // USDC,
35
+ // "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", //Vault relayer
36
+ // pool.signer
37
+ // );
38
+ // await expect(usdcAllowanceDelta.gt(0).toBe(true));
39
+ // });
40
+
41
+ // it("gets gas estimation for 2 USDC into WETH on Cowswap", async () => {
42
+ // const gasEstimate = await pool.trade(
43
+ // Dapp.COWSWAP,
44
+ // USDC,
45
+ // WETH,
46
+ // "2000000",
47
+ // 1,
48
+ // await getTxOptions(network),
49
+ // true
50
+ // );
51
+ // console.log(
52
+ // "Gas estimate for trading 2 USDC to WETH on Cowswap:",
53
+ // gasEstimate
54
+ // );
55
+ // expect(gasEstimate.minAmountOut).not.toBeNull();
56
+ // });
57
+
58
+ it("trades 2 USDC into WETH on Cowswap", async () => {
59
+ await pool.trade(
60
+ Dapp.COWSWAP,
61
+ USDC,
62
+ WETH,
63
+ "2000000",
64
+ 0.5,
65
+ await getTxOptions(network)
66
+ );
67
+ const wethBalanceDelta = await balanceDelta(
68
+ pool.address,
69
+ WETH,
70
+ pool.signer
71
+ );
72
+ expect(wethBalanceDelta.gt(0)).toBe(true);
73
+ });
74
+ });
75
+ };
76
+
77
+ testingHelper({
78
+ network: Network.POLYGON,
79
+ testingRun: testCowswap,
80
+ onFork: false
81
+ });
package/src/types.ts CHANGED
@@ -35,7 +35,8 @@ export enum Dapp {
35
35
  ODOS = "odos",
36
36
  PENDLE = "pendle",
37
37
  KYBERSWAP = "kyberswap",
38
- HYPERLIQUID = "hyperliquid"
38
+ HYPERLIQUID = "hyperliquid",
39
+ COWSWAP = "cowswap"
39
40
  }
40
41
 
41
42
  export enum Transaction {