@shapeshiftoss/swapper 17.7.1 → 17.7.3

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 (41) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/index.d.ts +1 -0
  3. package/dist/cjs/index.js +1 -0
  4. package/dist/cjs/swappers/NearIntentsSwapper/constants.d.ts +1 -0
  5. package/dist/cjs/swappers/NearIntentsSwapper/constants.js +2 -1
  6. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +5 -2
  7. package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers/helpers.js +5 -1
  8. package/dist/cjs/swappers/ThorchainSwapper/getTradeQuote/getTradeQuote.test.js +10 -0
  9. package/dist/cjs/thorchain-utils/checkTradeStatus.js +8 -1
  10. package/dist/cjs/thorchain-utils/cosmossdk/getThorTxData.d.ts +12 -0
  11. package/dist/cjs/thorchain-utils/cosmossdk/getThorTxData.js +19 -0
  12. package/dist/cjs/thorchain-utils/cosmossdk/index.d.ts +1 -0
  13. package/dist/cjs/thorchain-utils/cosmossdk/index.js +1 -0
  14. package/dist/cjs/thorchain-utils/getL1RateOrQuote.js +35 -10
  15. package/dist/cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.d.ts +3 -2
  16. package/dist/cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.js +21 -14
  17. package/dist/cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.test.js +11 -5
  18. package/dist/cjs/thorchain-utils/index.d.ts +1 -0
  19. package/dist/cjs/thorchain-utils/index.js +12 -1
  20. package/dist/cjs/types.d.ts +6 -0
  21. package/dist/esm/.tsbuildinfo +1 -1
  22. package/dist/esm/index.d.ts +1 -0
  23. package/dist/esm/index.js +1 -0
  24. package/dist/esm/swappers/NearIntentsSwapper/constants.d.ts +1 -0
  25. package/dist/esm/swappers/NearIntentsSwapper/constants.js +1 -0
  26. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +7 -4
  27. package/dist/esm/swappers/NearIntentsSwapper/utils/helpers/helpers.js +5 -1
  28. package/dist/esm/swappers/ThorchainSwapper/getTradeQuote/getTradeQuote.test.js +10 -0
  29. package/dist/esm/thorchain-utils/checkTradeStatus.js +8 -1
  30. package/dist/esm/thorchain-utils/cosmossdk/getThorTxData.d.ts +12 -0
  31. package/dist/esm/thorchain-utils/cosmossdk/getThorTxData.js +15 -0
  32. package/dist/esm/thorchain-utils/cosmossdk/index.d.ts +1 -0
  33. package/dist/esm/thorchain-utils/cosmossdk/index.js +1 -0
  34. package/dist/esm/thorchain-utils/getL1RateOrQuote.js +35 -10
  35. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.d.ts +3 -2
  36. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.js +20 -13
  37. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.test.js +12 -6
  38. package/dist/esm/thorchain-utils/index.d.ts +1 -0
  39. package/dist/esm/thorchain-utils/index.js +11 -1
  40. package/dist/esm/types.d.ts +6 -0
  41. package/package.json +2 -2
@@ -14,6 +14,7 @@ export * from './swappers/PortalsSwapper/index.js';
14
14
  export * from './swappers/ThorchainSwapper/index.js';
15
15
  export * from './swappers/MayachainSwapper/index.js';
16
16
  export * from './swappers/ButterSwap/index.js';
17
+ export * from './swappers/RelaySwapper/index.js';
17
18
  export * from './swappers/utils/helpers/helpers.js';
18
19
  export * from './thorchain-utils/index.js';
19
20
  export * from './types.js';
package/dist/esm/index.js CHANGED
@@ -14,6 +14,7 @@ export * from './swappers/PortalsSwapper/index.js';
14
14
  export * from './swappers/ThorchainSwapper/index.js';
15
15
  export * from './swappers/MayachainSwapper/index.js';
16
16
  export * from './swappers/ButterSwap/index.js';
17
+ export * from './swappers/RelaySwapper/index.js';
17
18
  export * from './swappers/utils/helpers/helpers.js';
18
19
  export * from './thorchain-utils/index.js';
19
20
  export * from './types.js';
@@ -1,3 +1,4 @@
1
1
  export declare const ONE_CLICK_BASE_URL = "https://1click.chaindefuser.com";
2
2
  export declare const DEFAULT_SLIPPAGE_BPS = 50;
3
3
  export declare const DEFAULT_QUOTE_DEADLINE_MS: number;
4
+ export declare const BTC_QUOTE_DEADLINE_MS: number;
@@ -1,3 +1,4 @@
1
1
  export const ONE_CLICK_BASE_URL = 'https://1click.chaindefuser.com';
2
2
  export const DEFAULT_SLIPPAGE_BPS = 50;
3
3
  export const DEFAULT_QUOTE_DEADLINE_MS = 30 * 60 * 1000;
4
+ export const BTC_QUOTE_DEADLINE_MS = 60 * 60 * 1000;
@@ -1,4 +1,4 @@
1
- import { CHAIN_NAMESPACE, fromAssetId, nearChainId } from '@shapeshiftoss/caip';
1
+ import { btcChainId, CHAIN_NAMESPACE, fromAssetId, nearChainId } from '@shapeshiftoss/caip';
2
2
  import { evm } from '@shapeshiftoss/chain-adapters';
3
3
  import { bn, bnOrZero, chainIdToFeeAssetId, contractAddressOrUndefined, DAO_TREASURY_NEAR, isToken, } from '@shapeshiftoss/utils';
4
4
  import { Err, Ok } from '@sniptt/monads';
@@ -8,7 +8,7 @@ import { SwapperName, TradeQuoteError } from '../../../types.js';
8
8
  import { createTradeAmountTooSmallErr, getInputOutputRate, makeSwapErrorRight, } from '../../../utils.js';
9
9
  import { buildAffiliateFee } from '../../utils/affiliateFee.js';
10
10
  import { isNativeEvmAsset } from '../../utils/helpers/helpers.js';
11
- import { DEFAULT_QUOTE_DEADLINE_MS, DEFAULT_SLIPPAGE_BPS } from '../constants.js';
11
+ import { BTC_QUOTE_DEADLINE_MS, DEFAULT_QUOTE_DEADLINE_MS, DEFAULT_SLIPPAGE_BPS, } from '../constants.js';
12
12
  import { QuoteRequest } from '../types.js';
13
13
  import { assetToNearIntentsAsset, calculateAccountCreationCosts } from '../utils/helpers/helpers.js';
14
14
  import { ApiError, initializeOneClickService, OneClickService } from '../utils/oneClickService.js';
@@ -49,6 +49,9 @@ export const getTradeQuote = async (input, deps) => {
49
49
  message: `Asset ${buyAsset.symbol} on ${buyAsset.networkName || buyAsset.chainId} is not supported by NEAR Intents`,
50
50
  }));
51
51
  }
52
+ const quoteDeadline = sellAsset.chainId === btcChainId || buyAsset.chainId === btcChainId
53
+ ? BTC_QUOTE_DEADLINE_MS
54
+ : DEFAULT_QUOTE_DEADLINE_MS;
52
55
  const quoteRequest = {
53
56
  dry: false,
54
57
  swapType: QuoteRequest.swapType.EXACT_INPUT,
@@ -63,7 +66,7 @@ export const getTradeQuote = async (input, deps) => {
63
66
  refundType: QuoteRequest.refundType.ORIGIN_CHAIN,
64
67
  recipient: receiveAddress,
65
68
  recipientType: QuoteRequest.recipientType.DESTINATION_CHAIN,
66
- deadline: new Date(Date.now() + DEFAULT_QUOTE_DEADLINE_MS).toISOString(),
69
+ deadline: new Date(Date.now() + quoteDeadline).toISOString(),
67
70
  referral: 'shapeshift',
68
71
  appFees: [
69
72
  {
@@ -256,7 +259,7 @@ export const getTradeQuote = async (input, deps) => {
256
259
  steps: [
257
260
  {
258
261
  accountNumber,
259
- allowanceContract: quote.depositAddress,
262
+ allowanceContract: '',
260
263
  buyAmountBeforeFeesCryptoBaseUnit: quote.amountOut,
261
264
  buyAmountAfterFeesCryptoBaseUnit: quote.amountOut,
262
265
  buyAsset,
@@ -45,6 +45,7 @@ export const getNearIntentsAsset = ({ nearNetwork, contractAddress, }) => {
45
45
  const NEP245_CHAINS = ['bsc', 'pol', 'avax', 'op', 'tron', 'monad', 'plasma'];
46
46
  const TOKEN_LOOKUP_CHAINS = ['sui', 'starknet', 'ton'];
47
47
  const NEAR_CHAIN = 'near';
48
+ const BTC_CHAIN = 'btc';
48
49
  const WNEAR_CONTRACT_ADDRESS = 'wrap.near';
49
50
  const isNep245Chain = (chain) => {
50
51
  return NEP245_CHAINS.includes(chain);
@@ -56,6 +57,9 @@ export const assetToNearIntentsAsset = async (asset) => {
56
57
  const nearNetwork = chainIdToNearIntentsChain[asset.chainId];
57
58
  if (!nearNetwork)
58
59
  return null;
60
+ // https://partners.near-intents.org/omni-migration#partners
61
+ if (nearNetwork === BTC_CHAIN)
62
+ return `1cs_v1:btc:native:coin`;
59
63
  // NEAR chain requires special handling
60
64
  // Native NEAR maps to wNEAR (wrap.near)
61
65
  if (nearNetwork === NEAR_CHAIN) {
@@ -91,7 +95,7 @@ export const assetToNearIntentsAsset = async (asset) => {
91
95
  }
92
96
  return match.assetId;
93
97
  }
94
- // NEP-141 chains (ETH, ARB, BASE, GNOSIS, BTC, DOGE): use predictable format
98
+ // NEP-141 chains (ETH, ARB, BASE, GNOSIS, DOGE): use predictable format
95
99
  const contractAddress = isToken(asset.assetId)
96
100
  ? fromAssetId(asset.assetId).assetReference
97
101
  : zeroAddress;
@@ -76,6 +76,11 @@ const expectedQuoteResponse = [
76
76
  thorchainSpecific: {
77
77
  maxStreamingQuantity: undefined,
78
78
  },
79
+ thorchainTransactionMetadata: {
80
+ to: '0x3624525075b88B24ecc29CE226b0CEc1fFcB6976',
81
+ data: '0x',
82
+ value: '0',
83
+ },
79
84
  },
80
85
  ],
81
86
  },
@@ -119,6 +124,11 @@ const expectedQuoteResponse = [
119
124
  thorchainSpecific: {
120
125
  maxStreamingQuantity: undefined,
121
126
  },
127
+ thorchainTransactionMetadata: {
128
+ to: '0x3624525075b88B24ecc29CE226b0CEc1fFcB6976',
129
+ data: '0x',
130
+ value: '0',
131
+ },
122
132
  },
123
133
  ],
124
134
  },
@@ -62,7 +62,14 @@ export const checkTradeStatus = async ({ txHash, chainId, address, fetchIsSmartC
62
62
  return { buyTxHash, status: TxStatus.Pending, message };
63
63
  }
64
64
  catch (e) {
65
- console.error(e);
65
+ const message = (() => {
66
+ if (axios.isAxiosError(e))
67
+ return e.response?.data?.message ?? e.message;
68
+ if (e instanceof Error)
69
+ return e.message;
70
+ return String(e);
71
+ })();
72
+ console.error(`checkTradeStatus(${nativeChain}, ${txHash}): ${message}`);
66
73
  return { buyTxHash: undefined, status: TxStatus.Unknown, message: undefined };
67
74
  }
68
75
  };
@@ -0,0 +1,12 @@
1
+ import type { Asset } from '@shapeshiftoss/types';
2
+ import type { SwapperConfig, SwapperName } from '../../types.js';
3
+ type GetThorTxDataArgs = {
4
+ sellAsset: Asset;
5
+ config: SwapperConfig;
6
+ swapperName: SwapperName;
7
+ };
8
+ type GetThorTxDataReturn = {
9
+ vault: string;
10
+ };
11
+ export declare const getThorTxData: ({ sellAsset, config, swapperName, }: GetThorTxDataArgs) => Promise<GetThorTxDataReturn>;
12
+ export {};
@@ -0,0 +1,15 @@
1
+ import { getInboundAddressDataForChain } from '../getInboundAddressDataForChain.js';
2
+ import { getChainIdBySwapper, getDaemonUrl } from '../index.js';
3
+ export const getThorTxData = async ({ sellAsset, config, swapperName, }) => {
4
+ // Native assets on the swapper's own chain (RUNE on THORChain, CACAO on MAYAChain)
5
+ // deposit via MsgDeposit and have no recipient address.
6
+ if (sellAsset.chainId === getChainIdBySwapper(swapperName))
7
+ return { vault: '' };
8
+ // Everything else (e.g. ATOM via THORChain, RUNE via MAYAChain) sends via MsgSend
9
+ // to the swapper's inbound vault on that chain.
10
+ const daemonUrl = getDaemonUrl(config, swapperName);
11
+ const res = await getInboundAddressDataForChain(daemonUrl, sellAsset.assetId, true, swapperName);
12
+ if (res.isErr())
13
+ throw res.unwrapErr();
14
+ return { vault: res.unwrap().address };
15
+ };
@@ -1 +1,2 @@
1
1
  export * from './getCosmosSdkTransactionFees.js';
2
+ export * from './getThorTxData.js';
@@ -1 +1,2 @@
1
1
  export * from './getCosmosSdkTransactionFees.js';
2
+ export * from './getThorTxData.js';
@@ -7,8 +7,10 @@ import { TronWeb } from 'tronweb';
7
7
  import { v4 as uuid } from 'uuid';
8
8
  import { getDefaultSlippageDecimalPercentageForSwapper } from '../index.js';
9
9
  import { buildAffiliateFee } from '../swappers/utils/affiliateFee.js';
10
+ import { isNativeEvmAsset } from '../swappers/utils/helpers/helpers.js';
10
11
  import { TradeQuoteError } from '../types.js';
11
12
  import { getInputOutputRate, makeSwapErrorRight } from '../utils.js';
13
+ import * as cosmossdk from './cosmossdk/index.js';
12
14
  import * as evm from './evm/index.js';
13
15
  import { getLimitWithManualSlippage } from './getLimitWithManualSlippage/getLimitWithManualSlippage.js';
14
16
  import { getQuote } from './getQuote.js';
@@ -128,7 +130,7 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
128
130
  affilate: getAffiliate(swapperName),
129
131
  });
130
132
  };
131
- const makeThorTradeRateOrQuote = ({ route, memo, allowanceContract, feeData, data, router, vault, }) => {
133
+ const makeThorTradeRateOrQuote = ({ route, memo, allowanceContract, feeData, data, router, vault, thorchainTransactionMetadata, }) => {
132
134
  const buyAmountAfterFeesCryptoBaseUnit = convertPrecision({
133
135
  value: route.expectedAmountOutThorBaseUnit,
134
136
  inputExponent: buyAssetNativePrecision,
@@ -182,6 +184,7 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
182
184
  thorchainSpecific: {
183
185
  maxStreamingQuantity: route.quote.max_streaming_quantity,
184
186
  },
187
+ thorchainTransactionMetadata,
185
188
  },
186
189
  ],
187
190
  };
@@ -213,6 +216,11 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
213
216
  data,
214
217
  router,
215
218
  vault,
219
+ thorchainTransactionMetadata: {
220
+ to: router,
221
+ data,
222
+ value: isNativeEvmAsset(sellAsset.assetId) ? sellAmountCryptoBaseUnit : '0',
223
+ },
216
224
  feeData: {
217
225
  protocolFees: getProtocolFees(route.quote),
218
226
  networkFeeCryptoBaseUnit,
@@ -260,6 +268,11 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
260
268
  route,
261
269
  allowanceContract: '0x0',
262
270
  memo,
271
+ thorchainTransactionMetadata: {
272
+ to: vault,
273
+ memo,
274
+ value: sellAmountCryptoBaseUnit,
275
+ },
263
276
  feeData,
264
277
  });
265
278
  }));
@@ -275,11 +288,18 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
275
288
  case CHAIN_NAMESPACE.CosmosSdk: {
276
289
  const cosmosChainAdapter = assertGetCosmosSdkChainAdapter(sellAsset.chainId);
277
290
  const { fast } = await cosmosChainAdapter.getFeeData({});
291
+ const { vault } = await cosmossdk.getThorTxData({ sellAsset, config, swapperName });
278
292
  return Ok(perRouteValues.map((route) => {
293
+ const memo = getMemo(route);
279
294
  return makeThorTradeRateOrQuote({
280
295
  route,
281
- memo: getMemo(route),
296
+ memo,
282
297
  allowanceContract: '0x0',
298
+ thorchainTransactionMetadata: {
299
+ to: vault,
300
+ memo,
301
+ value: sellAmountCryptoBaseUnit,
302
+ },
283
303
  feeData: {
284
304
  networkFeeCryptoBaseUnit: fast.txFee,
285
305
  protocolFees: getProtocolFees(route.quote),
@@ -293,13 +313,13 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
293
313
  case CHAIN_NAMESPACE.Solana: {
294
314
  const adapter = assertGetSolanaChainAdapter(sellAsset.chainId);
295
315
  const sendAddress = input.sendAddress;
316
+ const { vault } = await solana.getThorTxData({ sellAsset, config, swapperName });
296
317
  const maybeRoutes = await Promise.allSettled(perRouteValues.map(async (route) => {
297
318
  const memo = getMemo(route);
298
319
  const protocolFees = getProtocolFees(route.quote);
299
320
  const feeData = await (async () => {
300
321
  if (!sendAddress)
301
322
  return { networkFeeCryptoBaseUnit: undefined, protocolFees };
302
- const { vault } = await solana.getThorTxData({ sellAsset, config, swapperName });
303
323
  const memoInstruction = new TransactionInstruction({
304
324
  keys: [],
305
325
  programId: new PublicKey(SOLANA_MEMO_PROGRAM_ID),
@@ -325,6 +345,11 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
325
345
  route,
326
346
  allowanceContract: '0x0',
327
347
  memo,
348
+ thorchainTransactionMetadata: {
349
+ to: vault,
350
+ memo,
351
+ value: sellAmountCryptoBaseUnit,
352
+ },
328
353
  feeData,
329
354
  });
330
355
  }));
@@ -338,20 +363,15 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
338
363
  return Ok(routes);
339
364
  }
340
365
  case CHAIN_NAMESPACE.Tron: {
366
+ const { vault } = await tron.getThorTxData({ sellAsset, config, swapperName });
341
367
  const maybeRoutes = await Promise.allSettled(perRouteValues.map(async (route) => {
342
368
  const memo = getMemo(route);
343
369
  let networkFeeCryptoBaseUnit = undefined;
344
370
  // Calculate fees for rates when we have a receive address (wallet connected)
345
- if (input.quoteOrRate === 'rate' && input.receiveAddress) {
371
+ if (input.quoteOrRate === 'rate' && input.receiveAddress && vault) {
346
372
  try {
347
373
  const { sellAsset, sellAmountIncludingProtocolFeesCryptoBaseUnit } = input;
348
374
  const contractAddress = contractAddressOrUndefined(sellAsset.assetId);
349
- // Get vault address
350
- const { vault } = await tron.getThorTxData({
351
- sellAsset,
352
- config,
353
- swapperName,
354
- });
355
375
  // Estimate fees using the receive address for accurate energy calculation
356
376
  const tronWeb = new TronWeb({
357
377
  fullHost: deps.config.VITE_TRON_NODE_URL,
@@ -400,6 +420,11 @@ export const getL1RateOrQuote = async (input, deps, streamingInterval, tradeType
400
420
  route,
401
421
  allowanceContract: '0x0',
402
422
  memo,
423
+ thorchainTransactionMetadata: {
424
+ to: vault,
425
+ memo,
426
+ value: sellAmountCryptoBaseUnit,
427
+ },
403
428
  feeData: {
404
429
  networkFeeCryptoBaseUnit,
405
430
  protocolFees: getProtocolFees(route.quote),
@@ -1,7 +1,8 @@
1
+ import type { AssetId } from '@shapeshiftoss/caip';
1
2
  import type { Asset } from '@shapeshiftoss/types';
2
3
  import type { SwapperConfig, SwapperName } from '../../types.js';
3
- export declare const getOutboundFeeInSellAssetThorBaseUnit: (runePerAsset: string, swapperName: SwapperName) => BigNumber;
4
- export declare const getExpectedAffiliateFeeSellAssetThorUnit: (sellAmountCryptoBaseUnit: string, sellAsset: Asset, affiliateBps: string, swapperName: SwapperName) => BigNumber;
4
+ export declare const getOutboundFeeSellAssetThorBaseUnit: (runePerAsset: string, sellAssetId: AssetId, swapperName: SwapperName) => BigNumber;
5
+ export declare const getExpectedAffiliateFeeSellAssetThorBaseUnit: (sellAmountCryptoBaseUnit: string, sellAsset: Asset, affiliateBps: string, swapperName: SwapperName) => BigNumber;
5
6
  export declare const getThresholdedAffiliateBps: ({ sellAsset, affiliateBps, sellAmountCryptoBaseUnit, config, swapperName, }: {
6
7
  sellAsset: Asset;
7
8
  affiliateBps: string;
@@ -1,21 +1,28 @@
1
- import { bn, convertBasisPointsToDecimalPercentage, convertPrecision } from '@shapeshiftoss/utils';
2
- import { getMidgardUrl, getNativeFee, getNativePrecision, getPoolAssetId, isNativeAsset, thorService, } from '../index.js';
3
- export const getOutboundFeeInSellAssetThorBaseUnit = (runePerAsset, swapperName) => {
4
- return bn(getNativeFee(swapperName)).dividedBy(runePerAsset);
1
+ import { convertBasisPointsToDecimalPercentage, convertPrecision } from '@shapeshiftoss/utils';
2
+ import { getMidgardUrl, getNativeFee, getNativePrecision, getPoolAssetId, getSwapperNativeAssetId, isNativeAsset, thorService, } from '../index.js';
3
+ // Convert native fee to sell asset's native precision before dividing by `assetPrice`.
4
+ // MAYA's CACAO is 10-dec but pool assets are 8-dec — skip this and the result is 100x off.
5
+ export const getOutboundFeeSellAssetThorBaseUnit = (runePerAsset, sellAssetId, swapperName) => {
6
+ const nativeFeeSellAssetThorBaseUnit = convertPrecision({
7
+ value: getNativeFee(swapperName),
8
+ inputExponent: getNativePrecision(getSwapperNativeAssetId(swapperName), swapperName),
9
+ outputExponent: getNativePrecision(sellAssetId, swapperName),
10
+ });
11
+ return nativeFeeSellAssetThorBaseUnit.dividedBy(runePerAsset);
5
12
  };
6
- export const getExpectedAffiliateFeeSellAssetThorUnit = (sellAmountCryptoBaseUnit, sellAsset, affiliateBps, swapperName) => {
7
- const sellAmountThorUnit = convertPrecision({
13
+ export const getExpectedAffiliateFeeSellAssetThorBaseUnit = (sellAmountCryptoBaseUnit, sellAsset, affiliateBps, swapperName) => {
14
+ const sellAmountThorBaseUnit = convertPrecision({
8
15
  value: sellAmountCryptoBaseUnit,
9
16
  inputExponent: sellAsset.precision,
10
17
  outputExponent: getNativePrecision(sellAsset.assetId, swapperName),
11
18
  });
12
19
  const affiliatePercent = convertBasisPointsToDecimalPercentage(affiliateBps);
13
- return sellAmountThorUnit.times(affiliatePercent);
20
+ return sellAmountThorBaseUnit.times(affiliatePercent);
14
21
  };
15
22
  // don't apply an affiliate fee if it's below the outbound fee for the inbound pool
16
23
  export const getThresholdedAffiliateBps = async ({ sellAsset, affiliateBps, sellAmountCryptoBaseUnit, config, swapperName, }) => {
17
24
  const midgardUrl = getMidgardUrl(config, swapperName);
18
- const outboundFeeSellAssetThorUnit = await (async () => {
25
+ const outboundFeeSellAssetThorBaseUnit = await (async () => {
19
26
  if (isNativeAsset(sellAsset.assetId, swapperName))
20
27
  return getNativeFee(swapperName);
21
28
  const sellPoolId = getPoolAssetId({ assetId: sellAsset.assetId, swapperName });
@@ -24,11 +31,11 @@ export const getThresholdedAffiliateBps = async ({ sellAsset, affiliateBps, sell
24
31
  if (res.isErr())
25
32
  throw res.unwrapErr();
26
33
  const pool = res.unwrap().data;
27
- // calculate the rune outbound fee denominated in the sell asset, in native units
28
- return getOutboundFeeInSellAssetThorBaseUnit(pool.assetPrice, swapperName);
34
+ // calculate the rune outbound fee denominated in the sell asset, in thor base units
35
+ return getOutboundFeeSellAssetThorBaseUnit(pool.assetPrice, sellAsset.assetId, swapperName);
29
36
  })();
30
- // calculate the expected affiliate fee, in native units
31
- const expectedAffiliateFeeSellAssetThorUnit = getExpectedAffiliateFeeSellAssetThorUnit(sellAmountCryptoBaseUnit, sellAsset, affiliateBps, swapperName);
32
- const isAffiliateFeeBelowOutboundFee = expectedAffiliateFeeSellAssetThorUnit.lte(outboundFeeSellAssetThorUnit);
37
+ // calculate the expected affiliate fee, in thor base units
38
+ const expectedAffiliateFeeSellAssetThorBaseUnit = getExpectedAffiliateFeeSellAssetThorBaseUnit(sellAmountCryptoBaseUnit, sellAsset, affiliateBps, swapperName);
39
+ const isAffiliateFeeBelowOutboundFee = expectedAffiliateFeeSellAssetThorBaseUnit.lte(outboundFeeSellAssetThorBaseUnit);
33
40
  return isAffiliateFeeBelowOutboundFee ? '0' : affiliateBps;
34
41
  };
@@ -5,7 +5,7 @@ import { describe, expect, it, vi } from 'vitest';
5
5
  import { ETH } from '../../swappers/utils/test-data/index.js';
6
6
  import { SwapperName } from '../../types.js';
7
7
  import { thorService } from '../service.js';
8
- import { getExpectedAffiliateFeeSellAssetThorUnit, getOutboundFeeInSellAssetThorBaseUnit, getThresholdedAffiliateBps, } from './getThresholdedAffiliateBps.js';
8
+ import { getExpectedAffiliateFeeSellAssetThorBaseUnit, getOutboundFeeSellAssetThorBaseUnit, getThresholdedAffiliateBps, } from './getThresholdedAffiliateBps.js';
9
9
  const mockedThorService = vi.mocked(thorService);
10
10
  const mocks = vi.hoisted(() => ({
11
11
  get: vi.fn(),
@@ -24,18 +24,24 @@ vi.mock('../service', () => {
24
24
  thorService: mockAxios.default.create(),
25
25
  };
26
26
  });
27
- describe('getOutboundFeeInSellAssetThorBaseUnit', () => {
27
+ describe('getOutboundFeeSellAssetThorBaseUnit', () => {
28
28
  it('should return 0.02 rune denominated in the target asset, in thor units', () => {
29
29
  const assetPricePrecision = '4.00000'; // 1 token is 4x as valuable as 1 rune
30
- expect(getOutboundFeeInSellAssetThorBaseUnit(assetPricePrecision, SwapperName.Thorchain).toNumber()).toEqual(Number(thorchain.NATIVE_FEE) / 4);
30
+ expect(getOutboundFeeSellAssetThorBaseUnit(assetPricePrecision, ETH.assetId, SwapperName.Thorchain).toNumber()).toEqual(Number(thorchain.NATIVE_FEE) / 4);
31
+ });
32
+ it('should scale CACAO 10-dec native fee down to non-CACAO 8-dec sell asset precision on MAYA', () => {
33
+ // 1 eth = 100 cacao, NATIVE_FEE = 2e9 (10-dec CACAO = 0.2 CACAO)
34
+ // 0.2 CACAO / 100 (CACAO/ETH) = 0.002 ETH = 200_000 at 8-dec ETH
35
+ const assetPrice = '100';
36
+ expect(getOutboundFeeSellAssetThorBaseUnit(assetPrice, ETH.assetId, SwapperName.Mayachain).toNumber()).toEqual(200_000);
31
37
  });
32
38
  });
33
- describe('getExpectedAffiliateFeeSellAssetThorUnit', () => {
39
+ describe('getExpectedAffiliateFeeSellAssetThorBaseUnit', () => {
34
40
  it('should return the correct affiliate fee in thor base units', () => {
35
41
  const sellAmountCryptoBaseUnit = '1000000000000000000'; // 1 eth
36
42
  const affiliateBps = '35';
37
43
  const sellAsset = ETH;
38
- const result = getExpectedAffiliateFeeSellAssetThorUnit(sellAmountCryptoBaseUnit, sellAsset, affiliateBps, SwapperName.Thorchain);
44
+ const result = getExpectedAffiliateFeeSellAssetThorBaseUnit(sellAmountCryptoBaseUnit, sellAsset, affiliateBps, SwapperName.Thorchain);
39
45
  const expectation = bn('100000000').times('0.0035').toFixed(0);
40
46
  expect(result.toFixed(0)).toEqual(expectation);
41
47
  });
@@ -43,7 +49,7 @@ describe('getExpectedAffiliateFeeSellAssetThorUnit', () => {
43
49
  const sellAmountCryptoBaseUnit = '1000000000000000000'; // 1 eth
44
50
  const affiliateBps = '0';
45
51
  const sellAsset = ETH;
46
- const result = getExpectedAffiliateFeeSellAssetThorUnit(sellAmountCryptoBaseUnit, sellAsset, affiliateBps, SwapperName.Thorchain);
52
+ const result = getExpectedAffiliateFeeSellAssetThorBaseUnit(sellAmountCryptoBaseUnit, sellAsset, affiliateBps, SwapperName.Thorchain);
47
53
  const expectation = '0';
48
54
  expect(result.toFixed(0)).toEqual(expectation);
49
55
  });
@@ -23,6 +23,7 @@ export declare const getDaemonUrl: (config: SwapperConfig, swapperName: SwapperN
23
23
  export declare const getMidgardUrl: (config: SwapperConfig, swapperName: SwapperName) => string;
24
24
  export declare const isNativeAsset: (assetId: AssetId, swapperName: SwapperName) => boolean;
25
25
  export declare const getNativePrecision: (assetId: AssetId, swapperName: SwapperName) => 8 | 10;
26
+ export declare const getSwapperNativeAssetId: (swapperName: SwapperName) => AssetId;
26
27
  export declare const getNativeFee: (swapperName: SwapperName) => "2000000" | "2000000000";
27
28
  export declare const getAffiliate: (swapperName: SwapperName) => "ss" | "ssmaya";
28
29
  export declare const getPoolAssetId: ({ assetId, swapperName, }: {
@@ -1,4 +1,4 @@
1
- import { mayachainAssetId, mayachainChainId, thorchainChainId } from '@shapeshiftoss/caip';
1
+ import { mayachainAssetId, mayachainChainId, thorchainAssetId, thorchainChainId, } from '@shapeshiftoss/caip';
2
2
  import * as adapters from '@shapeshiftoss/chain-adapters';
3
3
  import { assetIdToMayaPoolAssetId, CACAO_PRECISION, isCacao, MAYACHAIN_AFFILIATE_NAME, MAYACHAIN_PRECISION, MAYACHAIN_STREAM_SWAP_SOURCE, } from '../swappers/MayachainSwapper/index.js';
4
4
  import { assetIdToThorPoolAssetId, isRune, THORCHAIN_AFFILIATE_NAME, THORCHAIN_LONGTAIL_STREAMING_SWAP_SOURCE, THORCHAIN_LONGTAIL_SWAP_SOURCE, THORCHAIN_PRECISION, THORCHAIN_STREAM_SWAP_SOURCE, } from '../swappers/ThorchainSwapper/index.js';
@@ -69,6 +69,16 @@ export const getNativePrecision = (assetId, swapperName) => {
69
69
  throw new Error(`Invalid swapper: ${swapperName}`);
70
70
  }
71
71
  };
72
+ export const getSwapperNativeAssetId = (swapperName) => {
73
+ switch (swapperName) {
74
+ case SwapperName.Thorchain:
75
+ return thorchainAssetId;
76
+ case SwapperName.Mayachain:
77
+ return mayachainAssetId;
78
+ default:
79
+ throw new Error(`Invalid swapper: ${swapperName}`);
80
+ }
81
+ };
72
82
  export const getNativeFee = (swapperName) => {
73
83
  switch (swapperName) {
74
84
  case SwapperName.Thorchain:
@@ -327,6 +327,12 @@ export type TradeQuoteStep = {
327
327
  thorchainSpecific?: {
328
328
  maxStreamingQuantity?: number;
329
329
  };
330
+ thorchainTransactionMetadata?: {
331
+ to: string;
332
+ data?: string;
333
+ value?: string;
334
+ memo?: string;
335
+ };
330
336
  relayTransactionMetadata?: RelayTransactionMetadata;
331
337
  butterSwapTransactionMetadata?: {
332
338
  to: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshiftoss/swapper",
3
- "version": "17.7.1",
3
+ "version": "17.7.3",
4
4
  "repository": "https://github.com/shapeshift/web",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,8 +52,8 @@
52
52
  "@shapeshiftoss/caip": "^8.16.7",
53
53
  "@shapeshiftoss/chain-adapters": "^11.3.9",
54
54
  "@shapeshiftoss/contracts": "^1.0.5-coderabbit-fix.2",
55
- "@shapeshiftoss/hdwallet-core": "^1.62.41",
56
55
  "@shapeshiftoss/types": "^8.6.7",
56
+ "@shapeshiftoss/hdwallet-core": "^1.62.41",
57
57
  "@shapeshiftoss/unchained-client": "^10.14.10",
58
58
  "@shapeshiftoss/utils": "^1.0.5"
59
59
  },