@shapeshiftoss/swapper 18.1.0 → 19.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 (121) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/swappers/AcrossSwapper/constant.js +2 -1
  3. package/dist/cjs/swappers/AcrossSwapper/endpoints.js +1 -1
  4. package/dist/cjs/swappers/AcrossSwapper/getTradeQuote/getTradeQuote.js +2 -1
  5. package/dist/cjs/swappers/AcrossSwapper/utils/acrossService.d.ts +6 -3
  6. package/dist/cjs/swappers/AcrossSwapper/utils/acrossService.js +5 -1
  7. package/dist/cjs/swappers/AcrossSwapper/utils/fetchAcrossTrade.js +1 -1
  8. package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossTradeContext.d.ts +1 -0
  9. package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossTradeContext.js +1 -0
  10. package/dist/cjs/swappers/ArbitrumBridgeSwapper/getTradeQuote/getTradeQuote.js +2 -0
  11. package/dist/cjs/swappers/AvnuSwapper/swapperApi/getTradeQuote.js +3 -1
  12. package/dist/cjs/swappers/AvnuSwapper/utils/getAvnuTradeContext.d.ts +1 -0
  13. package/dist/cjs/swappers/AvnuSwapper/utils/getAvnuTradeContext.js +1 -0
  14. package/dist/cjs/swappers/BebopSwapper/getBebopSolanaTradeQuote/getBebopSolanaTradeQuote.js +5 -2
  15. package/dist/cjs/swappers/BebopSwapper/getBebopTradeQuote/getBebopTradeQuote.js +2 -1
  16. package/dist/cjs/swappers/BebopSwapper/types.d.ts +2 -2
  17. package/dist/cjs/swappers/BebopSwapper/types.js +2 -0
  18. package/dist/cjs/swappers/BebopSwapper/utils/getBebopTradeContext.d.ts +1 -0
  19. package/dist/cjs/swappers/BebopSwapper/utils/getBebopTradeContext.js +1 -0
  20. package/dist/cjs/swappers/BebopSwapper/utils/helpers.d.ts +1 -1
  21. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +2 -0
  22. package/dist/cjs/swappers/ButterSwap/swapperApi/getTradeQuote.js +2 -0
  23. package/dist/cjs/swappers/ButterSwap/utils/helpers.js +10 -8
  24. package/dist/cjs/swappers/CetusSwapper/swapperApi/getTradeQuote.js +2 -0
  25. package/dist/cjs/swappers/ChainflipSwapper/constants.d.ts +1 -0
  26. package/dist/cjs/swappers/ChainflipSwapper/constants.js +3 -1
  27. package/dist/cjs/swappers/ChainflipSwapper/swapperApi/getTradeQuote.js +2 -0
  28. package/dist/cjs/swappers/CowSwapper/getCowSwapTradeQuote/getCowSwapTradeQuote.js +1 -0
  29. package/dist/cjs/swappers/DebridgeSwapper/constant.js +10 -8
  30. package/dist/cjs/swappers/DebridgeSwapper/getTradeQuote/getTradeQuote.js +2 -0
  31. package/dist/cjs/swappers/NearIntentsSwapper/endpoints.js +3 -1
  32. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +7 -0
  33. package/dist/cjs/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.js +11 -0
  34. package/dist/cjs/swappers/RelaySwapper/constant.js +4 -3
  35. package/dist/cjs/swappers/RelaySwapper/endpoints.js +6 -2
  36. package/dist/cjs/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +2 -0
  37. package/dist/cjs/swappers/RelaySwapper/utils/fetchRelayTrade.js +1 -1
  38. package/dist/cjs/swappers/RelaySwapper/utils/getLatestRelayStatusMessage.js +3 -1
  39. package/dist/cjs/swappers/RelaySwapper/utils/notifyTransactionIndexing.js +1 -1
  40. package/dist/cjs/swappers/RelaySwapper/utils/relayService.d.ts +6 -3
  41. package/dist/cjs/swappers/RelaySwapper/utils/relayService.js +3 -1
  42. package/dist/cjs/swappers/RelaySwapper/utils/relayTokenToAssetId.js +5 -0
  43. package/dist/cjs/swappers/RelaySwapper/utils/types.d.ts +2 -2
  44. package/dist/cjs/swappers/StonfiSwapper/endpoints.js +40 -14
  45. package/dist/cjs/swappers/StonfiSwapper/swapperApi/getTradeQuote.js +2 -0
  46. package/dist/cjs/swappers/SunioSwapper/getSunioTradeQuote/getSunioTradeQuote.js +2 -0
  47. package/dist/cjs/swappers/ThorchainSwapper/getTradeQuote/getTradeQuote.test.js +2 -0
  48. package/dist/cjs/swappers/ThorchainSwapper/utils/getLongtailQuote.js +2 -0
  49. package/dist/cjs/swappers/ZrxSwapper/getZrxTradeQuote/getZrxTradeQuote.js +1 -0
  50. package/dist/cjs/swappers/ZrxSwapper/types.d.ts +1 -1
  51. package/dist/cjs/swappers/ZrxSwapper/types.js +1 -0
  52. package/dist/cjs/swappers/ZrxSwapper/utils/constants.js +1 -0
  53. package/dist/cjs/swappers/ZrxSwapper/utils/helpers.d.ts +1 -1
  54. package/dist/cjs/swappers/ZrxSwapper/utils/helpers.js +5 -0
  55. package/dist/cjs/types.d.ts +3 -0
  56. package/dist/cjs/utils/helpers.d.ts +2 -0
  57. package/dist/cjs/utils/helpers.js +14 -1
  58. package/dist/cjs/utils/helpers.test.js +17 -0
  59. package/dist/cjs/utils/test-data/setupSwapQuote.js +1 -0
  60. package/dist/cjs/utils/thorchain/getThorL1TradeQuote.js +3 -0
  61. package/dist/esm/.tsbuildinfo +1 -1
  62. package/dist/esm/swappers/AcrossSwapper/constant.js +4 -3
  63. package/dist/esm/swappers/AcrossSwapper/endpoints.js +2 -2
  64. package/dist/esm/swappers/AcrossSwapper/getTradeQuote/getTradeQuote.js +2 -1
  65. package/dist/esm/swappers/AcrossSwapper/utils/acrossService.d.ts +6 -3
  66. package/dist/esm/swappers/AcrossSwapper/utils/acrossService.js +3 -0
  67. package/dist/esm/swappers/AcrossSwapper/utils/fetchAcrossTrade.js +2 -2
  68. package/dist/esm/swappers/AcrossSwapper/utils/getAcrossTradeContext.d.ts +1 -0
  69. package/dist/esm/swappers/AcrossSwapper/utils/getAcrossTradeContext.js +2 -1
  70. package/dist/esm/swappers/ArbitrumBridgeSwapper/getTradeQuote/getTradeQuote.js +2 -0
  71. package/dist/esm/swappers/AvnuSwapper/swapperApi/getTradeQuote.js +3 -1
  72. package/dist/esm/swappers/AvnuSwapper/utils/getAvnuTradeContext.d.ts +1 -0
  73. package/dist/esm/swappers/AvnuSwapper/utils/getAvnuTradeContext.js +2 -1
  74. package/dist/esm/swappers/BebopSwapper/getBebopSolanaTradeQuote/getBebopSolanaTradeQuote.js +3 -0
  75. package/dist/esm/swappers/BebopSwapper/getBebopTradeQuote/getBebopTradeQuote.js +2 -1
  76. package/dist/esm/swappers/BebopSwapper/types.d.ts +2 -2
  77. package/dist/esm/swappers/BebopSwapper/types.js +2 -0
  78. package/dist/esm/swappers/BebopSwapper/utils/getBebopTradeContext.d.ts +1 -0
  79. package/dist/esm/swappers/BebopSwapper/utils/getBebopTradeContext.js +2 -1
  80. package/dist/esm/swappers/BebopSwapper/utils/helpers.d.ts +1 -1
  81. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +2 -0
  82. package/dist/esm/swappers/ButterSwap/swapperApi/getTradeQuote.js +2 -0
  83. package/dist/esm/swappers/ButterSwap/utils/helpers.js +10 -8
  84. package/dist/esm/swappers/CetusSwapper/swapperApi/getTradeQuote.js +2 -0
  85. package/dist/esm/swappers/ChainflipSwapper/constants.d.ts +1 -0
  86. package/dist/esm/swappers/ChainflipSwapper/constants.js +2 -0
  87. package/dist/esm/swappers/ChainflipSwapper/swapperApi/getTradeQuote.js +2 -0
  88. package/dist/esm/swappers/CowSwapper/getCowSwapTradeQuote/getCowSwapTradeQuote.js +1 -0
  89. package/dist/esm/swappers/DebridgeSwapper/constant.js +11 -9
  90. package/dist/esm/swappers/DebridgeSwapper/getTradeQuote/getTradeQuote.js +2 -0
  91. package/dist/esm/swappers/NearIntentsSwapper/endpoints.js +3 -1
  92. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +7 -0
  93. package/dist/esm/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.js +12 -1
  94. package/dist/esm/swappers/RelaySwapper/constant.js +6 -5
  95. package/dist/esm/swappers/RelaySwapper/endpoints.js +7 -3
  96. package/dist/esm/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +2 -0
  97. package/dist/esm/swappers/RelaySwapper/utils/fetchRelayTrade.js +2 -2
  98. package/dist/esm/swappers/RelaySwapper/utils/getLatestRelayStatusMessage.js +3 -1
  99. package/dist/esm/swappers/RelaySwapper/utils/notifyTransactionIndexing.js +2 -2
  100. package/dist/esm/swappers/RelaySwapper/utils/relayService.d.ts +6 -3
  101. package/dist/esm/swappers/RelaySwapper/utils/relayService.js +1 -0
  102. package/dist/esm/swappers/RelaySwapper/utils/relayTokenToAssetId.js +5 -0
  103. package/dist/esm/swappers/RelaySwapper/utils/types.d.ts +2 -2
  104. package/dist/esm/swappers/StonfiSwapper/endpoints.js +41 -15
  105. package/dist/esm/swappers/StonfiSwapper/swapperApi/getTradeQuote.js +2 -0
  106. package/dist/esm/swappers/SunioSwapper/getSunioTradeQuote/getSunioTradeQuote.js +2 -0
  107. package/dist/esm/swappers/ThorchainSwapper/getTradeQuote/getTradeQuote.test.js +2 -0
  108. package/dist/esm/swappers/ThorchainSwapper/utils/getLongtailQuote.js +2 -0
  109. package/dist/esm/swappers/ZrxSwapper/getZrxTradeQuote/getZrxTradeQuote.js +2 -1
  110. package/dist/esm/swappers/ZrxSwapper/types.d.ts +1 -1
  111. package/dist/esm/swappers/ZrxSwapper/types.js +1 -0
  112. package/dist/esm/swappers/ZrxSwapper/utils/constants.js +1 -0
  113. package/dist/esm/swappers/ZrxSwapper/utils/helpers.d.ts +1 -1
  114. package/dist/esm/swappers/ZrxSwapper/utils/helpers.js +5 -0
  115. package/dist/esm/types.d.ts +3 -0
  116. package/dist/esm/utils/helpers.d.ts +2 -0
  117. package/dist/esm/utils/helpers.js +12 -0
  118. package/dist/esm/utils/helpers.test.js +18 -1
  119. package/dist/esm/utils/test-data/setupSwapQuote.js +1 -0
  120. package/dist/esm/utils/thorchain/getThorL1TradeQuote.js +3 -0
  121. package/package.json +5 -5
@@ -1,5 +1,6 @@
1
1
  import { Err, Ok } from '@sniptt/monads';
2
2
  import { assertQuoteAddresses } from '../../../utils/index.js';
3
+ import { FALLBACK_QUOTE_DEADLINE_MS } from '../../../utils/helpers.js';
3
4
  import { getRelayStepData } from '../utils/getRelayStepData.js';
4
5
  import { getRelayTradeContext } from '../utils/getRelayTradeContext.js';
5
6
  export const getTradeQuote = async (input, deps, relayChainMap) => {
@@ -42,6 +43,7 @@ export const getTradeQuote = async (input, deps, relayChainMap) => {
42
43
  const tradeQuote = {
43
44
  ...tradeCommon,
44
45
  quoteOrRate: 'quote',
46
+ deadline: Date.now() + FALLBACK_QUOTE_DEADLINE_MS,
45
47
  receiveAddress,
46
48
  steps,
47
49
  };
@@ -1,4 +1,4 @@
1
- import { relayService } from './relayService.js';
1
+ import { getRelayRequestConfig, relayService } from './relayService.js';
2
2
  export const fetchRelayTrade = async (params, config) => {
3
- return await relayService.post(`${config.VITE_RELAY_API_URL}/quote/v2`, params);
3
+ return await relayService.post(`${config.VITE_RELAY_API_URL}/quote/v2`, params, getRelayRequestConfig(config));
4
4
  };
@@ -7,10 +7,12 @@ export const getLatestRelayStatusMessage = (status) => {
7
7
  case statusValue === 'delayed':
8
8
  return RelayStatusMessage.Retrying;
9
9
  case statusValue === 'pending':
10
+ case statusValue === 'depositing':
11
+ case statusValue === 'submitted':
10
12
  return RelayStatusMessage.DepositDetected;
11
13
  case statusValue === 'success':
12
14
  return RelayStatusMessage.SwapComplete;
13
- case statusValue === 'failed':
15
+ case statusValue === 'failure':
14
16
  return RelayStatusMessage.SwapFailed;
15
17
  default:
16
18
  return 'Unknown status';
@@ -1,4 +1,4 @@
1
- import { relayService } from './relayService.js';
1
+ import { getRelayRequestConfig, relayService } from './relayService.js';
2
2
  export const notifyTransactionIndexing = async (params, config) => {
3
- return await relayService.post(`${config.VITE_RELAY_API_URL}/transactions/single`, params);
3
+ return await relayService.post(`${config.VITE_RELAY_API_URL}/transactions/single`, params, getRelayRequestConfig(config));
4
4
  };
@@ -1,5 +1,8 @@
1
+ import type { AxiosRequestConfig } from 'axios';
2
+ import type { SwapperConfig } from '../../../types.js';
1
3
  export declare const relayService: {
2
- get: <T = any>(url: string, config?: import("axios").AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T, any, {}>, import("../../../index.js").SwapErrorRight>>;
3
- post: <T_1 = any>(url: string, data: any, config?: import("axios").AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T_1, any, {}>, import("../../../index.js").SwapErrorRight>>;
4
- delete: <T_2 = any>(url: string, data: any, config?: import("axios").AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T_2, any, {}>, import("../../../index.js").SwapErrorRight>>;
4
+ get: <T = any>(url: string, config?: AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T, any, {}>, import("../../../types.js").SwapErrorRight>>;
5
+ post: <T_1 = any>(url: string, data: any, config?: AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T_1, any, {}>, import("../../../types.js").SwapErrorRight>>;
6
+ delete: <T_2 = any>(url: string, data: any, config?: AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T_2, any, {}>, import("../../../types.js").SwapErrorRight>>;
5
7
  };
8
+ export declare const getRelayRequestConfig: (config: SwapperConfig) => AxiosRequestConfig | undefined;
@@ -10,3 +10,4 @@ const axiosConfig = {
10
10
  };
11
11
  const relayServiceBase = createCache(maxAgeMillis, cachedUrls, axiosConfig);
12
12
  export const relayService = makeSwapperAxiosServiceMonadic(relayServiceBase);
13
+ export const getRelayRequestConfig = (config) => config.VITE_RELAY_API_KEY ? { headers: { 'x-api-key': config.VITE_RELAY_API_KEY } } : undefined;
@@ -229,6 +229,11 @@ export const relayTokenToAssetId = (relayToken) => {
229
229
  assetReference: ASSET_REFERENCE.Abstract,
230
230
  assetNamespace: ASSET_NAMESPACE.slip44,
231
231
  };
232
+ case CHAIN_REFERENCE.RobinhoodMainnet:
233
+ return {
234
+ assetReference: ASSET_REFERENCE.Robinhood,
235
+ assetNamespace: ASSET_NAMESPACE.slip44,
236
+ };
232
237
  default:
233
238
  throw Error(`chainId '${relayToken.chainId}' not supported`);
234
239
  }
@@ -11,11 +11,11 @@ export type RelayMetadata = {
11
11
  data?: string;
12
12
  };
13
13
  export type RelayStatus = {
14
- status: 'success' | 'failed' | 'pending' | 'refund' | 'delayed' | 'waiting';
14
+ status: 'success' | 'failure' | 'pending' | 'submitted' | 'depositing' | 'refund' | 'delayed' | 'waiting';
15
15
  details?: string;
16
16
  inTxHashes: string[];
17
17
  txHashes: string[];
18
- time: number;
18
+ updatedAt: number;
19
19
  originChainId: number;
20
20
  destinationChainId: number;
21
21
  };
@@ -1,5 +1,5 @@
1
1
  import { toAddressNList } from '@shapeshiftoss/chain-adapters';
2
- import { TxStatus } from '@shapeshiftoss/unchained-client';
2
+ import { TransferType, TxStatus } from '@shapeshiftoss/unchained-client';
3
3
  import { Blockchain } from '@ston-fi/omniston-sdk';
4
4
  import { createDefaultStatusResponse, getExecutableTradeStep, getSwapMetadata, isExecutableTradeQuote, } from '../../utils/index.js';
5
5
  import { getTradeQuote } from './swapperApi/getTradeQuote.js';
@@ -97,6 +97,20 @@ export const stonfiApi = {
97
97
  }
98
98
  };
99
99
  const { quoteId } = getSwapMetadata(swap.metadata.swapperMetadata, 'stonfi');
100
+ // Settlement precedes toncenter's jetton indexer, and confirmed rows are never re-parsed -
101
+ // hold confirmation until the receive leg is visible so the confirmed-time parse and upsert
102
+ // carries both legs of the swap
103
+ const hasVisibleReceiveLeg = async () => {
104
+ const adapter = assertGetTonChainAdapter(swap.sellAsset.chainId);
105
+ const sellAddress = swap.sellAccountId.split(':')[2] ?? '';
106
+ const addresses = new Set([sellAddress, swap.receiveAddress].filter((address) => Boolean(address)));
107
+ for (const address of addresses) {
108
+ const tx = await adapter.parseTx(sellTxHash, address);
109
+ if (tx.transfers.some(transfer => transfer.type === TransferType.Receive))
110
+ return true;
111
+ }
112
+ return false;
113
+ };
100
114
  try {
101
115
  const tradeStatus = await waitForFirstTradeStatus({
102
116
  quoteId,
@@ -110,14 +124,13 @@ export const stonfiApi = {
110
124
  return checkTxStatusViaChainAdapter();
111
125
  }
112
126
  const statusOneOf = tradeStatus.status;
127
+ // While the trade is in flight the wallet tx may already be confirmed, but the payout leg
128
+ // hasn't landed - confirming here would parse and upsert a trace without the receive, so
129
+ // completion waits for settlement
113
130
  if (statusOneOf.awaitingTransfer ||
114
131
  statusOneOf.transferring ||
115
132
  statusOneOf.swapping ||
116
133
  statusOneOf.receivingFunds) {
117
- const chainStatus = await checkTxStatusViaChainAdapter();
118
- if (chainStatus.status === TxStatus.Confirmed) {
119
- return chainStatus;
120
- }
121
134
  if (statusOneOf.awaitingTransfer) {
122
135
  return {
123
136
  status: TxStatus.Pending,
@@ -149,19 +162,32 @@ export const stonfiApi = {
149
162
  }
150
163
  if (statusOneOf.tradeSettled) {
151
164
  const result = statusOneOf.tradeSettled.result;
152
- if (result === 'TRADE_RESULT_FULLY_FILLED') {
153
- return {
154
- status: TxStatus.Confirmed,
155
- buyTxHash: sellTxHash,
156
- message: undefined,
157
- };
158
- }
159
- if (result === 'TRADE_RESULT_PARTIALLY_FILLED') {
160
- return {
165
+ if (result === 'TRADE_RESULT_FULLY_FILLED' || result === 'TRADE_RESULT_PARTIALLY_FILLED') {
166
+ const settled = {
161
167
  status: TxStatus.Confirmed,
162
168
  buyTxHash: sellTxHash,
163
- message: 'trade.statuses.partiallyFilled',
169
+ message: result === 'TRADE_RESULT_PARTIALLY_FILLED'
170
+ ? 'trade.statuses.partiallyFilled'
171
+ : undefined,
164
172
  };
173
+ try {
174
+ if (await hasVisibleReceiveLeg())
175
+ return settled;
176
+ return {
177
+ status: TxStatus.Pending,
178
+ buyTxHash: undefined,
179
+ message: 'trade.statuses.receivingFunds',
180
+ };
181
+ }
182
+ catch (error) {
183
+ // Indexer/API failure must not block completion
184
+ console.error('[Stonfi] Error verifying settlement receive leg:', {
185
+ sellTxHash,
186
+ result,
187
+ error,
188
+ });
189
+ return settled;
190
+ }
165
191
  }
166
192
  if (result === 'TRADE_RESULT_ABORTED') {
167
193
  return {
@@ -1,5 +1,6 @@
1
1
  import { Err, Ok } from '@sniptt/monads';
2
2
  import { assertQuoteAddresses } from '../../../utils/index.js';
3
+ import { normalizeEpochToMs } from '../../../utils/helpers.js';
3
4
  import { getStonfiStepData } from '../utils/getStonfiStepData.js';
4
5
  import { getStonfiTradeContext } from '../utils/getStonfiTradeContext.js';
5
6
  export const getTradeQuote = async (input, deps) => {
@@ -24,6 +25,7 @@ export const getTradeQuote = async (input, deps) => {
24
25
  const tradeQuote = {
25
26
  ...tradeCommon,
26
27
  quoteOrRate: 'quote',
28
+ deadline: normalizeEpochToMs(stonfiTransactionData.tradeStartDeadline),
27
29
  receiveAddress,
28
30
  steps: [
29
31
  {
@@ -1,5 +1,6 @@
1
1
  import { Err, Ok } from '@sniptt/monads';
2
2
  import { assertQuoteAddresses } from '../../../utils/index.js';
3
+ import { FALLBACK_QUOTE_DEADLINE_MS } from '../../../utils/helpers.js';
3
4
  import { getSunioStepData } from '../utils/getSunioStepData.js';
4
5
  import { getSunioTradeContext } from '../utils/getSunioTradeContext.js';
5
6
  export const getSunioTradeQuote = async (input, deps) => {
@@ -24,6 +25,7 @@ export const getSunioTradeQuote = async (input, deps) => {
24
25
  const tradeQuote = {
25
26
  ...tradeCommon,
26
27
  quoteOrRate: 'quote',
28
+ deadline: Date.now() + FALLBACK_QUOTE_DEADLINE_MS,
27
29
  receiveAddress,
28
30
  steps: [
29
31
  {
@@ -62,6 +62,7 @@ const expectedQuoteResponse = [
62
62
  tradeType: TradeType.L1ToL1,
63
63
  slippageTolerancePercentageDecimal: '0.04357',
64
64
  expiry: 1713710808,
65
+ deadline: 1713710808000,
65
66
  swapperName: SwapperName.Thorchain,
66
67
  steps: [
67
68
  {
@@ -112,6 +113,7 @@ const expectedQuoteResponse = [
112
113
  tradeType: TradeType.L1ToL1,
113
114
  slippageTolerancePercentageDecimal: undefined,
114
115
  expiry: 1713710808,
116
+ deadline: 1713710808000,
115
117
  swapperName: SwapperName.Thorchain,
116
118
  steps: [
117
119
  {
@@ -73,6 +73,8 @@ export const getLongtailToL1Quote = async (input, deps, streamingInterval, swapp
73
73
  const { data, transactionData, networkFeeCryptoBaseUnit } = maybeStepData.unwrap();
74
74
  return Ok({
75
75
  ...quote,
76
+ // The aggregator swapIn deadline is tighter than the daemon quote expiry
77
+ deadline: Math.min(quote.deadline, Number(deadline) * 1000),
76
78
  data: data ?? quote.data,
77
79
  // This logic will need to be updated to support multi-hop, if that's ever implemented for THORChain
78
80
  steps: quote.steps.map(s => ({
@@ -2,7 +2,7 @@ import { Err, Ok } from '@sniptt/monads';
2
2
  import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants.js';
3
3
  import { SwapperName, TradeQuoteError } from '../../../types.js';
4
4
  import { assertQuoteAddresses, makeSwapErrorRight } from '../../../utils/index.js';
5
- import { isNativeEvmAsset } from '../../../utils/helpers.js';
5
+ import { FALLBACK_QUOTE_DEADLINE_MS, isNativeEvmAsset } from '../../../utils/helpers.js';
6
6
  import { fetchZrxQuote } from '../utils/fetchFromZrx.js';
7
7
  import { getZrxStepData } from '../utils/getZrxStepData.js';
8
8
  import { getZrxTradeContext } from '../utils/getZrxTradeContext.js';
@@ -76,6 +76,7 @@ export const getZrxTradeQuote = async (input, deps) => {
76
76
  const tradeQuote = {
77
77
  ...tradeCommon,
78
78
  quoteOrRate: 'quote',
79
+ deadline: Date.now() + FALLBACK_QUOTE_DEADLINE_MS,
79
80
  receiveAddress,
80
81
  steps: [
81
82
  {
@@ -3,7 +3,7 @@ import type { Address, TypedData } from 'viem';
3
3
  import type { GetEvmTradeQuoteInput, GetEvmTradeRateInput } from '../../types.js';
4
4
  export type ZrxTradeQuoteInput = GetEvmTradeQuoteInput;
5
5
  export type ZrxTradeRateInput = GetEvmTradeRateInput;
6
- export declare const zrxSupportedChainIds: readonly [KnownChainIds.EthereumMainnet, KnownChainIds.AvalancheMainnet, KnownChainIds.OptimismMainnet, KnownChainIds.BnbSmartChainMainnet, KnownChainIds.PolygonMainnet, KnownChainIds.ArbitrumMainnet, KnownChainIds.BaseMainnet];
6
+ export declare const zrxSupportedChainIds: readonly [KnownChainIds.EthereumMainnet, KnownChainIds.AvalancheMainnet, KnownChainIds.OptimismMainnet, KnownChainIds.BnbSmartChainMainnet, KnownChainIds.PolygonMainnet, KnownChainIds.ArbitrumMainnet, KnownChainIds.BaseMainnet, KnownChainIds.RobinhoodMainnet];
7
7
  export type ZrxSupportedChainId = (typeof zrxSupportedChainIds)[number];
8
8
  type ZrxFee = {
9
9
  amount: string;
@@ -7,4 +7,5 @@ export const zrxSupportedChainIds = [
7
7
  KnownChainIds.PolygonMainnet,
8
8
  KnownChainIds.ArbitrumMainnet,
9
9
  KnownChainIds.BaseMainnet,
10
+ KnownChainIds.RobinhoodMainnet,
10
11
  ];
@@ -18,6 +18,7 @@ export const ZRX_SUPPORTED_CHAINIDS = Object.freeze([
18
18
  KnownChainIds.PolygonMainnet,
19
19
  KnownChainIds.ArbitrumMainnet,
20
20
  KnownChainIds.BaseMainnet,
21
+ KnownChainIds.RobinhoodMainnet,
21
22
  ]);
22
23
  // https://0x.org/docs/developer-resources/faqs-and-troubleshooting
23
24
  export const ZRX_NATIVE_ASSET_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
@@ -6,7 +6,7 @@ import type { SwapErrorRight } from '../../../types.js';
6
6
  import type { ZrxFees, ZrxPriceResponse } from '../types.js';
7
7
  export declare const assetIdToZrxToken: (assetId: AssetId) => string;
8
8
  export declare const zrxTokenToAssetId: (token: string, chainId: ChainId) => AssetId;
9
- export declare const isSupportedChainId: (chainId: ChainId) => chainId is KnownChainIds.EthereumMainnet | KnownChainIds.AvalancheMainnet | KnownChainIds.OptimismMainnet | KnownChainIds.BnbSmartChainMainnet | KnownChainIds.PolygonMainnet | KnownChainIds.ArbitrumMainnet | KnownChainIds.BaseMainnet;
9
+ export declare const isSupportedChainId: (chainId: ChainId) => chainId is KnownChainIds.EthereumMainnet | KnownChainIds.AvalancheMainnet | KnownChainIds.OptimismMainnet | KnownChainIds.BnbSmartChainMainnet | KnownChainIds.PolygonMainnet | KnownChainIds.ArbitrumMainnet | KnownChainIds.BaseMainnet | KnownChainIds.RobinhoodMainnet;
10
10
  export declare const isWrappedNativeSell: (route: ZrxPriceResponse['route']) => boolean;
11
11
  export declare const assertValidTrade: ({ buyAsset, sellAsset, }: {
12
12
  buyAsset: Asset;
@@ -56,6 +56,11 @@ export const zrxTokenToAssetId = (token, chainId) => {
56
56
  assetReference: ASSET_REFERENCE.Base,
57
57
  assetNamespace: ASSET_NAMESPACE.slip44,
58
58
  };
59
+ case KnownChainIds.RobinhoodMainnet:
60
+ return {
61
+ assetReference: ASSET_REFERENCE.Robinhood,
62
+ assetNamespace: ASSET_NAMESPACE.slip44,
63
+ };
59
64
  default:
60
65
  throw Error(`chainId '${chainId}' not supported`);
61
66
  }
@@ -49,11 +49,13 @@ export type SwapperConfig = {
49
49
  VITE_CHAINFLIP_API_URL: string;
50
50
  VITE_FEATURE_CHAINFLIP_SWAP_DCA: boolean;
51
51
  VITE_RELAY_API_URL: string;
52
+ VITE_RELAY_API_KEY: string;
52
53
  VITE_BEBOP_API_KEY: string;
53
54
  VITE_NEAR_INTENTS_API_KEY: string;
54
55
  VITE_SUI_NODE_URL: string;
55
56
  VITE_ACROSS_API_URL: string;
56
57
  VITE_ACROSS_INTEGRATOR_ID: string;
58
+ VITE_ACROSS_API_KEY: string;
57
59
  VITE_DEBRIDGE_API_URL: string;
58
60
  VITE_BOB_GATEWAY_API_KEY: string;
59
61
  };
@@ -439,6 +441,7 @@ export type TradeQuote = TradeQuoteBase & {
439
441
  } & {
440
442
  quoteOrRate: 'quote';
441
443
  receiveAddress: string;
444
+ deadline: number;
442
445
  };
443
446
  export type MultiHopTradeQuote = TradeQuote & {
444
447
  steps: MultiHopTradeQuoteSteps;
@@ -1,3 +1,5 @@
1
1
  import type { AssetId, ChainId } from '@shapeshiftoss/caip';
2
+ export declare const FALLBACK_QUOTE_DEADLINE_MS = 60000;
3
+ export declare const normalizeEpochToMs: (value: number) => number;
2
4
  export declare const isNativeEvmAsset: (assetId: AssetId) => boolean;
3
5
  export declare const getTreasuryAddressFromChainId: (chainId: ChainId) => string;
@@ -1,6 +1,18 @@
1
1
  import { arbitrumAssetId, avalancheAssetId, baseAssetId, bscAssetId, ethAssetId, fromAssetId, gnosisAssetId, katanaAssetId, monadAssetId, optimismAssetId, plasmaAssetId, polygonAssetId, } from '@shapeshiftoss/caip';
2
2
  import { KnownChainIds } from '@shapeshiftoss/types';
3
3
  import { DAO_TREASURY_ARBITRUM, DAO_TREASURY_AVALANCHE, DAO_TREASURY_BASE, DAO_TREASURY_BITCOIN, DAO_TREASURY_BOB, DAO_TREASURY_BSC, DAO_TREASURY_ETHEREUM_MAINNET, DAO_TREASURY_GNOSIS, DAO_TREASURY_HYPEREVM, DAO_TREASURY_MONAD, DAO_TREASURY_OPTIMISM, DAO_TREASURY_POLYGON, DAO_TREASURY_SOLANA, DAO_TREASURY_STARKNET, DAO_TREASURY_TON, isTreasuryChainId, } from '@shapeshiftoss/utils';
4
+ // Deadline for providers without their own expiry - short enough to keep priced amounts honest
5
+ export const FALLBACK_QUOTE_DEADLINE_MS = 60_000;
6
+ // Bands are unambiguous for any realistic date: unix s land ~2e9, ms ~2e12, µs ~2e15, ns ~2e18
7
+ export const normalizeEpochToMs = (value) => {
8
+ if (value < 1e12)
9
+ return value * 1000;
10
+ if (value < 1e15)
11
+ return value;
12
+ if (value < 1e18)
13
+ return Math.floor(value / 1000);
14
+ return Math.floor(value / 1e6);
15
+ };
4
16
  export const isNativeEvmAsset = (assetId) => {
5
17
  const { chainId } = fromAssetId(assetId);
6
18
  switch (chainId) {
@@ -2,7 +2,7 @@ import { thorchainChainId } from '@shapeshiftoss/caip';
2
2
  import { KnownChainIds } from '@shapeshiftoss/types';
3
3
  import { treasuryChainIds } from '@shapeshiftoss/utils';
4
4
  import { describe, expect, it } from 'vitest';
5
- import { getTreasuryAddressFromChainId } from './helpers.js';
5
+ import { getTreasuryAddressFromChainId, normalizeEpochToMs } from './helpers.js';
6
6
  describe('getTreasuryAddressFromChainId', () => {
7
7
  // Affiliate and fee recipient addresses for every swapper flow through here, so pin the values
8
8
  // rather than the wiring - a chain pointing at another chain's treasury misroutes revenue silently
@@ -30,3 +30,20 @@ describe('getTreasuryAddressFromChainId', () => {
30
30
  expect(() => getTreasuryAddressFromChainId(thorchainChainId)).toThrow('[getTreasuryAddressFromChainId] - Unsupported chainId');
31
31
  });
32
32
  });
33
+ describe('normalizeEpochToMs', () => {
34
+ // 2026-08-05T00:00:00Z expressed in each unit
35
+ const epochS = 1785888000;
36
+ const epochMs = epochS * 1000;
37
+ it('converts unix seconds to ms', () => {
38
+ expect(normalizeEpochToMs(epochS)).toBe(epochMs);
39
+ });
40
+ it('passes milliseconds through', () => {
41
+ expect(normalizeEpochToMs(epochMs)).toBe(epochMs);
42
+ });
43
+ it('converts microseconds to ms', () => {
44
+ expect(normalizeEpochToMs(epochMs * 1000)).toBe(epochMs);
45
+ });
46
+ it('converts nanoseconds to ms', () => {
47
+ expect(normalizeEpochToMs(epochMs * 1e6)).toBe(epochMs);
48
+ });
49
+ });
@@ -7,6 +7,7 @@ export const setupQuote = () => {
7
7
  const tradeQuote = {
8
8
  quoteOrRate: 'quote',
9
9
  id: 'foobar',
10
+ deadline: Date.now() + 60_000,
10
11
  receiveAddress: '0x1234',
11
12
  affiliateBps: '0',
12
13
  slippageTolerancePercentageDecimal: '0',
@@ -1,5 +1,6 @@
1
1
  import { Err, Ok } from '@sniptt/monads';
2
2
  import { assertQuoteAddresses, makeTradeStepBuildFailedErr } from '../../utils/index.js';
3
+ import { normalizeEpochToMs } from '../helpers.js';
3
4
  import { getLimitWithManualSlippage } from './getLimitWithManualSlippage/getLimitWithManualSlippage.js';
4
5
  import { getSuccessfulTrades, getThorL1TradeContexts } from './getThorL1TradeContexts.js';
5
6
  import { getThorStepData } from './getThorStepData.js';
@@ -50,6 +51,8 @@ export const getThorL1TradeQuote = async (input, deps, streamingInterval, tradeT
50
51
  const quote = {
51
52
  ...tradeCommon,
52
53
  quoteOrRate: 'quote',
54
+ // The daemon quote expiry scopes the inbound address - sending later risks a rotated vault
55
+ deadline: normalizeEpochToMs(tradeCommon.expiry),
53
56
  memo,
54
57
  receiveAddress,
55
58
  data,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshiftoss/swapper",
3
- "version": "18.1.0",
3
+ "version": "19.0.0",
4
4
  "repository": "https://github.com/shapeshift/web",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -49,14 +49,14 @@
49
49
  "qs": "^6.14.2",
50
50
  "retry-axios": "^2.6.0",
51
51
  "uuid": "^9.0.0",
52
- "viem": "2.43.5",
52
+ "viem": "2.55.11",
53
53
  "@shapeshiftoss/caip": "^8.16.10",
54
- "@shapeshiftoss/chain-adapters": "^11.5.0",
55
- "@shapeshiftoss/contracts": "^1.0.7",
56
54
  "@shapeshiftoss/hdwallet-core": "^1.62.41",
57
55
  "@shapeshiftoss/types": "^9.0.0",
58
56
  "@shapeshiftoss/unchained-client": "^10.14.11",
59
- "@shapeshiftoss/utils": "^1.1.0"
57
+ "@shapeshiftoss/contracts": "^1.0.7",
58
+ "@shapeshiftoss/utils": "^1.1.0",
59
+ "@shapeshiftoss/chain-adapters": "^11.5.1"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/lodash": "^4.14.178",