@shapeshiftoss/swapper 19.0.0 → 20.1.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 (165) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/exactOutputFiltering.test.d.ts +1 -0
  3. package/dist/cjs/exactOutputFiltering.test.js +70 -0
  4. package/dist/cjs/swapper.d.ts +3 -3
  5. package/dist/cjs/swapper.js +29 -6
  6. package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossStepData.d.ts +1 -0
  7. package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossStepData.js +2 -2
  8. package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossTradeContext.js +1 -0
  9. package/dist/cjs/swappers/BebopSwapper/utils/getBebopStepData.d.ts +1 -0
  10. package/dist/cjs/swappers/BebopSwapper/utils/getBebopStepData.js +2 -2
  11. package/dist/cjs/swappers/BebopSwapper/utils/getBebopTradeContext.js +1 -0
  12. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +5 -1
  13. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +11 -2
  14. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.d.ts +2 -1
  15. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.js +2 -1
  16. package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.d.ts +2 -1
  17. package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.js +2 -1
  18. package/dist/cjs/swappers/ChainflipSwapper/ChainflipSwapper.js +1 -0
  19. package/dist/cjs/swappers/ChainflipSwapper/checkTradeStatus.test.d.ts +1 -0
  20. package/dist/cjs/swappers/ChainflipSwapper/checkTradeStatus.test.js +48 -0
  21. package/dist/cjs/swappers/ChainflipSwapper/endpoints.js +5 -2
  22. package/dist/cjs/swappers/ChainflipSwapper/types.d.ts +3 -0
  23. package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeStepData.d.ts +1 -0
  24. package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeStepData.js +2 -2
  25. package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeTradeContext.js +1 -0
  26. package/dist/cjs/swappers/NearIntentsSwapper/NearIntentsSwapper.js +1 -0
  27. package/dist/cjs/swappers/NearIntentsSwapper/checkTradeStatus.test.d.ts +1 -0
  28. package/dist/cjs/swappers/NearIntentsSwapper/checkTradeStatus.test.js +52 -0
  29. package/dist/cjs/swappers/NearIntentsSwapper/constants.d.ts +1 -1
  30. package/dist/cjs/swappers/NearIntentsSwapper/constants.js +4 -3
  31. package/dist/cjs/swappers/NearIntentsSwapper/endpoints.js +4 -1
  32. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.d.ts +2 -1
  33. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +14 -9
  34. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.d.ts +2 -1
  35. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +14 -9
  36. package/dist/cjs/swappers/NearIntentsSwapper/types.d.ts +3 -1
  37. package/dist/cjs/swappers/NearIntentsSwapper/utils/exactOutput.test.d.ts +1 -0
  38. package/dist/cjs/swappers/NearIntentsSwapper/utils/exactOutput.test.js +61 -0
  39. package/dist/cjs/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.d.ts +2 -2
  40. package/dist/cjs/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.js +4 -2
  41. package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.d.ts +5 -5
  42. package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.js +30 -26
  43. package/dist/cjs/swappers/NearIntentsSwapper/utils/quoteDeadline.test.d.ts +1 -0
  44. package/dist/cjs/swappers/NearIntentsSwapper/utils/quoteDeadline.test.js +28 -0
  45. package/dist/cjs/swappers/PortalsSwapper/endpoints.js +51 -47
  46. package/dist/cjs/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.js +1 -1
  47. package/dist/cjs/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.js +1 -1
  48. package/dist/cjs/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.d.ts +0 -1
  49. package/dist/cjs/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.js +3 -6
  50. package/dist/cjs/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.js +6 -3
  51. package/dist/cjs/swappers/PortalsSwapper/utils/fetchSquidStatus.d.ts +0 -1
  52. package/dist/cjs/swappers/PortalsSwapper/utils/fetchSquidStatus.js +1 -8
  53. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.d.ts +1 -0
  54. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.js +16 -8
  55. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.test.d.ts +1 -0
  56. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.test.js +70 -0
  57. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.d.ts +3 -2
  58. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.js +34 -16
  59. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.d.ts +1 -0
  60. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.js +93 -0
  61. package/dist/cjs/swappers/RelaySwapper/endpoints.js +9 -18
  62. package/dist/cjs/swappers/RelaySwapper/getTradeQuote/getTradeQuote.d.ts +2 -1
  63. package/dist/cjs/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +5 -2
  64. package/dist/cjs/swappers/RelaySwapper/getTradeRate/getTradeRate.d.ts +2 -1
  65. package/dist/cjs/swappers/RelaySwapper/getTradeRate/getTradeRate.js +5 -2
  66. package/dist/cjs/swappers/RelaySwapper/utils/getRelayTradeContext.d.ts +2 -2
  67. package/dist/cjs/swappers/RelaySwapper/utils/getRelayTradeContext.js +22 -10
  68. package/dist/cjs/swappers/RelaySwapper/utils/helpers.d.ts +2 -2
  69. package/dist/cjs/swappers/RelaySwapper/utils/relayStatus.d.ts +8 -0
  70. package/dist/cjs/swappers/RelaySwapper/utils/relayStatus.js +39 -0
  71. package/dist/cjs/swappers/RelaySwapper/utils/types.d.ts +18 -1
  72. package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.d.ts +1 -0
  73. package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.js +2 -2
  74. package/dist/cjs/swappers/SunioSwapper/utils/getSunioTradeContext.js +6 -1
  75. package/dist/cjs/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +1 -0
  76. package/dist/cjs/types.d.ts +21 -2
  77. package/dist/cjs/types.js +2 -0
  78. package/dist/cjs/utils/cowswap/index.d.ts +4 -1
  79. package/dist/cjs/utils/cowswap/index.js +5 -1
  80. package/dist/cjs/utils/helpers.d.ts +9 -0
  81. package/dist/cjs/utils/helpers.js +23 -1
  82. package/dist/cjs/utils/helpers.test.js +41 -0
  83. package/dist/esm/.tsbuildinfo +1 -1
  84. package/dist/esm/exactOutputFiltering.test.d.ts +1 -0
  85. package/dist/esm/exactOutputFiltering.test.js +68 -0
  86. package/dist/esm/swapper.d.ts +3 -3
  87. package/dist/esm/swapper.js +29 -6
  88. package/dist/esm/swappers/AcrossSwapper/utils/getAcrossStepData.d.ts +1 -0
  89. package/dist/esm/swappers/AcrossSwapper/utils/getAcrossStepData.js +2 -2
  90. package/dist/esm/swappers/AcrossSwapper/utils/getAcrossTradeContext.js +1 -0
  91. package/dist/esm/swappers/BebopSwapper/utils/getBebopStepData.d.ts +1 -0
  92. package/dist/esm/swappers/BebopSwapper/utils/getBebopStepData.js +2 -2
  93. package/dist/esm/swappers/BebopSwapper/utils/getBebopTradeContext.js +1 -0
  94. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +5 -1
  95. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +11 -2
  96. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.d.ts +2 -1
  97. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.js +2 -1
  98. package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.d.ts +2 -1
  99. package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.js +2 -1
  100. package/dist/esm/swappers/ChainflipSwapper/ChainflipSwapper.js +1 -0
  101. package/dist/esm/swappers/ChainflipSwapper/checkTradeStatus.test.d.ts +1 -0
  102. package/dist/esm/swappers/ChainflipSwapper/checkTradeStatus.test.js +46 -0
  103. package/dist/esm/swappers/ChainflipSwapper/endpoints.js +5 -2
  104. package/dist/esm/swappers/ChainflipSwapper/types.d.ts +3 -0
  105. package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeStepData.d.ts +1 -0
  106. package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeStepData.js +2 -2
  107. package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeTradeContext.js +1 -0
  108. package/dist/esm/swappers/NearIntentsSwapper/NearIntentsSwapper.js +1 -0
  109. package/dist/esm/swappers/NearIntentsSwapper/checkTradeStatus.test.d.ts +1 -0
  110. package/dist/esm/swappers/NearIntentsSwapper/checkTradeStatus.test.js +50 -0
  111. package/dist/esm/swappers/NearIntentsSwapper/constants.d.ts +1 -1
  112. package/dist/esm/swappers/NearIntentsSwapper/constants.js +3 -2
  113. package/dist/esm/swappers/NearIntentsSwapper/endpoints.js +6 -3
  114. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.d.ts +2 -1
  115. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +7 -3
  116. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.d.ts +2 -1
  117. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +7 -3
  118. package/dist/esm/swappers/NearIntentsSwapper/types.d.ts +3 -1
  119. package/dist/esm/swappers/NearIntentsSwapper/utils/exactOutput.test.d.ts +1 -0
  120. package/dist/esm/swappers/NearIntentsSwapper/utils/exactOutput.test.js +59 -0
  121. package/dist/esm/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.d.ts +2 -2
  122. package/dist/esm/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.js +4 -2
  123. package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.d.ts +5 -5
  124. package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.js +32 -28
  125. package/dist/esm/swappers/NearIntentsSwapper/utils/quoteDeadline.test.d.ts +1 -0
  126. package/dist/esm/swappers/NearIntentsSwapper/utils/quoteDeadline.test.js +26 -0
  127. package/dist/esm/swappers/PortalsSwapper/endpoints.js +53 -49
  128. package/dist/esm/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.js +1 -1
  129. package/dist/esm/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.js +1 -1
  130. package/dist/esm/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.d.ts +0 -1
  131. package/dist/esm/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.js +2 -4
  132. package/dist/esm/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.js +6 -3
  133. package/dist/esm/swappers/PortalsSwapper/utils/fetchSquidStatus.d.ts +0 -1
  134. package/dist/esm/swappers/PortalsSwapper/utils/fetchSquidStatus.js +0 -6
  135. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.d.ts +1 -0
  136. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.js +13 -5
  137. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.test.d.ts +1 -0
  138. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.test.js +68 -0
  139. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.d.ts +3 -2
  140. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.js +35 -17
  141. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.d.ts +1 -0
  142. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.js +91 -0
  143. package/dist/esm/swappers/RelaySwapper/endpoints.js +11 -20
  144. package/dist/esm/swappers/RelaySwapper/getTradeQuote/getTradeQuote.d.ts +2 -1
  145. package/dist/esm/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +3 -1
  146. package/dist/esm/swappers/RelaySwapper/getTradeRate/getTradeRate.d.ts +2 -1
  147. package/dist/esm/swappers/RelaySwapper/getTradeRate/getTradeRate.js +3 -1
  148. package/dist/esm/swappers/RelaySwapper/utils/getRelayTradeContext.d.ts +2 -2
  149. package/dist/esm/swappers/RelaySwapper/utils/getRelayTradeContext.js +23 -11
  150. package/dist/esm/swappers/RelaySwapper/utils/helpers.d.ts +2 -2
  151. package/dist/esm/swappers/RelaySwapper/utils/relayStatus.d.ts +8 -0
  152. package/dist/esm/swappers/RelaySwapper/utils/relayStatus.js +32 -0
  153. package/dist/esm/swappers/RelaySwapper/utils/types.d.ts +18 -1
  154. package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.d.ts +1 -0
  155. package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.js +2 -2
  156. package/dist/esm/swappers/SunioSwapper/utils/getSunioTradeContext.js +6 -1
  157. package/dist/esm/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +1 -0
  158. package/dist/esm/types.d.ts +21 -2
  159. package/dist/esm/types.js +2 -0
  160. package/dist/esm/utils/cowswap/index.d.ts +4 -1
  161. package/dist/esm/utils/cowswap/index.js +3 -0
  162. package/dist/esm/utils/helpers.d.ts +9 -0
  163. package/dist/esm/utils/helpers.js +20 -0
  164. package/dist/esm/utils/helpers.test.js +42 -1
  165. package/package.json +6 -6
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const constants_1 = require("./constants");
5
+ const swapper_1 = require("./swapper");
6
+ const types_1 = require("./types");
7
+ const assets_1 = require("./utils/test-data/assets");
8
+ // Exact-output support is structural - a swapper cannot claim it without implementing it
9
+ (0, vitest_1.describe)('exact output capability', () => {
10
+ (0, vitest_1.it)('is implemented by the swappers whose upstream API can honour an exact buy amount', () => {
11
+ for (const swapperName of [types_1.SwapperName.NearIntents, types_1.SwapperName.Relay]) {
12
+ (0, vitest_1.expect)(constants_1.swappers[swapperName]?.getExactOutputTradeRate).toBeDefined();
13
+ (0, vitest_1.expect)(constants_1.swappers[swapperName]?.getExactOutputTradeQuote).toBeDefined();
14
+ }
15
+ });
16
+ (0, vitest_1.it)('is absent everywhere else', () => {
17
+ const exactOutputCapable = Object.values(types_1.SwapperName).filter(swapperName => constants_1.swappers[swapperName]?.getExactOutputTradeRate !== undefined);
18
+ (0, vitest_1.expect)(exactOutputCapable).toEqual([types_1.SwapperName.Relay, types_1.SwapperName.NearIntents]);
19
+ });
20
+ });
21
+ const exactOutputInput = {
22
+ sellAsset: assets_1.ETH,
23
+ buyAsset: assets_1.BTC,
24
+ buyAmountCryptoBaseUnit: '100000',
25
+ affiliateBps: '0',
26
+ allowMultiHop: true,
27
+ receiveAddress: undefined,
28
+ accountNumber: undefined,
29
+ quoteOrRate: 'rate',
30
+ };
31
+ const deps = {};
32
+ (0, vitest_1.describe)('getTradeRates on an exact buy amount', () => {
33
+ // Silently omitting these would read as the swapper being unavailable rather than unable
34
+ (0, vitest_1.it)('reports an error for a swapper that cannot quote one', async () => {
35
+ const result = await (0, swapper_1.getTradeRates)(exactOutputInput, types_1.SwapperName.Thorchain, deps);
36
+ (0, vitest_1.expect)(result).toBeDefined();
37
+ (0, vitest_1.expect)(result?.isErr()).toBe(true);
38
+ (0, vitest_1.expect)(result?.unwrapErr().code).toEqual(types_1.TradeQuoteError.ExactOutputNotSupported);
39
+ (0, vitest_1.expect)(result?.swapperName).toEqual(types_1.SwapperName.Thorchain);
40
+ });
41
+ (0, vitest_1.it)('skips entirely on a zero buy amount', async () => {
42
+ const result = await (0, swapper_1.getTradeRates)({ ...exactOutputInput, buyAmountCryptoBaseUnit: '0' }, types_1.SwapperName.Thorchain, deps);
43
+ (0, vitest_1.expect)(result).toBeUndefined();
44
+ });
45
+ // The base-unit regex upstream admits padded zeros, so the check can't be a string comparison
46
+ (0, vitest_1.it)('skips entirely on a padded zero buy amount', async () => {
47
+ const result = await (0, swapper_1.getTradeRates)({ ...exactOutputInput, buyAmountCryptoBaseUnit: '00' }, types_1.SwapperName.Thorchain, deps);
48
+ (0, vitest_1.expect)(result).toBeUndefined();
49
+ });
50
+ });
51
+ // Quotes dispatch on the same input shape as rates, so they gate the same way
52
+ (0, vitest_1.describe)('getTradeQuotes on an exact buy amount', () => {
53
+ const exactOutputQuoteInput = {
54
+ ...exactOutputInput,
55
+ receiveAddress: 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq',
56
+ accountNumber: 0,
57
+ quoteOrRate: 'quote',
58
+ };
59
+ (0, vitest_1.it)('reports an error for a swapper that cannot quote one', async () => {
60
+ const result = await (0, swapper_1.getTradeQuotes)(exactOutputQuoteInput, types_1.SwapperName.Thorchain, deps);
61
+ (0, vitest_1.expect)(result).toBeDefined();
62
+ (0, vitest_1.expect)(result?.isErr()).toBe(true);
63
+ (0, vitest_1.expect)(result?.unwrapErr().code).toEqual(types_1.TradeQuoteError.ExactOutputNotSupported);
64
+ (0, vitest_1.expect)(result?.swapperName).toEqual(types_1.SwapperName.Thorchain);
65
+ });
66
+ (0, vitest_1.it)('skips entirely on a zero buy amount', async () => {
67
+ const result = await (0, swapper_1.getTradeQuotes)({ ...exactOutputQuoteInput, buyAmountCryptoBaseUnit: '0' }, types_1.SwapperName.Thorchain, deps);
68
+ (0, vitest_1.expect)(result).toBeUndefined();
69
+ });
70
+ });
@@ -1,3 +1,3 @@
1
- import type { GetTradeQuoteInput, GetTradeRateInput, QuoteResult, RateResult, SwapperDeps, SwapperName } from './types';
2
- export declare const getTradeQuotes: (getTradeQuoteInput: GetTradeQuoteInput, swapperName: SwapperName, deps: SwapperDeps) => Promise<QuoteResult | undefined>;
3
- export declare const getTradeRates: (getTradeRateInput: GetTradeRateInput, swapperName: SwapperName, deps: SwapperDeps, quoteTimeoutMs?: number) => Promise<RateResult | undefined>;
1
+ import type { GetExactOutputTradeQuoteInput, GetExactOutputTradeRateInput, GetTradeQuoteInput, GetTradeRateInput, QuoteResult, RateResult, SwapperDeps, SwapperName } from './types';
2
+ export declare const getTradeQuotes: (getTradeQuoteInput: GetTradeQuoteInput | GetExactOutputTradeQuoteInput, swapperName: SwapperName, deps: SwapperDeps) => Promise<QuoteResult | undefined>;
3
+ export declare const getTradeRates: (getTradeRateInput: GetTradeRateInput | GetExactOutputTradeRateInput, swapperName: SwapperName, deps: SwapperDeps, quoteTimeoutMs?: number) => Promise<RateResult | undefined>;
@@ -2,19 +2,33 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTradeRates = exports.getTradeQuotes = void 0;
4
4
  const utils_1 = require("@shapeshiftoss/utils");
5
+ const monads_1 = require("@sniptt/monads");
5
6
  const constants_1 = require("./constants");
6
7
  const types_1 = require("./types");
7
8
  const utils_2 = require("./utils");
9
+ const EXACT_OUTPUT_NOT_SUPPORTED_ERROR = (0, utils_2.makeSwapErrorRight)({
10
+ code: types_1.TradeQuoteError.ExactOutputNotSupported,
11
+ message: 'This swapper cannot derive a sell amount from an exact buy amount',
12
+ });
8
13
  const getTradeQuotes = async (getTradeQuoteInput, swapperName, deps) => {
9
14
  if ((0, utils_1.bnOrZero)(getTradeQuoteInput.affiliateBps).lt(0))
10
15
  return;
11
- if (getTradeQuoteInput.sellAmountIncludingProtocolFeesCryptoBaseUnit === '0')
12
- return;
13
16
  const swapper = constants_1.swappers[swapperName];
14
17
  if (swapper === undefined)
15
18
  return;
19
+ // Compared numerically so a padded zero can't slip through as an amount
20
+ const drivingAmount = 'buyAmountCryptoBaseUnit' in getTradeQuoteInput
21
+ ? getTradeQuoteInput.buyAmountCryptoBaseUnit
22
+ : getTradeQuoteInput.sellAmountIncludingProtocolFeesCryptoBaseUnit;
23
+ if ((0, utils_1.bnOrZero)(drivingAmount).isZero())
24
+ return;
25
+ const quotePromise = 'buyAmountCryptoBaseUnit' in getTradeQuoteInput
26
+ ? swapper.getExactOutputTradeQuote?.(getTradeQuoteInput, deps)
27
+ : swapper.getTradeQuote(getTradeQuoteInput, deps);
28
+ if (!quotePromise)
29
+ return { ...(0, monads_1.Err)(EXACT_OUTPUT_NOT_SUPPORTED_ERROR), swapperName };
16
30
  try {
17
- const quote = await (0, utils_1.timeoutMonadic)(swapper.getTradeQuote(getTradeQuoteInput, deps), constants_1.QUOTE_TIMEOUT_MS, constants_1.QUOTE_TIMEOUT_ERROR);
31
+ const quote = await (0, utils_1.timeoutMonadic)(quotePromise, constants_1.QUOTE_TIMEOUT_MS, constants_1.QUOTE_TIMEOUT_ERROR);
18
32
  return {
19
33
  ...quote,
20
34
  swapperName,
@@ -30,13 +44,22 @@ exports.getTradeQuotes = getTradeQuotes;
30
44
  const getTradeRates = async (getTradeRateInput, swapperName, deps, quoteTimeoutMs = constants_1.QUOTE_TIMEOUT_MS) => {
31
45
  if ((0, utils_1.bnOrZero)(getTradeRateInput.affiliateBps).lt(0))
32
46
  return;
33
- if (getTradeRateInput.sellAmountIncludingProtocolFeesCryptoBaseUnit === '0')
34
- return;
35
47
  const swapper = constants_1.swappers[swapperName];
36
48
  if (swapper === undefined)
37
49
  return;
50
+ // Compared numerically so a padded zero can't slip through as an amount
51
+ const drivingAmount = 'buyAmountCryptoBaseUnit' in getTradeRateInput
52
+ ? getTradeRateInput.buyAmountCryptoBaseUnit
53
+ : getTradeRateInput.sellAmountIncludingProtocolFeesCryptoBaseUnit;
54
+ if ((0, utils_1.bnOrZero)(drivingAmount).isZero())
55
+ return;
56
+ const ratePromise = 'buyAmountCryptoBaseUnit' in getTradeRateInput
57
+ ? swapper.getExactOutputTradeRate?.(getTradeRateInput, deps)
58
+ : swapper.getTradeRate(getTradeRateInput, deps);
59
+ if (!ratePromise)
60
+ return { ...(0, monads_1.Err)(EXACT_OUTPUT_NOT_SUPPORTED_ERROR), swapperName };
38
61
  try {
39
- const { timed, original } = (0, utils_1.timeoutMonadicWithOriginal)(swapper.getTradeRate(getTradeRateInput, deps), quoteTimeoutMs, (0, utils_2.makeSwapErrorRight)({
62
+ const { timed, original } = (0, utils_1.timeoutMonadicWithOriginal)(ratePromise, quoteTimeoutMs, (0, utils_2.makeSwapErrorRight)({
40
63
  code: types_1.TradeQuoteError.Timeout,
41
64
  message: `quote timed out after ${quoteTimeoutMs / 1000}s`,
42
65
  }));
@@ -3,6 +3,7 @@ import type { StepDataArgs, SwapErrorRight, TxBuildData } from '../../../types';
3
3
  import type { AcrossSwapTx } from './types';
4
4
  type BaseArgs = {
5
5
  swapTx: AcrossSwapTx;
6
+ sellAmountCryptoBaseUnit: string;
6
7
  spenderAddress: string;
7
8
  fallbackNetworkFeeCryptoBaseUnit: string;
8
9
  };
@@ -10,7 +10,7 @@ const utils_2 = require("../../../utils");
10
10
  const evm_1 = require("../../../utils/evm");
11
11
  const solana_1 = require("../../../utils/solana");
12
12
  async function getAcrossStepData(args) {
13
- const { swapTx, sellAsset, spenderAddress, from, type, input, fallbackNetworkFeeCryptoBaseUnit, deps, } = args;
13
+ const { swapTx, sellAsset, sellAmountCryptoBaseUnit, spenderAddress, from, type, input, fallbackNetworkFeeCryptoBaseUnit, deps, } = args;
14
14
  const supportsEIP1559 = 'supportsEIP1559' in input ? input.supportsEIP1559 : false;
15
15
  switch (swapTx.ecosystem) {
16
16
  case 'evm': {
@@ -25,7 +25,7 @@ async function getAcrossStepData(args) {
25
25
  };
26
26
  const stateOverride = {
27
27
  sellAsset,
28
- sellAmountCryptoBaseUnit: input.sellAmountIncludingProtocolFeesCryptoBaseUnit,
28
+ sellAmountCryptoBaseUnit,
29
29
  spenderAddress,
30
30
  };
31
31
  if (type === 'rate') {
@@ -173,6 +173,7 @@ const getAcrossTradeContext = async ({ input, deps, depositor, recipient, }) =>
173
173
  stepDataArgs: {
174
174
  swapTx: quote.swapTx,
175
175
  sellAsset,
176
+ sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
176
177
  from: depositor,
177
178
  spenderAddress: allowanceContract,
178
179
  fallbackNetworkFeeCryptoBaseUnit: quote.fees.originGas.amount,
@@ -3,6 +3,7 @@ import type { StepDataArgs, SwapErrorRight, TxBuildData } from '../../../types';
3
3
  import type { BebopQuoteResponse } from '../types';
4
4
  type BaseArgs = {
5
5
  tx: BebopQuoteResponse['tx'];
6
+ sellAmountCryptoBaseUnit: string;
6
7
  spenderAddress: string;
7
8
  };
8
9
  export type GetBebopStepDataArgs = StepDataArgs<BaseArgs, {
@@ -8,7 +8,7 @@ const viem_1 = require("viem");
8
8
  const utils_2 = require("../../../utils");
9
9
  const evm_1 = require("../../../utils/evm");
10
10
  async function getBebopStepData(args) {
11
- const { tx, spenderAddress, sellAsset, type, input, from, deps } = args;
11
+ const { tx, spenderAddress, sellAsset, sellAmountCryptoBaseUnit, type, input, from, deps } = args;
12
12
  const adapter = deps.assertGetEvmChainAdapter(sellAsset.chainId);
13
13
  const supportsEIP1559 = 'supportsEIP1559' in input ? input.supportsEIP1559 : false;
14
14
  if (type === 'rate') {
@@ -43,7 +43,7 @@ async function getBebopStepData(args) {
43
43
  supportsEIP1559,
44
44
  stateOverride: {
45
45
  sellAsset,
46
- sellAmountCryptoBaseUnit: input.sellAmountIncludingProtocolFeesCryptoBaseUnit,
46
+ sellAmountCryptoBaseUnit,
47
47
  spenderAddress,
48
48
  },
49
49
  });
@@ -78,6 +78,7 @@ const getBebopTradeContext = async ({ input, deps, from, receiver, }) => {
78
78
  tx: quote.tx,
79
79
  spenderAddress: allowanceContract,
80
80
  sellAsset,
81
+ sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
81
82
  from,
82
83
  deps,
83
84
  },
@@ -13,14 +13,18 @@ const getBobGatewayTradeQuote = async (input, deps) => {
13
13
  if (maybeAddresses.isErr())
14
14
  return (0, monads_1.Err)(maybeAddresses.unwrapErr());
15
15
  const { sendAddress, receiveAddress } = maybeAddresses.unwrap();
16
+ const isEvmSell = (0, chain_adapters_1.isEvmChainId)(sellAsset.chainId);
16
17
  // omit the sender for utxo sells so order creation does not enforce a per-address confirmed
17
18
  // funds check (deposits are matched via op_return, not the sending address)
18
- const sender = (0, chain_adapters_1.isEvmChainId)(sellAsset.chainId) ? sendAddress : undefined;
19
+ const sender = isEvmSell ? sendAddress : undefined;
20
+ // utxo deposits are refunded on the sell chain, so refunds go to the sending address
21
+ const refundAddress = isEvmSell ? undefined : sendAddress;
19
22
  const maybeContext = await (0, getBobGatewayTradeContext_1.getBobGatewayTradeContext)({
20
23
  input,
21
24
  deps,
22
25
  sender,
23
26
  recipient: receiveAddress,
27
+ refundAddress,
24
28
  });
25
29
  if (maybeContext.isErr())
26
30
  return (0, monads_1.Err)(maybeContext.unwrapErr());
@@ -8,9 +8,18 @@ const getBobGatewayTradeContext_1 = require("../utils/getBobGatewayTradeContext"
8
8
  const helpers_1 = require("../utils/helpers");
9
9
  const getBobGatewayTradeRate = async (input, deps) => {
10
10
  const { accountNumber, sellAsset, buyAsset, receiveAddress } = input;
11
+ const isBtcSell = sellAsset.chainId === caip_1.btcChainId;
11
12
  const recipient = receiveAddress ?? (0, helpers_1.dummyAddressForChainId)(buyAsset.chainId);
12
- const sender = sellAsset.chainId === caip_1.btcChainId ? undefined : (0, helpers_1.dummyAddressForChainId)(sellAsset.chainId);
13
- const maybeContext = await (0, getBobGatewayTradeContext_1.getBobGatewayTradeContext)({ input, deps, sender, recipient });
13
+ const sender = isBtcSell ? undefined : (0, helpers_1.dummyAddressForChainId)(sellAsset.chainId);
14
+ // utxo deposits are refunded on the sell chain, so the refund address must be a btc address
15
+ const refundAddress = isBtcSell ? (0, helpers_1.dummyAddressForChainId)(sellAsset.chainId) : undefined;
16
+ const maybeContext = await (0, getBobGatewayTradeContext_1.getBobGatewayTradeContext)({
17
+ input,
18
+ deps,
19
+ sender,
20
+ recipient,
21
+ refundAddress,
22
+ });
14
23
  if (maybeContext.isErr())
15
24
  return (0, monads_1.Err)(maybeContext.unwrapErr());
16
25
  const { tradeCommon, stepCommon, protocolFees, stepDataArgs } = maybeContext.unwrap();
@@ -8,10 +8,11 @@ type BobGatewayTradeContext = {
8
8
  protocolFees: QuoteFeeData['protocolFees'];
9
9
  stepDataArgs: Omit<GetBobGatewayStepDataArgs, 'type' | 'input' | 'from'>;
10
10
  };
11
- export declare const getBobGatewayTradeContext: ({ input, deps, sender, recipient, }: {
11
+ export declare const getBobGatewayTradeContext: ({ input, deps, sender, recipient, refundAddress, }: {
12
12
  input: BobGatewayTradeQuoteInput | BobGatewayTradeRateInput;
13
13
  deps: SwapperDeps;
14
14
  sender: string | undefined;
15
15
  recipient: string;
16
+ refundAddress: string | undefined;
16
17
  }) => Promise<Result<BobGatewayTradeContext, SwapErrorRight>>;
17
18
  export {};
@@ -7,7 +7,7 @@ const uuid_1 = require("uuid");
7
7
  const types_1 = require("../../../types");
8
8
  const utils_1 = require("../../../utils");
9
9
  const helpers_1 = require("./helpers");
10
- const getBobGatewayTradeContext = async ({ input, deps, sender, recipient, }) => {
10
+ const getBobGatewayTradeContext = async ({ input, deps, sender, recipient, refundAddress, }) => {
11
11
  const { sellAsset, buyAsset, sellAmountIncludingProtocolFeesCryptoBaseUnit, affiliateBps, slippageTolerancePercentageDecimal, } = input;
12
12
  const assertion = (0, helpers_1.assertValidTrade)({ sellAsset, buyAsset });
13
13
  if (assertion.isErr())
@@ -21,6 +21,7 @@ const getBobGatewayTradeContext = async ({ input, deps, sender, recipient, }) =>
21
21
  buyChainName,
22
22
  sender,
23
23
  recipient,
24
+ refundAddress,
24
25
  amount: sellAmountIncludingProtocolFeesCryptoBaseUnit,
25
26
  affiliateBps,
26
27
  slippageTolerancePercentageDecimal,
@@ -11,7 +11,7 @@ export declare const getBobGatewayClient: (config: SwapperConfig) => GatewaySDK;
11
11
  export declare const toTronBase58: (address: string) => string;
12
12
  export declare const assetIdToBobGatewayToken: (assetId: string) => string;
13
13
  export declare const getBobGatewayAffiliates: (affiliateBps: string) => GetQuoteParams['affiliates'];
14
- export declare const getBobGatewayQuote: ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, amount, affiliateBps, slippageTolerancePercentageDecimal, }: {
14
+ export declare const getBobGatewayQuote: ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, refundAddress, amount, affiliateBps, slippageTolerancePercentageDecimal, }: {
15
15
  config: SwapperConfig;
16
16
  sellAsset: Asset;
17
17
  buyAsset: Asset;
@@ -19,6 +19,7 @@ export declare const getBobGatewayQuote: ({ config, sellAsset, buyAsset, sellCha
19
19
  buyChainName: BobGatewayChainName;
20
20
  sender: string | undefined;
21
21
  recipient: string;
22
+ refundAddress: string | undefined;
22
23
  amount: string;
23
24
  affiliateBps: string;
24
25
  slippageTolerancePercentageDecimal: string | undefined;
@@ -49,7 +49,7 @@ const getBobGatewayAffiliates = (affiliateBps) => {
49
49
  return [{ address: (0, viem_1.getAddress)(affiliateAddress), bps: bps.toNumber() }];
50
50
  };
51
51
  exports.getBobGatewayAffiliates = getBobGatewayAffiliates;
52
- const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, amount, affiliateBps, slippageTolerancePercentageDecimal, }) => {
52
+ const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, refundAddress, amount, affiliateBps, slippageTolerancePercentageDecimal, }) => {
53
53
  const slippage = (0, constants_2.decimalSlippageToBobBps)(slippageTolerancePercentageDecimal ??
54
54
  (0, constants_1.getDefaultSlippageDecimalPercentageForSwapper)(types_1.SwapperName.BobGateway));
55
55
  try {
@@ -63,6 +63,7 @@ const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChainName,
63
63
  amount,
64
64
  maxSlippage: Number(slippage),
65
65
  ownerAddress: sellChainName === 'bitcoin' ? recipient : sender,
66
+ refundAddress,
66
67
  affiliates: (0, exports.getBobGatewayAffiliates)(affiliateBps),
67
68
  });
68
69
  return (0, monads_1.Ok)(quote);
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.chainflipSwapper = void 0;
4
4
  const utils_1 = require("../../utils");
5
5
  exports.chainflipSwapper = {
6
+ supportsExternalPayment: true,
6
7
  executeEvmTransaction: utils_1.executeEvmTransaction,
7
8
  executeSolanaTransaction: utils_1.executeSolanaTransaction,
8
9
  executeTronTransaction: utils_1.executeTronTransaction,
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const monads_1 = require("@sniptt/monads");
4
+ const vitest_1 = require("vitest");
5
+ const endpoints_1 = require("./endpoints");
6
+ const chainflipService_1 = require("./utils/chainflipService");
7
+ vitest_1.vi.mock('./utils/chainflipService', () => ({
8
+ chainflipService: { get: vitest_1.vi.fn() },
9
+ }));
10
+ const makeInput = () => ({
11
+ config: { VITE_CHAINFLIP_API_URL: 'https://broker', VITE_CHAINFLIP_API_KEY: 'key' },
12
+ swap: { metadata: { swapperMetadata: { name: 'chainflip', swapId: 1234 } } },
13
+ });
14
+ const mockStatus = (status) => vitest_1.vi.mocked(chainflipService_1.chainflipService.get).mockResolvedValue((0, monads_1.Ok)({ data: { status } }));
15
+ (0, vitest_1.describe)('chainflip checkTradeStatus', () => {
16
+ (0, vitest_1.beforeEach)(() => {
17
+ vitest_1.vi.clearAllMocks();
18
+ });
19
+ (0, vitest_1.it)('reports the deposit tx hash while the swap is still pending', async () => {
20
+ mockStatus({
21
+ state: 'swapping',
22
+ swapId: '1234',
23
+ deposit: { transactionReference: '0xdeposit' },
24
+ });
25
+ const result = await endpoints_1.chainflipApi.checkTradeStatus(makeInput());
26
+ (0, vitest_1.expect)(result.sellTxHash).toBe('0xdeposit');
27
+ (0, vitest_1.expect)(result.buyTxHash).toBeUndefined();
28
+ });
29
+ (0, vitest_1.it)('reports the deposit tx hash alongside a completed egress', async () => {
30
+ mockStatus({
31
+ state: 'completed',
32
+ swapId: '1234',
33
+ deposit: { transactionReference: '0xdeposit' },
34
+ swapEgress: { transactionReference: '0xegress' },
35
+ });
36
+ const result = await endpoints_1.chainflipApi.checkTradeStatus(makeInput());
37
+ (0, vitest_1.expect)(result.sellTxHash).toBe('0xdeposit');
38
+ (0, vitest_1.expect)(result.buyTxHash).toBe('0xegress');
39
+ });
40
+ (0, vitest_1.it)('has no deposit tx hash before the deposit is witnessed', async () => {
41
+ mockStatus({ state: 'waiting', swapId: '1234' });
42
+ (0, vitest_1.expect)((await endpoints_1.chainflipApi.checkTradeStatus(makeInput())).sellTxHash).toBeUndefined();
43
+ });
44
+ (0, vitest_1.it)('treats a null transaction reference as no deposit yet', async () => {
45
+ mockStatus({ state: 'receiving', swapId: '1234', deposit: { transactionReference: null } });
46
+ (0, vitest_1.expect)((await endpoints_1.chainflipApi.checkTradeStatus(makeInput())).sellTxHash).toBeUndefined();
47
+ });
48
+ });
@@ -55,13 +55,15 @@ exports.chainflipApi = {
55
55
  };
56
56
  }
57
57
  const { data: statusResponse } = maybeStatusResponse.unwrap();
58
- const buyTxHash = statusResponse.status.swapEgress?.transactionReference;
58
+ const buyTxHash = statusResponse.status.swapEgress?.transactionReference ?? undefined;
59
+ const sellTxHash = statusResponse.status.deposit?.transactionReference ?? undefined;
59
60
  const swapperTxId = statusResponse.status.swapId;
60
61
  const swapperTxLink = swapperTxId ? `https://scan.chainflip.io/swaps/${swapperTxId}` : undefined;
61
62
  // Assume no outbound Tx is a pending Tx
62
63
  if (!buyTxHash) {
63
64
  return {
64
- buyTxHash: undefined,
65
+ buyTxHash,
66
+ sellTxHash,
65
67
  status: unchained_client_1.TxStatus.Pending,
66
68
  swapperTxId,
67
69
  swapperTxLink,
@@ -72,6 +74,7 @@ exports.chainflipApi = {
72
74
  // Chainflip waits for 3 confirmations to assume complete (vs. 1 for us), which is turbo long.
73
75
  return {
74
76
  buyTxHash,
77
+ sellTxHash,
75
78
  status: unchained_client_1.TxStatus.Confirmed,
76
79
  swapperTxId,
77
80
  swapperTxLink,
@@ -11,6 +11,9 @@ export type ChainFlipStatus = {
11
11
  status: {
12
12
  state: 'waiting' | 'receiving' | 'swapping' | 'sending' | 'sent' | 'completed' | 'failed';
13
13
  swapId?: string;
14
+ deposit?: {
15
+ transactionReference?: string | null;
16
+ };
14
17
  swap?: ChainflipBaasStatusSwap;
15
18
  swapEgress?: ChainflipBaasStatusEgress;
16
19
  };
@@ -3,6 +3,7 @@ import type { StepDataArgs, SwapErrorRight, TxBuildData } from '../../../types';
3
3
  import type { DebridgeTx } from './types';
4
4
  type BaseArgs = {
5
5
  tx: DebridgeTx;
6
+ sellAmountCryptoBaseUnit: string;
6
7
  gasLimit: string | undefined;
7
8
  spenderAddress: string;
8
9
  fallbackNetworkFeeCryptoBaseUnit: string | undefined;
@@ -6,7 +6,7 @@ const monads_1 = require("@sniptt/monads");
6
6
  const utils_1 = require("../../../utils");
7
7
  const evm_1 = require("../../../utils/evm");
8
8
  async function getDebridgeStepData(args) {
9
- const { tx, gasLimit, spenderAddress, fallbackNetworkFeeCryptoBaseUnit, sellAsset, from, type, input, deps, } = args;
9
+ const { tx, sellAmountCryptoBaseUnit, gasLimit, spenderAddress, fallbackNetworkFeeCryptoBaseUnit, sellAsset, from, type, input, deps, } = args;
10
10
  const adapter = deps.assertGetEvmChainAdapter(sellAsset.chainId);
11
11
  const supportsEIP1559 = 'supportsEIP1559' in input ? input.supportsEIP1559 : false;
12
12
  const transactionData = {
@@ -19,7 +19,7 @@ async function getDebridgeStepData(args) {
19
19
  };
20
20
  const stateOverride = {
21
21
  sellAsset,
22
- sellAmountCryptoBaseUnit: input.sellAmountIncludingProtocolFeesCryptoBaseUnit,
22
+ sellAmountCryptoBaseUnit,
23
23
  spenderAddress,
24
24
  };
25
25
  if (type === 'rate') {
@@ -84,6 +84,7 @@ const getDebridgeTradeContext = async ({ input, deps, senderAddress, recipientAd
84
84
  protocolFees: quote.protocolFees,
85
85
  stepDataArgs: {
86
86
  tx: quote.tx,
87
+ sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
87
88
  gasLimit: quote.gasLimit,
88
89
  fallbackNetworkFeeCryptoBaseUnit: quote.fallbackNetworkFeeCryptoBaseUnit,
89
90
  sellAsset,
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nearIntentsSwapper = void 0;
4
4
  const utils_1 = require("../../utils");
5
5
  exports.nearIntentsSwapper = {
6
+ supportsExternalPayment: true,
6
7
  executeEvmTransaction: utils_1.executeEvmTransaction,
7
8
  executeSolanaTransaction: utils_1.executeSolanaTransaction,
8
9
  executeStarknetTransaction: utils_1.executeStarknetTransaction,
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const endpoints_1 = require("./endpoints");
5
+ const oneClickService_1 = require("./utils/oneClickService");
6
+ vitest_1.vi.mock('./utils/oneClickService', () => ({
7
+ initializeOneClickService: vitest_1.vi.fn(),
8
+ OneClickService: { getExecutionStatus: vitest_1.vi.fn() },
9
+ }));
10
+ const makeInput = () => ({
11
+ config: { VITE_NEAR_INTENTS_API_KEY: 'key' },
12
+ swap: {
13
+ metadata: { swapperMetadata: { name: 'nearIntents', depositAddress: '0xdepositaddress' } },
14
+ },
15
+ });
16
+ const mockExecutionStatus = (response) => vitest_1.vi.mocked(oneClickService_1.OneClickService.getExecutionStatus).mockResolvedValue(response);
17
+ (0, vitest_1.describe)('near intents checkTradeStatus', () => {
18
+ (0, vitest_1.beforeEach)(() => {
19
+ vitest_1.vi.clearAllMocks();
20
+ });
21
+ (0, vitest_1.it)('reports the origin chain deposit tx hash', async () => {
22
+ mockExecutionStatus({
23
+ status: 'PROCESSING',
24
+ swapDetails: {
25
+ originChainTxHashes: [{ hash: '0xdeposit', explorerUrl: '' }],
26
+ destinationChainTxHashes: [],
27
+ },
28
+ });
29
+ const result = await endpoints_1.nearIntentsApi.checkTradeStatus(makeInput());
30
+ (0, vitest_1.expect)(result.sellTxHash).toBe('0xdeposit');
31
+ (0, vitest_1.expect)(result.buyTxHash).toBeUndefined();
32
+ });
33
+ (0, vitest_1.it)('reports both sides once the swap settles', async () => {
34
+ mockExecutionStatus({
35
+ status: 'SUCCESS',
36
+ swapDetails: {
37
+ originChainTxHashes: [{ hash: '0xdeposit', explorerUrl: '' }],
38
+ destinationChainTxHashes: [{ hash: '0xsettlement', explorerUrl: '' }],
39
+ },
40
+ });
41
+ const result = await endpoints_1.nearIntentsApi.checkTradeStatus(makeInput());
42
+ (0, vitest_1.expect)(result.sellTxHash).toBe('0xdeposit');
43
+ (0, vitest_1.expect)(result.buyTxHash).toBe('0xsettlement');
44
+ });
45
+ (0, vitest_1.it)('has no deposit tx hash before the deposit lands', async () => {
46
+ mockExecutionStatus({
47
+ status: 'PENDING_DEPOSIT',
48
+ swapDetails: { originChainTxHashes: [], destinationChainTxHashes: [] },
49
+ });
50
+ (0, vitest_1.expect)((await endpoints_1.nearIntentsApi.checkTradeStatus(makeInput())).sellTxHash).toBeUndefined();
51
+ });
52
+ });
@@ -1,4 +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;
4
+ export declare const UTXO_QUOTE_DEADLINE_MS: number;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BTC_QUOTE_DEADLINE_MS = exports.DEFAULT_QUOTE_DEADLINE_MS = exports.DEFAULT_SLIPPAGE_BPS = exports.ONE_CLICK_BASE_URL = void 0;
3
+ exports.UTXO_QUOTE_DEADLINE_MS = exports.DEFAULT_QUOTE_DEADLINE_MS = exports.DEFAULT_SLIPPAGE_BPS = exports.ONE_CLICK_BASE_URL = void 0;
4
4
  exports.ONE_CLICK_BASE_URL = 'https://1click.chaindefuser.com';
5
5
  exports.DEFAULT_SLIPPAGE_BPS = 50;
6
- exports.DEFAULT_QUOTE_DEADLINE_MS = 30 * 60 * 1000;
7
- exports.BTC_QUOTE_DEADLINE_MS = 60 * 60 * 1000;
6
+ // 1Click refunds a deposit it cannot settle by the requested deadline, and prices a quote the same at any length
7
+ exports.DEFAULT_QUOTE_DEADLINE_MS = 60 * 60 * 1000;
8
+ exports.UTXO_QUOTE_DEADLINE_MS = 4 * 60 * 60 * 1000;
@@ -14,6 +14,8 @@ const oneClickService_1 = require("./utils/oneClickService");
14
14
  exports.nearIntentsApi = {
15
15
  getTradeQuote: (input, deps) => (0, getTradeQuote_1.getTradeQuote)(input, deps),
16
16
  getTradeRate: (input, deps) => (0, getTradeRate_1.getTradeRate)(input, deps),
17
+ getExactOutputTradeQuote: (input, deps) => (0, getTradeQuote_1.getExactOutputTradeQuote)(input, deps),
18
+ getExactOutputTradeRate: (input, deps) => (0, getTradeRate_1.getExactOutputTradeRate)(input, deps),
17
19
  getUnsignedEvmTransaction: evm_1.getUnsignedEvmTransaction,
18
20
  getEvmTransactionFees: evm_1.getEvmTransactionFees,
19
21
  getUnsignedUtxoTransaction: utxo_1.getUnsignedUtxoTransaction,
@@ -164,14 +166,15 @@ exports.nearIntentsApi = {
164
166
  const statusResponse = await oneClickService_1.OneClickService.getExecutionStatus(depositAddress);
165
167
  const txStatus = (0, helpers_1.mapNearIntentsStatus)(statusResponse.status);
166
168
  const message = (0, helpers_1.getNearIntentsStatusMessage)(statusResponse.status);
167
- // Extract buyTxHash from destination chain transactions
168
169
  const buyTxHash = statusResponse.swapDetails?.destinationChainTxHashes?.[0]?.hash;
170
+ const sellTxHash = statusResponse.swapDetails?.originChainTxHashes?.[0]?.hash;
169
171
  // amountOut is only meaningful destination-denominated on terminal success - in-flight and
170
172
  // refund states may carry settlement-internal or refund values
171
173
  const actualBuyAmountCryptoBaseUnit = statusResponse.status === 'SUCCESS' ? statusResponse.swapDetails?.amountOut : undefined;
172
174
  return {
173
175
  status: txStatus,
174
176
  buyTxHash,
177
+ sellTxHash,
175
178
  swapperTxLink: `https://explorer.near-intents.org/transactions/${depositAddress}`,
176
179
  message,
177
180
  actualBuyAmountCryptoBaseUnit,
@@ -1,4 +1,5 @@
1
1
  import type { Result } from '@sniptt/monads';
2
2
  import type { SwapErrorRight, SwapperDeps, TradeQuote } from '../../../types';
3
- import type { NearIntentsTradeQuoteInput } from '../types';
3
+ import type { NearIntentsExactOutputTradeQuoteInput, NearIntentsTradeQuoteInput } from '../types';
4
4
  export declare const getTradeQuote: (input: NearIntentsTradeQuoteInput, deps: SwapperDeps) => Promise<Result<TradeQuote[], SwapErrorRight>>;
5
+ export declare const getExactOutputTradeQuote: (input: NearIntentsExactOutputTradeQuoteInput, deps: SwapperDeps) => Promise<Result<TradeQuote[], SwapErrorRight>>;