@swapkit/core 1.0.0-rc.99 → 1.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.
Files changed (45) hide show
  1. package/dist/index.js +3 -0
  2. package/dist/index.js.map +12 -0
  3. package/package.json +23 -44
  4. package/src/__tests__/helpers.test.ts +65 -0
  5. package/src/client.ts +415 -0
  6. package/src/helpers/explorerUrls.ts +44 -0
  7. package/src/index.ts +6 -4
  8. package/src/types.ts +44 -0
  9. package/LICENSE +0 -201
  10. package/dist/index.cjs +0 -3
  11. package/dist/index.cjs.map +0 -1
  12. package/dist/index.d.ts +0 -230
  13. package/dist/index.es.js +0 -9119
  14. package/dist/index.es.js.map +0 -1
  15. package/src/aggregator/contracts/avaxGeneric.ts +0 -92
  16. package/src/aggregator/contracts/avaxWoofi.ts +0 -145
  17. package/src/aggregator/contracts/bscGeneric.ts +0 -106
  18. package/src/aggregator/contracts/ethGeneric.ts +0 -92
  19. package/src/aggregator/contracts/index.ts +0 -76
  20. package/src/aggregator/contracts/pancakeV2.ts +0 -145
  21. package/src/aggregator/contracts/pangolin.ts +0 -120
  22. package/src/aggregator/contracts/routers/index.ts +0 -58
  23. package/src/aggregator/contracts/routers/kyber.ts +0 -402
  24. package/src/aggregator/contracts/routers/oneinch.ts +0 -2188
  25. package/src/aggregator/contracts/routers/pancakeswap.ts +0 -340
  26. package/src/aggregator/contracts/routers/pangolin.ts +0 -340
  27. package/src/aggregator/contracts/routers/sushiswap.ts +0 -340
  28. package/src/aggregator/contracts/routers/traderJoe.ts +0 -340
  29. package/src/aggregator/contracts/routers/uniswapv2.ts +0 -340
  30. package/src/aggregator/contracts/routers/uniswapv3.ts +0 -254
  31. package/src/aggregator/contracts/routers/woofi.ts +0 -171
  32. package/src/aggregator/contracts/sushiswap.ts +0 -120
  33. package/src/aggregator/contracts/traderJoe.ts +0 -120
  34. package/src/aggregator/contracts/uniswapV2.ts +0 -120
  35. package/src/aggregator/contracts/uniswapV2Leg.ts +0 -128
  36. package/src/aggregator/contracts/uniswapV3_100.ts +0 -128
  37. package/src/aggregator/contracts/uniswapV3_10000.ts +0 -128
  38. package/src/aggregator/contracts/uniswapV3_3000.ts +0 -128
  39. package/src/aggregator/contracts/uniswapV3_500.ts +0 -128
  40. package/src/aggregator/getSwapParams.ts +0 -70
  41. package/src/client/__tests__/helpers.test.ts +0 -77
  42. package/src/client/explorerUrls.ts +0 -61
  43. package/src/client/index.ts +0 -769
  44. package/src/client/thornode.ts +0 -31
  45. package/src/client/types.ts +0 -115
@@ -1,769 +0,0 @@
1
- import type { ErrorKeys, ThornameRegisterParam } from '@swapkit/helpers';
2
- import {
3
- AssetValue,
4
- gasFeeMultiplier,
5
- getMemoFor,
6
- getMinAmountByChain,
7
- SwapKitError,
8
- SwapKitNumber,
9
- } from '@swapkit/helpers';
10
- import type { CosmosLikeToolbox } from '@swapkit/toolbox-cosmos';
11
- import type { AVAXToolbox, BSCToolbox, ETHToolbox, EVMToolbox } from '@swapkit/toolbox-evm';
12
- import type { UTXOToolbox } from '@swapkit/toolbox-utxo';
13
- import type {
14
- AddChainWalletParams,
15
- EVMChain,
16
- EVMWalletOptions,
17
- ExtendParams,
18
- WalletOption,
19
- } from '@swapkit/types';
20
- import {
21
- AGG_SWAP,
22
- Chain,
23
- ChainToChainId,
24
- FeeOption,
25
- MemoType,
26
- SWAP_IN,
27
- SWAP_OUT,
28
- TCAvalancheDepositABI,
29
- TCBscDepositABI,
30
- TCEthereumVaultAbi,
31
- } from '@swapkit/types';
32
-
33
- import type { AGG_CONTRACT_ADDRESS } from '../aggregator/contracts/index.ts';
34
- import { lowercasedContractAbiMapping } from '../aggregator/contracts/index.ts';
35
- import { getSwapInParams } from '../aggregator/getSwapParams.ts';
36
-
37
- import { getExplorerAddressUrl, getExplorerTxUrl } from './explorerUrls.ts';
38
- import { getInboundData, getMimirData } from './thornode.ts';
39
- import type {
40
- CoreTxParams,
41
- EVMWallet,
42
- SwapParams,
43
- ThorchainWallet,
44
- Wallet,
45
- WalletMethods,
46
- } from './types.ts';
47
-
48
- const getEmptyWalletStructure = () =>
49
- (Object.values(Chain) as Chain[]).reduce(
50
- (acc, chain) => {
51
- acc[chain] = null;
52
- return acc;
53
- },
54
- {} as Record<Chain, null>,
55
- );
56
-
57
- const validateAddressType = async ({ chain, address }: { chain: Chain; address?: string }) => {
58
- if (!address) return false;
59
-
60
- switch (chain) {
61
- case Chain.Bitcoin:
62
- // filter out taproot addresses
63
- return !address.startsWith('bc1p');
64
- default:
65
- return true;
66
- }
67
- };
68
-
69
- export class SwapKitCore<T = ''> {
70
- public connectedChains: Wallet = getEmptyWalletStructure();
71
- public connectedWallets: WalletMethods = getEmptyWalletStructure();
72
- public readonly stagenet: boolean = false;
73
-
74
- constructor({ stagenet }: { stagenet?: boolean } | undefined = {}) {
75
- this.stagenet = !!stagenet;
76
- }
77
-
78
- getAddress = (chain: Chain) => this.connectedChains[chain]?.address || '';
79
- getExplorerTxUrl = (chain: Chain, txHash: string) => getExplorerTxUrl({ chain, txHash });
80
- getWallet = <T extends Chain>(chain: Chain) => this.connectedWallets[chain] as WalletMethods[T];
81
- getExplorerAddressUrl = (chain: Chain, address: string) =>
82
- getExplorerAddressUrl({ chain, address });
83
- getBalance = async (chain: Chain, potentialScamFilter?: boolean) => {
84
- const wallet = await this.getWalletByChain(chain, potentialScamFilter);
85
-
86
- return wallet?.balance || [];
87
- };
88
-
89
- swap = async ({ streamSwap, recipient, route, feeOptionKey }: SwapParams) => {
90
- const {
91
- meta: { quoteMode },
92
- // evmTransactionDetails: contractCallParams,
93
- } = route;
94
- const evmChain = quoteMode.startsWith('ERC20-')
95
- ? Chain.Ethereum
96
- : quoteMode.startsWith('ARC20-')
97
- ? Chain.Avalanche
98
- : quoteMode.startsWith('BEP20-')
99
- ? Chain.BinanceSmartChain
100
- : undefined;
101
-
102
- if (!route.complete) throw new SwapKitError('core_swap_route_not_complete');
103
-
104
- // TODO enable when BE is ready
105
- // if (contractCallParams && evmChain) {
106
- // const walletMethods = this.connectedWallets[evmChain];
107
-
108
- // if (!walletMethods?.call) {
109
- // throw new SwapKitError('core_wallet_connection_not_found');
110
- // }
111
-
112
- // const { contractAddress, contractMethod, contractParams, contractParamsStreaming } =
113
- // contractCallParams;
114
-
115
- // if (!(streamSwap ? contractParamsStreaming : contractParams)) {
116
- // throw new SwapKitError('core_swap_route_transaction_not_found');
117
- // }
118
-
119
- // return await walletMethods.call<string>({
120
- // contractAddress,
121
- // abi: lowercasedContractAbiMapping[contractAddress.toLowerCase()],
122
- // funcName: contractMethod,
123
- // funcParams: streamSwap ? contractParamsStreaming : contractParams,
124
- // });
125
- // }
126
-
127
- if (AGG_SWAP.includes(quoteMode) && evmChain) {
128
- const walletMethods = this.connectedWallets[evmChain];
129
- if (!walletMethods?.sendTransaction) {
130
- throw new SwapKitError('core_wallet_connection_not_found');
131
- }
132
-
133
- const transaction = streamSwap ? route?.streamingSwap?.transaction : route?.transaction;
134
- if (!transaction) throw new SwapKitError('core_swap_route_transaction_not_found');
135
-
136
- const { data, from, to, value } = route.transaction;
137
-
138
- const params = {
139
- data,
140
- from,
141
- to: to.toLowerCase(),
142
- chainId: BigInt(ChainToChainId[evmChain]),
143
- value: value ? BigInt(value) : 0n,
144
- };
145
-
146
- return walletMethods.sendTransaction(params, feeOptionKey) as Promise<string>;
147
- }
148
-
149
- if (SWAP_OUT.includes(quoteMode)) {
150
- if (!route.calldata.fromAsset) throw new SwapKitError('core_swap_asset_not_recognized');
151
- const asset = await AssetValue.fromString(route.calldata.fromAsset);
152
- if (!asset) throw new SwapKitError('core_swap_asset_not_recognized');
153
-
154
- const { address: recipient } = await this.#getInboundDataByChain(asset.chain);
155
- const {
156
- contract: router,
157
- calldata: { expiration, amountIn, memo, memoStreamingSwap },
158
- } = route;
159
-
160
- const assetValue = asset.add(SwapKitNumber.fromBigInt(BigInt(amountIn), asset.decimal));
161
- const swapMemo = (streamSwap ? memoStreamingSwap || memo : memo) as string;
162
-
163
- return this.deposit({
164
- expiration,
165
- assetValue,
166
- memo: swapMemo,
167
- feeOptionKey,
168
- router,
169
- recipient,
170
- });
171
- }
172
-
173
- if (SWAP_IN.includes(quoteMode) && evmChain) {
174
- const { calldata, contract: contractAddress } = route;
175
- if (!contractAddress) throw new SwapKitError('core_swap_contract_not_found');
176
-
177
- const walletMethods = this.connectedWallets[evmChain];
178
- const from = this.getAddress(evmChain);
179
-
180
- if (!walletMethods?.sendTransaction || !from) {
181
- throw new SwapKitError('core_wallet_connection_not_found');
182
- }
183
-
184
- const { getProvider, toChecksumAddress } = await import('@swapkit/toolbox-evm');
185
- const provider = getProvider(evmChain);
186
- const abi = lowercasedContractAbiMapping[contractAddress.toLowerCase()];
187
-
188
- if (!abi) throw new SwapKitError('core_swap_contract_not_supported', { contractAddress });
189
-
190
- const contract = await walletMethods.createContract?.(contractAddress, abi, provider);
191
-
192
- const tx = await contract.getFunction('swapIn').populateTransaction(
193
- ...getSwapInParams({
194
- streamSwap,
195
- toChecksumAddress,
196
- contractAddress: contractAddress as AGG_CONTRACT_ADDRESS,
197
- recipient,
198
- calldata,
199
- }),
200
- { from },
201
- );
202
-
203
- return walletMethods.sendTransaction(tx, feeOptionKey) as Promise<string>;
204
- }
205
-
206
- throw new SwapKitError('core_swap_quote_mode_not_supported', { quoteMode });
207
- };
208
-
209
- getWalletByChain = async (chain: Chain, potentialScamFilter?: boolean) => {
210
- const address = this.getAddress(chain);
211
- if (!address) return null;
212
- const defaultBalance = [AssetValue.fromChainOrSignature(chain)];
213
- const walletType = this.connectedChains[chain]?.walletType as WalletOption;
214
-
215
- try {
216
- const balance = await this.getWallet(chain)?.getBalance(address, potentialScamFilter);
217
-
218
- this.connectedChains[chain] = {
219
- address,
220
- balance: balance?.length ? balance : defaultBalance,
221
- walletType,
222
- };
223
-
224
- return { ...this.connectedChains[chain] };
225
- } catch (error) {
226
- console.error(error);
227
-
228
- return { address, balance: defaultBalance, walletType };
229
- }
230
- };
231
-
232
- approveAssetValue = (assetValue: AssetValue, contractAddress?: string) =>
233
- this.#approve({ assetValue, type: 'approve', contractAddress });
234
-
235
- isAssetValueApproved = (assetValue: AssetValue, contractAddress?: string) =>
236
- this.#approve<boolean>({ assetValue, contractAddress, type: 'checkOnly' });
237
-
238
- validateAddress = ({ address, chain }: { address: string; chain: Chain }) =>
239
- this.getWallet(chain)?.validateAddress?.(address);
240
-
241
- transfer = async (params: CoreTxParams & { router?: string }) => {
242
- const walletInstance = this.connectedWallets[params.assetValue.chain];
243
- if (!walletInstance) throw new SwapKitError('core_wallet_connection_not_found');
244
-
245
- try {
246
- return await walletInstance.transfer(this.#prepareTxParams(params));
247
- } catch (error) {
248
- throw new SwapKitError('core_swap_transaction_error', error);
249
- }
250
- };
251
-
252
- deposit = async ({
253
- assetValue,
254
- recipient,
255
- router,
256
- ...rest
257
- }: CoreTxParams & { router?: string }) => {
258
- const { chain, symbol, ticker } = assetValue;
259
- const walletInstance = this.connectedWallets[chain];
260
- const isAddressValidated = await validateAddressType({
261
- address: await walletInstance?.getAddress(),
262
- chain,
263
- });
264
-
265
- if (!isAddressValidated) {
266
- throw new SwapKitError('core_transaction_invalid_sender_address');
267
- }
268
-
269
- if (!walletInstance) throw new SwapKitError('core_wallet_connection_not_found');
270
-
271
- const params = this.#prepareTxParams({ assetValue, recipient, router, ...rest });
272
-
273
- try {
274
- switch (chain) {
275
- case Chain.THORChain:
276
- case Chain.Maya: {
277
- const wallet = walletInstance as ThorchainWallet;
278
- return await (recipient === '' ? wallet.deposit(params) : wallet.transfer(params));
279
- }
280
-
281
- case Chain.Ethereum:
282
- case Chain.BinanceSmartChain:
283
- case Chain.Avalanche: {
284
- const { getChecksumAddressFromAsset } = await import('@swapkit/toolbox-evm');
285
-
286
- const abi =
287
- chain === Chain.Avalanche
288
- ? TCAvalancheDepositABI
289
- : chain === Chain.BinanceSmartChain
290
- ? TCBscDepositABI
291
- : TCEthereumVaultAbi;
292
-
293
- const response = await (
294
- walletInstance as EVMWallet<typeof AVAXToolbox | typeof ETHToolbox | typeof BSCToolbox>
295
- ).call({
296
- abi,
297
- contractAddress:
298
- router || ((await this.#getInboundDataByChain(chain as EVMChain)).router as string),
299
- funcName: 'depositWithExpiry',
300
- funcParams: [
301
- recipient,
302
- getChecksumAddressFromAsset({ chain, symbol, ticker }, chain),
303
- assetValue.getBaseValue('string'),
304
- params.memo,
305
- rest.expiration || parseInt(`${(new Date().getTime() + 15 * 60 * 1000) / 1000}`),
306
- ],
307
- txOverrides: {
308
- from: params.from,
309
- value: assetValue.isGasAsset ? assetValue.getBaseValue('bigint') : undefined,
310
- },
311
- });
312
-
313
- return response as string;
314
- }
315
-
316
- default: {
317
- return await walletInstance.transfer(params);
318
- }
319
- }
320
- } catch (error: any) {
321
- const errorMessage = (error?.message || error?.toString()).toLowerCase();
322
- const isInsufficientFunds = errorMessage?.includes('insufficient funds');
323
- const isGas = errorMessage?.includes('gas');
324
- const isServer = errorMessage?.includes('server');
325
- const isUserRejected = errorMessage?.includes('user rejected');
326
- const errorKey: ErrorKeys = isInsufficientFunds
327
- ? 'core_transaction_deposit_insufficient_funds_error'
328
- : isGas
329
- ? 'core_transaction_deposit_gas_error'
330
- : isServer
331
- ? 'core_transaction_deposit_server_error'
332
- : isUserRejected
333
- ? 'core_transaction_user_rejected'
334
- : 'core_transaction_deposit_error';
335
-
336
- throw new SwapKitError(errorKey, error);
337
- }
338
- };
339
-
340
- /**
341
- * TC related Methods
342
- */
343
- createLiquidity = async ({
344
- runeAssetValue,
345
- assetValue,
346
- }: {
347
- runeAssetValue: AssetValue;
348
- assetValue: AssetValue;
349
- }) => {
350
- if (runeAssetValue.lte(0) || assetValue.lte(0)) {
351
- throw new SwapKitError('core_transaction_create_liquidity_invalid_params');
352
- }
353
-
354
- let runeTx = '';
355
- let assetTx = '';
356
-
357
- try {
358
- runeTx = await this.#depositToPool({
359
- assetValue: runeAssetValue,
360
- memo: getMemoFor(MemoType.DEPOSIT, {
361
- ...assetValue,
362
- address: this.getAddress(assetValue.chain),
363
- }),
364
- });
365
- } catch (error) {
366
- throw new SwapKitError('core_transaction_create_liquidity_rune_error', error);
367
- }
368
-
369
- try {
370
- assetTx = await this.#depositToPool({
371
- assetValue,
372
- memo: getMemoFor(MemoType.DEPOSIT, {
373
- ...assetValue,
374
- address: this.getAddress(Chain.THORChain),
375
- }),
376
- });
377
- } catch (error) {
378
- throw new SwapKitError('core_transaction_create_liquidity_asset_error', error);
379
- }
380
-
381
- return { runeTx, assetTx };
382
- };
383
-
384
- addLiquidity = async ({
385
- runeAssetValue,
386
- assetValue,
387
- runeAddr,
388
- assetAddr,
389
- isPendingSymmAsset,
390
- mode = 'sym',
391
- }: {
392
- runeAssetValue: AssetValue;
393
- assetValue: AssetValue;
394
- isPendingSymmAsset?: boolean;
395
- runeAddr?: string;
396
- assetAddr?: string;
397
- mode?: 'sym' | 'rune' | 'asset';
398
- }) => {
399
- const { chain, symbol } = assetValue;
400
- const isSym = mode === 'sym';
401
- const runeTransfer = runeAssetValue?.gt(0) && (isSym || mode === 'rune');
402
- const assetTransfer = assetValue?.gt(0) && (isSym || mode === 'asset');
403
- const includeRuneAddress = isPendingSymmAsset || runeTransfer;
404
- const runeAddress = includeRuneAddress ? runeAddr || this.getAddress(Chain.THORChain) : '';
405
- const assetAddress = isSym || mode === 'asset' ? assetAddr || this.getAddress(chain) : '';
406
-
407
- if (!runeTransfer && !assetTransfer) {
408
- throw new SwapKitError('core_transaction_add_liquidity_invalid_params');
409
- }
410
- if (includeRuneAddress && !runeAddress) {
411
- throw new SwapKitError('core_transaction_add_liquidity_no_rune_address');
412
- }
413
-
414
- let runeTx, assetTx;
415
-
416
- if (runeTransfer && runeAssetValue) {
417
- try {
418
- runeTx = await this.#depositToPool({
419
- assetValue: runeAssetValue,
420
- memo: getMemoFor(MemoType.DEPOSIT, { chain, symbol, address: assetAddress }),
421
- });
422
- } catch (error) {
423
- throw new SwapKitError('core_transaction_add_liquidity_rune_error', error);
424
- }
425
- }
426
-
427
- if (assetTransfer && assetValue) {
428
- try {
429
- assetTx = await this.#depositToPool({
430
- assetValue,
431
- memo: getMemoFor(MemoType.DEPOSIT, { chain, symbol, address: runeAddress }),
432
- });
433
- } catch (error) {
434
- throw new SwapKitError('core_transaction_add_liquidity_asset_error', error);
435
- }
436
- }
437
-
438
- return { runeTx, assetTx };
439
- };
440
-
441
- addLiquidityPart = ({
442
- assetValue,
443
- poolAddress,
444
- address,
445
- symmetric,
446
- }: {
447
- assetValue: AssetValue;
448
- address?: string;
449
- poolAddress: string;
450
- symmetric: boolean;
451
- }) => {
452
- if (symmetric && !address) {
453
- throw new SwapKitError('core_transaction_add_liquidity_invalid_params');
454
- }
455
- const memo = getMemoFor(MemoType.DEPOSIT, {
456
- chain: poolAddress.split('.')[0] as Chain,
457
- symbol: poolAddress.split('.')[1],
458
- address: symmetric ? address : '',
459
- });
460
-
461
- return this.#depositToPool({ assetValue, memo });
462
- };
463
-
464
- withdraw = async ({
465
- memo,
466
- assetValue,
467
- percent,
468
- from,
469
- to,
470
- }: {
471
- memo?: string;
472
- assetValue: AssetValue;
473
- percent: number;
474
- from: 'sym' | 'rune' | 'asset';
475
- to: 'sym' | 'rune' | 'asset';
476
- }) => {
477
- const targetAsset =
478
- to === 'rune' && from !== 'rune'
479
- ? AssetValue.fromChainOrSignature(Chain.THORChain)
480
- : (from === 'sym' && to === 'sym') || from === 'rune' || from === 'asset'
481
- ? undefined
482
- : assetValue;
483
-
484
- const value = getMinAmountByChain(from === 'asset' ? assetValue.chain : Chain.THORChain);
485
- const memoString =
486
- memo ||
487
- getMemoFor(MemoType.WITHDRAW, {
488
- symbol: assetValue.symbol,
489
- chain: assetValue.chain,
490
- ticker: assetValue.ticker,
491
- basisPoints: Math.min(10000, Math.round(percent * 100)),
492
- targetAssetString: targetAsset?.toString(),
493
- singleSide: false,
494
- });
495
-
496
- return this.#depositToPool({ assetValue: value, memo: memoString });
497
- };
498
-
499
- savings = async ({
500
- assetValue,
501
- memo,
502
- percent,
503
- type,
504
- }: { assetValue: AssetValue; memo?: string } & (
505
- | { type: 'add'; percent?: undefined }
506
- | { type: 'withdraw'; percent: number }
507
- )) => {
508
- const memoType = type === 'add' ? MemoType.DEPOSIT : MemoType.WITHDRAW;
509
- const memoString =
510
- memo ||
511
- getMemoFor(memoType, {
512
- ticker: assetValue.ticker,
513
- symbol: assetValue.symbol,
514
- chain: assetValue.chain,
515
- singleSide: true,
516
- basisPoints: percent ? Math.min(10000, Math.round(percent * 100)) : undefined,
517
- });
518
-
519
- const value =
520
- memoType === MemoType.DEPOSIT ? assetValue : getMinAmountByChain(assetValue.chain);
521
-
522
- return this.#depositToPool({ memo: memoString, assetValue: value });
523
- };
524
-
525
- loan = ({
526
- assetValue,
527
- memo,
528
- minAmount,
529
- type,
530
- }: {
531
- assetValue: AssetValue;
532
- memo?: string;
533
- minAmount: AssetValue;
534
- type: 'open' | 'close';
535
- }) =>
536
- this.#depositToPool({
537
- assetValue,
538
- memo:
539
- memo ||
540
- getMemoFor(type === 'open' ? MemoType.OPEN_LOAN : MemoType.CLOSE_LOAN, {
541
- asset: assetValue.toString(),
542
- minAmount: minAmount.toString(),
543
- address: this.getAddress(assetValue.chain),
544
- }),
545
- });
546
-
547
- nodeAction = ({
548
- type,
549
- assetValue,
550
- address,
551
- }: { address: string } & (
552
- | { type: 'bond' | 'unbond'; assetValue: AssetValue }
553
- | { type: 'leave'; assetValue?: undefined }
554
- )) => {
555
- const memoType =
556
- type === 'bond' ? MemoType.BOND : type === 'unbond' ? MemoType.UNBOND : MemoType.LEAVE;
557
- const memo = getMemoFor(memoType, {
558
- address,
559
- unbondAmount: type === 'unbond' ? assetValue.getBaseValue('number') : undefined,
560
- });
561
-
562
- return this.#thorchainTransfer({
563
- memo,
564
- assetValue: type === 'bond' ? assetValue : getMinAmountByChain(Chain.THORChain),
565
- });
566
- };
567
-
568
- registerThorname = ({
569
- assetValue,
570
- ...param
571
- }: ThornameRegisterParam & { assetValue: AssetValue }) =>
572
- this.#thorchainTransfer({ assetValue, memo: getMemoFor(MemoType.THORNAME_REGISTER, param) });
573
-
574
- extend = ({ wallets, config, apis = {}, rpcUrls = {} }: ExtendParams<T>) => {
575
- try {
576
- wallets.forEach((wallet) => {
577
- // @ts-expect-error - this is fine as we are extending the class
578
- this[wallet.connectMethodName] = wallet.connect({
579
- addChain: this.#addConnectedChain,
580
- config: config || {},
581
- apis,
582
- rpcUrls,
583
- });
584
- });
585
- } catch (error) {
586
- throw new SwapKitError('core_extend_error', error);
587
- }
588
- };
589
-
590
- estimateMaxSendableAmount = async ({
591
- chain,
592
- params,
593
- }: {
594
- chain: Chain;
595
- params: { from: string; recipient: string; assetValue: AssetValue };
596
- }) => {
597
- const walletMethods = this.getWallet<typeof chain>(chain);
598
-
599
- switch (chain) {
600
- case Chain.Arbitrum:
601
- case Chain.Avalanche:
602
- case Chain.BinanceSmartChain:
603
- case Chain.Ethereum:
604
- case Chain.Optimism:
605
- case Chain.Polygon: {
606
- const { estimateMaxSendableAmount } = await import('@swapkit/toolbox-evm');
607
- return estimateMaxSendableAmount({
608
- ...params,
609
- toolbox: walletMethods as EVMToolbox,
610
- });
611
- }
612
-
613
- case Chain.Bitcoin:
614
- case Chain.BitcoinCash:
615
- case Chain.Dogecoin:
616
- case Chain.Litecoin:
617
- return (walletMethods as UTXOToolbox).estimateMaxSendableAmount(params);
618
-
619
- case Chain.Binance:
620
- case Chain.THORChain:
621
- case Chain.Cosmos: {
622
- const { estimateMaxSendableAmount } = await import('@swapkit/toolbox-cosmos');
623
- return estimateMaxSendableAmount({
624
- ...params,
625
- toolbox: walletMethods as CosmosLikeToolbox,
626
- });
627
- }
628
-
629
- default:
630
- throw new SwapKitError('core_estimated_max_spendable_chain_not_supported');
631
- }
632
- };
633
-
634
- /**
635
- * Wallet connection methods
636
- */
637
- connectXDEFI = async (_chains: Chain[]): Promise<void> => {
638
- throw new SwapKitError('core_wallet_xdefi_not_installed');
639
- };
640
- connectEVMWallet = async (_chains: Chain[] | Chain, _wallet: EVMWalletOptions): Promise<void> => {
641
- throw new SwapKitError('core_wallet_evmwallet_not_installed');
642
- };
643
- connectWalletconnect = async (_chains: Chain[], _options?: any): Promise<void> => {
644
- throw new SwapKitError('core_wallet_walletconnect_not_installed');
645
- };
646
- connectKeepkey = async (_chains: Chain[], _derivationPath: number[][]): Promise<string> => {
647
- throw new SwapKitError('core_wallet_keepkey_not_installed');
648
- };
649
- connectKeystore = async (_chains: Chain[], _phrase: string): Promise<void> => {
650
- throw new SwapKitError('core_wallet_keystore_not_installed');
651
- };
652
- connectLedger = async (_chains: Chain, _derivationPath: number[]): Promise<void> => {
653
- throw new SwapKitError('core_wallet_ledger_not_installed');
654
- };
655
- connectTrezor = async (_chains: Chain, _derivationPath: number[]): Promise<void> => {
656
- throw new SwapKitError('core_wallet_trezor_not_installed');
657
- };
658
- connectKeplr = async (_chain: Chain): Promise<void> => {
659
- throw new SwapKitError('core_wallet_keplr_not_installed');
660
- };
661
- connectOkx = async (_chains: Chain[]): Promise<void> => {
662
- throw new SwapKitError('core_wallet_okx_not_installed');
663
- };
664
- disconnectChain = (chain: Chain) => {
665
- this.connectedChains[chain] = null;
666
- this.connectedWallets[chain] = null;
667
- };
668
-
669
- #getInboundDataByChain = async (chain: Chain) => {
670
- switch (chain) {
671
- case Chain.Maya:
672
- case Chain.THORChain:
673
- return { gas_rate: '0', router: '', address: '', halted: false, chain };
674
-
675
- default: {
676
- const inboundData = await getInboundData(this.stagenet);
677
- const chainAddressData = inboundData.find((item) => item.chain === chain);
678
-
679
- if (!chainAddressData) throw new SwapKitError('core_inbound_data_not_found');
680
- if (chainAddressData?.halted) throw new SwapKitError('core_chain_halted');
681
-
682
- return chainAddressData;
683
- }
684
- }
685
- };
686
-
687
- #addConnectedChain = ({ chain, wallet, walletMethods }: AddChainWalletParams) => {
688
- this.connectedChains[chain] = wallet;
689
- this.connectedWallets[chain] = walletMethods;
690
- };
691
-
692
- #approve = async <T = string>({
693
- assetValue,
694
- type = 'checkOnly',
695
- contractAddress,
696
- }: {
697
- assetValue: AssetValue;
698
- type?: 'checkOnly' | 'approve';
699
- contractAddress?: string;
700
- }) => {
701
- const { address, chain, isGasAsset, isSynthetic } = assetValue;
702
- const isEVMChain = [Chain.Ethereum, Chain.Avalanche, Chain.BinanceSmartChain].includes(chain);
703
- const isNativeEVM = isEVMChain && isGasAsset;
704
-
705
- if (isNativeEVM || !isEVMChain || isSynthetic) return true;
706
-
707
- const walletMethods = this.connectedWallets[chain as EVMChain];
708
- const walletAction = type === 'checkOnly' ? walletMethods?.isApproved : walletMethods?.approve;
709
-
710
- if (!walletAction) throw new SwapKitError('core_wallet_connection_not_found');
711
-
712
- const from = this.getAddress(chain);
713
-
714
- if (!address || !from) throw new SwapKitError('core_approve_asset_address_or_from_not_found');
715
-
716
- const spenderAddress =
717
- contractAddress || ((await this.#getInboundDataByChain(chain)).router as string);
718
-
719
- return walletAction({
720
- amount: assetValue.getBaseValue('bigint'),
721
- assetAddress: address,
722
- from,
723
- spenderAddress,
724
- }) as Promise<T>;
725
- };
726
-
727
- #depositToPool = async ({
728
- assetValue,
729
- memo,
730
- feeOptionKey = FeeOption.Fast,
731
- }: {
732
- assetValue: AssetValue;
733
- memo: string;
734
- feeOptionKey?: FeeOption;
735
- }) => {
736
- const {
737
- gas_rate,
738
- router,
739
- address: poolAddress,
740
- } = await this.#getInboundDataByChain(assetValue.chain);
741
- const feeRate = (parseInt(gas_rate) || 0) * gasFeeMultiplier[feeOptionKey];
742
-
743
- return this.deposit({
744
- assetValue,
745
- recipient: poolAddress,
746
- memo,
747
- router,
748
- feeRate,
749
- });
750
- };
751
-
752
- #thorchainTransfer = async ({ memo, assetValue }: { assetValue: AssetValue; memo: string }) => {
753
- const mimir = await getMimirData(this.stagenet);
754
-
755
- // check if trading is halted or not
756
- if (mimir['HALTCHAINGLOBAL'] >= 1 || mimir['HALTTHORCHAIN'] >= 1) {
757
- throw new SwapKitError('core_chain_halted');
758
- }
759
-
760
- return this.deposit({ assetValue, recipient: '', memo });
761
- };
762
-
763
- #prepareTxParams = ({ assetValue, ...restTxParams }: CoreTxParams & { router?: string }) => ({
764
- ...restTxParams,
765
- memo: restTxParams.memo || '',
766
- from: this.getAddress(assetValue.chain),
767
- assetValue,
768
- });
769
- }