@shapeshiftoss/swapper 17.7.3 → 17.8.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 (124) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/constants.js +35 -26
  3. package/dist/cjs/index.d.ts +1 -0
  4. package/dist/cjs/index.js +1 -0
  5. package/dist/cjs/swappers/ArbitrumBridgeSwapper/getTradeQuote/getTradeQuote.test.js +12 -4
  6. package/dist/cjs/swappers/BebopSwapper/getBebopSolanaTradeRate/getBebopSolanaTradeRate.js +9 -5
  7. package/dist/cjs/swappers/BebopSwapper/getBebopTradeQuote/getBebopTradeQuote.js +1 -9
  8. package/dist/cjs/swappers/BebopSwapper/getBebopTradeRate/getBebopTradeRate.js +9 -13
  9. package/dist/cjs/swappers/BebopSwapper/types.d.ts +64 -78
  10. package/dist/cjs/swappers/BebopSwapper/utils/fetchFromBebop.d.ts +0 -16
  11. package/dist/cjs/swappers/BebopSwapper/utils/fetchFromBebop.js +49 -82
  12. package/dist/cjs/swappers/BobGatewaySwapper/BobGatewaySwapper.d.ts +2 -0
  13. package/dist/cjs/swappers/BobGatewaySwapper/BobGatewaySwapper.js +8 -0
  14. package/dist/cjs/swappers/BobGatewaySwapper/endpoints.d.ts +2 -0
  15. package/dist/cjs/swappers/BobGatewaySwapper/endpoints.js +143 -0
  16. package/dist/cjs/swappers/BobGatewaySwapper/index.d.ts +3 -0
  17. package/dist/cjs/swappers/BobGatewaySwapper/index.js +22 -0
  18. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.d.ts +3 -0
  19. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +90 -0
  20. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeRate.d.ts +3 -0
  21. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +73 -0
  22. package/dist/cjs/swappers/BobGatewaySwapper/types.d.ts +20 -0
  23. package/dist/cjs/swappers/BobGatewaySwapper/types.js +2 -0
  24. package/dist/cjs/swappers/BobGatewaySwapper/utils/constants.d.ts +13 -0
  25. package/dist/cjs/swappers/BobGatewaySwapper/utils/constants.js +31 -0
  26. package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.d.ts +49 -0
  27. package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.js +314 -0
  28. package/dist/cjs/swappers/ChainflipSwapper/ChainflipSwapper.js +1 -0
  29. package/dist/cjs/swappers/ChainflipSwapper/constants.d.ts +1 -1
  30. package/dist/cjs/swappers/ChainflipSwapper/constants.js +3 -0
  31. package/dist/cjs/swappers/ChainflipSwapper/endpoints.js +20 -0
  32. package/dist/cjs/swappers/ChainflipSwapper/types.d.ts +2 -1
  33. package/dist/cjs/swappers/ChainflipSwapper/types.js +1 -0
  34. package/dist/cjs/swappers/ChainflipSwapper/utils/getQuoteOrRate.js +23 -3
  35. package/dist/cjs/swappers/ChainflipSwapper/utils/helpers.d.ts +2 -2
  36. package/dist/cjs/swappers/ChainflipSwapper/utils/helpers.js +2 -1
  37. package/dist/cjs/swappers/CowSwapper/utils/helpers/helpers.test.js +3 -3
  38. package/dist/cjs/swappers/RelaySwapper/constant.js +1 -1
  39. package/dist/cjs/swappers/SunioSwapper/endpoints.js +19 -36
  40. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapContractCall.d.ts +6 -0
  41. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapContractCall.js +33 -0
  42. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapRouteParameters.js +6 -6
  43. package/dist/cjs/swappers/SunioSwapper/utils/constants.d.ts +2 -0
  44. package/dist/cjs/swappers/SunioSwapper/utils/constants.js +7 -1
  45. package/dist/cjs/swappers/SunioSwapper/utils/estimateSunioNetworkFee.d.ts +12 -0
  46. package/dist/cjs/swappers/SunioSwapper/utils/estimateSunioNetworkFee.js +78 -0
  47. package/dist/cjs/swappers/SunioSwapper/utils/getQuoteOrRate.js +16 -74
  48. package/dist/cjs/swappers/SunioSwapper/utils/getSunioTransactionFees.d.ts +2 -0
  49. package/dist/cjs/swappers/SunioSwapper/utils/getSunioTransactionFees.js +36 -0
  50. package/dist/cjs/swappers/utils/helpers/helpers.js +1 -0
  51. package/dist/cjs/thorchain-utils/getL1RateOrQuote.js +5 -2
  52. package/dist/cjs/thorchain-utils/getQuote.js +27 -29
  53. package/dist/cjs/thorchain-utils/tron/getTronTransactionFees.js +8 -5
  54. package/dist/cjs/thorchain-utils/types.d.ts +1 -1
  55. package/dist/cjs/types.d.ts +10 -3
  56. package/dist/cjs/types.js +5 -0
  57. package/dist/esm/.tsbuildinfo +1 -1
  58. package/dist/esm/constants.js +9 -0
  59. package/dist/esm/index.d.ts +1 -0
  60. package/dist/esm/index.js +1 -0
  61. package/dist/esm/swappers/ArbitrumBridgeSwapper/getTradeQuote/getTradeQuote.test.js +12 -4
  62. package/dist/esm/swappers/BebopSwapper/getBebopSolanaTradeRate/getBebopSolanaTradeRate.js +10 -6
  63. package/dist/esm/swappers/BebopSwapper/getBebopTradeQuote/getBebopTradeQuote.js +1 -9
  64. package/dist/esm/swappers/BebopSwapper/getBebopTradeRate/getBebopTradeRate.js +10 -14
  65. package/dist/esm/swappers/BebopSwapper/types.d.ts +64 -78
  66. package/dist/esm/swappers/BebopSwapper/utils/fetchFromBebop.d.ts +0 -16
  67. package/dist/esm/swappers/BebopSwapper/utils/fetchFromBebop.js +45 -76
  68. package/dist/esm/swappers/BobGatewaySwapper/BobGatewaySwapper.d.ts +2 -0
  69. package/dist/esm/swappers/BobGatewaySwapper/BobGatewaySwapper.js +5 -0
  70. package/dist/esm/swappers/BobGatewaySwapper/endpoints.d.ts +2 -0
  71. package/dist/esm/swappers/BobGatewaySwapper/endpoints.js +140 -0
  72. package/dist/esm/swappers/BobGatewaySwapper/index.d.ts +3 -0
  73. package/dist/esm/swappers/BobGatewaySwapper/index.js +3 -0
  74. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.d.ts +3 -0
  75. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +86 -0
  76. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeRate.d.ts +3 -0
  77. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +69 -0
  78. package/dist/esm/swappers/BobGatewaySwapper/types.d.ts +20 -0
  79. package/dist/esm/swappers/BobGatewaySwapper/utils/constants.d.ts +13 -0
  80. package/dist/esm/swappers/BobGatewaySwapper/utils/constants.js +27 -0
  81. package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.d.ts +49 -0
  82. package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.js +299 -0
  83. package/dist/esm/swappers/ChainflipSwapper/ChainflipSwapper.js +2 -1
  84. package/dist/esm/swappers/ChainflipSwapper/constants.d.ts +1 -1
  85. package/dist/esm/swappers/ChainflipSwapper/constants.js +4 -1
  86. package/dist/esm/swappers/ChainflipSwapper/endpoints.js +20 -0
  87. package/dist/esm/swappers/ChainflipSwapper/types.d.ts +2 -1
  88. package/dist/esm/swappers/ChainflipSwapper/types.js +1 -0
  89. package/dist/esm/swappers/ChainflipSwapper/utils/getQuoteOrRate.js +24 -4
  90. package/dist/esm/swappers/ChainflipSwapper/utils/helpers.d.ts +2 -2
  91. package/dist/esm/swappers/ChainflipSwapper/utils/helpers.js +2 -1
  92. package/dist/esm/swappers/CowSwapper/utils/helpers/helpers.test.js +3 -3
  93. package/dist/esm/swappers/RelaySwapper/constant.js +1 -1
  94. package/dist/esm/swappers/SunioSwapper/endpoints.js +19 -36
  95. package/dist/esm/swappers/SunioSwapper/utils/buildSwapContractCall.d.ts +6 -0
  96. package/dist/esm/swappers/SunioSwapper/utils/buildSwapContractCall.js +29 -0
  97. package/dist/esm/swappers/SunioSwapper/utils/buildSwapRouteParameters.js +6 -6
  98. package/dist/esm/swappers/SunioSwapper/utils/constants.d.ts +2 -0
  99. package/dist/esm/swappers/SunioSwapper/utils/constants.js +6 -0
  100. package/dist/esm/swappers/SunioSwapper/utils/estimateSunioNetworkFee.d.ts +12 -0
  101. package/dist/esm/swappers/SunioSwapper/utils/estimateSunioNetworkFee.js +74 -0
  102. package/dist/esm/swappers/SunioSwapper/utils/getQuoteOrRate.js +16 -74
  103. package/dist/esm/swappers/SunioSwapper/utils/getSunioTransactionFees.d.ts +2 -0
  104. package/dist/esm/swappers/SunioSwapper/utils/getSunioTransactionFees.js +32 -0
  105. package/dist/esm/swappers/utils/helpers/helpers.js +2 -1
  106. package/dist/esm/thorchain-utils/getL1RateOrQuote.js +5 -2
  107. package/dist/esm/thorchain-utils/getQuote.js +27 -29
  108. package/dist/esm/thorchain-utils/tron/getTronTransactionFees.js +8 -5
  109. package/dist/esm/thorchain-utils/types.d.ts +1 -1
  110. package/dist/esm/types.d.ts +10 -3
  111. package/dist/esm/types.js +5 -0
  112. package/package.json +8 -7
  113. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapTransaction.d.ts +0 -11
  114. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapTransaction.js +0 -57
  115. package/dist/cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.d.ts +0 -12
  116. package/dist/cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.js +0 -47
  117. package/dist/cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.test.js +0 -100
  118. package/dist/esm/swappers/SunioSwapper/utils/buildSwapTransaction.d.ts +0 -11
  119. package/dist/esm/swappers/SunioSwapper/utils/buildSwapTransaction.js +0 -53
  120. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.d.ts +0 -12
  121. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.js +0 -41
  122. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.test.d.ts +0 -1
  123. package/dist/esm/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.test.js +0 -98
  124. /package/dist/{cjs/thorchain-utils/getThresholdedAffiliateBps/getThresholdedAffiliateBps.test.d.ts → esm/swappers/BobGatewaySwapper/types.js} +0 -0
@@ -0,0 +1,299 @@
1
+ import { GatewayErrorCode, GatewaySDK, isGatewayError } from '@gobob/bob-sdk';
2
+ import { ASSET_NAMESPACE, ethChainId, fromAssetId, toAssetId } from '@shapeshiftoss/caip';
3
+ import { evm, isEvmChainId } from '@shapeshiftoss/chain-adapters';
4
+ import { TxStatus } from '@shapeshiftoss/unchained-client';
5
+ import { bnOrZero, chainIdToFeeAssetId, contractAddressOrUndefined, isToken, } from '@shapeshiftoss/utils';
6
+ import { Err, Ok } from '@sniptt/monads';
7
+ import { getAddress, zeroAddress } from 'viem';
8
+ import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants.js';
9
+ import { SwapperName, TradeQuoteError } from '../../../types.js';
10
+ import { createTradeAmountTooSmallErr, makeSwapErrorRight } from '../../../utils.js';
11
+ import { getTreasuryAddressFromChainId } from '../../utils/helpers/helpers.js';
12
+ import { BOB_GATEWAY_BASE_URL, BOB_GATEWAY_OFFRAMP_DEFAULT_GAS_LIMIT, BOB_GATEWAY_ONRAMP_DEFAULT_TX_VSIZE, BOB_GATEWAY_TOKENSWAP_DEFAULT_GAS_LIMIT, bobGatewayChainNameToChainId, chainIdToBobGatewayChainName, decimalSlippageToBobBps, } from './constants.js';
13
+ export const getBobGatewayClient = (config) => {
14
+ return new GatewaySDK({ basePath: BOB_GATEWAY_BASE_URL, apiKey: config.VITE_BOB_GATEWAY_API_KEY });
15
+ };
16
+ export const assetIdToBobGatewayToken = (assetId) => {
17
+ // BOB Gateway uses the zero address as the token address for native assets
18
+ if (!isToken(assetId))
19
+ return zeroAddress;
20
+ return fromAssetId(assetId).assetReference;
21
+ };
22
+ export const getBobGatewayAffiliates = (affiliateBps) => {
23
+ const bps = bnOrZero(affiliateBps);
24
+ if (!bps.isFinite() || bps.lte(0))
25
+ return undefined;
26
+ const affiliateAddress = getTreasuryAddressFromChainId(ethChainId);
27
+ return [{ address: getAddress(affiliateAddress), bps: bps.toNumber() }];
28
+ };
29
+ export const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, amount, affiliateBps, slippageTolerancePercentageDecimal, }) => {
30
+ const slippage = decimalSlippageToBobBps(slippageTolerancePercentageDecimal ??
31
+ getDefaultSlippageDecimalPercentageForSwapper(SwapperName.BobGateway));
32
+ try {
33
+ const quote = await getBobGatewayClient(config).getQuote({
34
+ fromChain: sellChainName,
35
+ toChain: buyChainName,
36
+ fromToken: assetIdToBobGatewayToken(sellAsset.assetId),
37
+ toToken: assetIdToBobGatewayToken(buyAsset.assetId),
38
+ fromUserAddress: sender,
39
+ toUserAddress: recipient,
40
+ amount,
41
+ maxSlippage: Number(slippage),
42
+ affiliates: getBobGatewayAffiliates(affiliateBps),
43
+ });
44
+ return Ok(quote);
45
+ }
46
+ catch (err) {
47
+ if (isGatewayError(err)) {
48
+ switch (err.code) {
49
+ case GatewayErrorCode.QuoteAmountTooLow:
50
+ return Err(createTradeAmountTooSmallErr({
51
+ minAmountCryptoBaseUnit: err.details.minimum,
52
+ assetId: sellAsset.assetId,
53
+ }));
54
+ case GatewayErrorCode.UnableToCoverFees:
55
+ return Err(makeSwapErrorRight({
56
+ message: '[BobGateway] sell amount does not cover fees',
57
+ code: TradeQuoteError.SellAmountBelowTradeFee,
58
+ cause: err,
59
+ }));
60
+ case GatewayErrorCode.NoRoute:
61
+ return Err(makeSwapErrorRight({
62
+ message: '[BobGateway] no route found for trade pair',
63
+ code: TradeQuoteError.NoRouteFound,
64
+ cause: err,
65
+ }));
66
+ case GatewayErrorCode.DisabledChain:
67
+ return Err(makeSwapErrorRight({
68
+ message: '[BobGateway] trading is temporarily halted for this chain',
69
+ code: TradeQuoteError.TradingHalted,
70
+ cause: err,
71
+ }));
72
+ default:
73
+ break;
74
+ }
75
+ }
76
+ return Err(makeSwapErrorRight({
77
+ message: '[BobGateway] failed to fetch quote',
78
+ code: TradeQuoteError.QueryFailed,
79
+ cause: err,
80
+ }));
81
+ }
82
+ };
83
+ export const createBobGatewayOrderMetadata = async (config, gatewayQuote) => {
84
+ try {
85
+ const orderResponse = await getBobGatewayClient(config).api.createOrderV2({
86
+ gatewayQuoteV2: gatewayQuote,
87
+ });
88
+ // onramp (BTC→EVM)
89
+ if ('onramp' in orderResponse) {
90
+ return Ok({
91
+ orderId: orderResponse.onramp.orderId,
92
+ utxoTx: {
93
+ depositAddress: orderResponse.onramp.address,
94
+ opReturnData: orderResponse.onramp.opReturnData ?? undefined,
95
+ },
96
+ });
97
+ }
98
+ // offramp (EVM→BTC) and tokenSwap (EVM→EVM) orders share the same tx shape
99
+ const order = 'offramp' in orderResponse ? orderResponse.offramp : orderResponse.tokenSwap;
100
+ return Ok({
101
+ orderId: order.orderId,
102
+ evmTx: {
103
+ to: order.tx.to,
104
+ data: order.tx.data,
105
+ value: order.tx.value,
106
+ chain: order.tx.chain,
107
+ },
108
+ });
109
+ }
110
+ catch (err) {
111
+ if (isGatewayError(err) && err.code === GatewayErrorCode.InsufficientConfirmedFunds) {
112
+ return Err(makeSwapErrorRight({
113
+ message: '[BobGateway] insufficient confirmed balance',
114
+ code: TradeQuoteError.InsufficientFundsUnconfirmed,
115
+ cause: err,
116
+ }));
117
+ }
118
+ return Err(makeSwapErrorRight({
119
+ message: '[BobGateway] failed to create order',
120
+ code: TradeQuoteError.QueryFailed,
121
+ cause: err,
122
+ }));
123
+ }
124
+ };
125
+ export const registerBobGatewayTx = async ({ config, orderId, txHash, sellAsset, buyAsset, }) => {
126
+ const registerTxV2 = (() => {
127
+ // BTC→EVM
128
+ if (chainIdToBobGatewayChainName[sellAsset.chainId] === 'bitcoin') {
129
+ return { onramp: { orderId, bitcoinTxid: txHash } };
130
+ }
131
+ // EVM→BTC
132
+ if (chainIdToBobGatewayChainName[buyAsset.chainId] === 'bitcoin') {
133
+ return { offramp: { orderId, evmTxhash: txHash } };
134
+ }
135
+ // EVM→EVM
136
+ return { tokenSwap: { orderId, evmTxhash: txHash } };
137
+ })();
138
+ await getBobGatewayClient(config).api.registerTxV2({ registerTxV2 });
139
+ };
140
+ export const getBobGatewayQuoteFeeData = async (input, { assertGetUtxoChainAdapter, assertGetEvmChainAdapter }, orderMetadata) => {
141
+ const { sellAsset, sellAmountIncludingProtocolFeesCryptoBaseUnit } = input;
142
+ try {
143
+ if (orderMetadata.utxoTx && 'xpub' in input) {
144
+ const { depositAddress, opReturnData } = orderMetadata.utxoTx;
145
+ const { fast } = await assertGetUtxoChainAdapter(sellAsset.chainId).getFeeData({
146
+ to: depositAddress,
147
+ value: sellAmountIncludingProtocolFeesCryptoBaseUnit,
148
+ chainSpecific: { pubkey: input.xpub, opReturnData },
149
+ sendMax: false,
150
+ });
151
+ return Ok({
152
+ networkFeeCryptoBaseUnit: fast.txFee,
153
+ chainSpecific: { satsPerByte: fast.chainSpecific.satoshiPerByte },
154
+ });
155
+ }
156
+ if (orderMetadata.evmTx && input.sendAddress && 'supportsEIP1559' in input) {
157
+ const { to, data, value } = orderMetadata.evmTx;
158
+ const { networkFeeCryptoBaseUnit } = await evm.getFees({
159
+ adapter: assertGetEvmChainAdapter(sellAsset.chainId),
160
+ to,
161
+ data,
162
+ value,
163
+ from: input.sendAddress,
164
+ supportsEIP1559: input.supportsEIP1559,
165
+ });
166
+ return Ok({ networkFeeCryptoBaseUnit });
167
+ }
168
+ throw new Error('[BobGateway] invalid quote');
169
+ }
170
+ catch (err) {
171
+ return Err(makeSwapErrorRight({
172
+ message: '[BobGateway] failed to estimate network fee',
173
+ code: TradeQuoteError.NetworkFeeEstimationFailed,
174
+ cause: err,
175
+ }));
176
+ }
177
+ };
178
+ export const getBobGatewayRateNetworkFeeCryptoBaseUnit = async (quote, sellAsset, { assertGetEvmChainAdapter, assertGetUtxoChainAdapter }) => {
179
+ try {
180
+ if ('onramp' in quote) {
181
+ const adapter = assertGetUtxoChainAdapter(sellAsset.chainId);
182
+ const { fast } = await adapter.httpProvider.getNetworkFees();
183
+ if (!fast?.satsPerKiloByte)
184
+ return undefined;
185
+ const satsPerByte = Math.max(1, Math.ceil(fast.satsPerKiloByte / 1000));
186
+ return bnOrZero(satsPerByte).times(BOB_GATEWAY_ONRAMP_DEFAULT_TX_VSIZE).toFixed(0);
187
+ }
188
+ const defaultGasLimit = 'offramp' in quote
189
+ ? BOB_GATEWAY_OFFRAMP_DEFAULT_GAS_LIMIT
190
+ : BOB_GATEWAY_TOKENSWAP_DEFAULT_GAS_LIMIT;
191
+ const { average } = await assertGetEvmChainAdapter(sellAsset.chainId).getGasFeeData();
192
+ const feePerGas = bnOrZero(average.maxFeePerGas).gt(0) ? average.maxFeePerGas : average.gasPrice;
193
+ return bnOrZero(defaultGasLimit).times(bnOrZero(feePerGas)).toFixed(0);
194
+ }
195
+ catch {
196
+ return undefined;
197
+ }
198
+ };
199
+ export const mapBobGatewayOrderStatusToTxStatus = (status) => {
200
+ if ('inProgress' in status)
201
+ return TxStatus.Pending;
202
+ if ('success' in status)
203
+ return TxStatus.Confirmed;
204
+ if ('failed' in status)
205
+ return TxStatus.Failed;
206
+ if ('refunded' in status)
207
+ return TxStatus.Failed;
208
+ return TxStatus.Unknown;
209
+ };
210
+ const bobGatewayFeeToAssetId = (fee) => {
211
+ const chainId = bobGatewayChainNameToChainId[fee.chain];
212
+ if (!chainId)
213
+ return;
214
+ if (fee.address.toLowerCase() === zeroAddress)
215
+ return chainIdToFeeAssetId(chainId);
216
+ return toAssetId({
217
+ chainId,
218
+ assetNamespace: ASSET_NAMESPACE.erc20,
219
+ assetReference: fee.address,
220
+ });
221
+ };
222
+ export const parseBobGatewayQuote = (quote, buyAsset, assetsById) => {
223
+ const { outputAmount, estimatedTimeInSecs, fees } = (() => {
224
+ if ('onramp' in quote) {
225
+ const { outputAmount, estimatedTimeInSecs, fees } = quote.onramp;
226
+ return { outputAmount, estimatedTimeInSecs, fees: [fees] };
227
+ }
228
+ if ('offramp' in quote) {
229
+ const { outputAmount, estimatedTimeInSecs, feeBreakdown } = quote.offramp;
230
+ const { affiliateFee, inclusionFee, protocolFee, solverFee } = feeBreakdown;
231
+ return {
232
+ outputAmount,
233
+ estimatedTimeInSecs,
234
+ fees: [affiliateFee, inclusionFee, protocolFee, solverFee],
235
+ };
236
+ }
237
+ const { outputAmount, estimatedTimeInSecs, fees } = quote.tokenSwap;
238
+ return { outputAmount, estimatedTimeInSecs, fees: [fees] };
239
+ })();
240
+ const protocolFees = fees.reduce((acc, fee) => {
241
+ const amountCryptoBaseUnit = bnOrZero(fee.amount);
242
+ if (amountCryptoBaseUnit.lte(0))
243
+ return acc;
244
+ const assetId = bobGatewayFeeToAssetId(fee);
245
+ if (!assetId)
246
+ return acc;
247
+ const asset = assetId === buyAsset.assetId ? buyAsset : assetsById[assetId];
248
+ if (!asset)
249
+ return acc;
250
+ acc[assetId] = {
251
+ amountCryptoBaseUnit: bnOrZero(acc[assetId]?.amountCryptoBaseUnit)
252
+ .plus(amountCryptoBaseUnit)
253
+ .toFixed(),
254
+ asset,
255
+ requiresBalance: false,
256
+ };
257
+ return acc;
258
+ }, {});
259
+ // buyAmountBeforeFees is denominated in the buy asset, so only add back buy-asset-denominated fees
260
+ const buyAssetFeeCryptoBaseUnit = bnOrZero(protocolFees[buyAsset.assetId]?.amountCryptoBaseUnit);
261
+ return {
262
+ buyAmountBeforeFeesCryptoBaseUnit: buyAssetFeeCryptoBaseUnit
263
+ .plus(bnOrZero(outputAmount.amount))
264
+ .toFixed(),
265
+ buyAmountAfterFeesCryptoBaseUnit: outputAmount.amount,
266
+ protocolFees,
267
+ estimatedExecutionTimeMs: typeof estimatedTimeInSecs === 'number' ? estimatedTimeInSecs * 1000 : undefined,
268
+ };
269
+ };
270
+ export const getBobGatewayAllowanceContract = (quote, sellAsset) => {
271
+ if (!isEvmChainId(sellAsset.chainId))
272
+ return '';
273
+ if (!contractAddressOrUndefined(sellAsset.assetId))
274
+ return '';
275
+ if ('offramp' in quote)
276
+ return quote.offramp.txTo;
277
+ if ('tokenSwap' in quote)
278
+ return quote.tokenSwap.txTo;
279
+ return '';
280
+ };
281
+ export const assertValidTrade = ({ sellAsset, buyAsset, }) => {
282
+ const sellChainName = chainIdToBobGatewayChainName[sellAsset.chainId];
283
+ const buyChainName = chainIdToBobGatewayChainName[buyAsset.chainId];
284
+ if (!sellChainName) {
285
+ return Err(makeSwapErrorRight({
286
+ message: `[BobGateway] unsupported sell chain: ${sellAsset.chainId}`,
287
+ code: TradeQuoteError.UnsupportedChain,
288
+ details: { chainId: sellAsset.chainId },
289
+ }));
290
+ }
291
+ if (!buyChainName) {
292
+ return Err(makeSwapErrorRight({
293
+ message: `[BobGateway] unsupported buy chain: ${buyAsset.chainId}`,
294
+ code: TradeQuoteError.UnsupportedChain,
295
+ details: { chainId: buyAsset.chainId },
296
+ }));
297
+ }
298
+ return Ok({ sellChainName, buyChainName });
299
+ };
@@ -1,7 +1,8 @@
1
- import { executeEvmTransaction, executeSolanaTransaction } from '../../utils.js';
1
+ import { executeEvmTransaction, executeSolanaTransaction, executeTronTransaction, } from '../../utils.js';
2
2
  export const chainflipSwapper = {
3
3
  executeEvmTransaction,
4
4
  executeSolanaTransaction,
5
+ executeTronTransaction,
5
6
  executeUtxoTransaction: (txToSign, { signAndBroadcastTransaction }) => {
6
7
  return signAndBroadcastTransaction(txToSign);
7
8
  },
@@ -5,7 +5,7 @@ import type { SwapSource } from '../../types.js';
5
5
  import { ChainflipNetwork } from './types.js';
6
6
  export declare const CHAINFLIP_REGULAR_QUOTE: "regular";
7
7
  export declare const CHAINFLIP_DCA_QUOTE: "dca";
8
- export declare const ChainflipSupportedChainIds: readonly [KnownChainIds.EthereumMainnet, KnownChainIds.ArbitrumMainnet, KnownChainIds.BitcoinMainnet, KnownChainIds.SolanaMainnet];
8
+ export declare const ChainflipSupportedChainIds: readonly [KnownChainIds.EthereumMainnet, KnownChainIds.ArbitrumMainnet, KnownChainIds.BitcoinMainnet, KnownChainIds.SolanaMainnet, KnownChainIds.TronMainnet];
9
9
  export type ChainflipSupportedChainId = (typeof ChainflipSupportedChainIds)[number];
10
10
  export declare const ChainflipSupportedAssetIdsByChainId: Partial<Record<KnownChainIds, AssetId[]>>;
11
11
  export declare const chainIdToChainflipNetwork: Partial<Record<ChainId, ChainflipNetwork>>;
@@ -1,4 +1,4 @@
1
- import { arbitrumAssetId, btcAssetId, ethAssetId, flipAssetId, solAssetId, usdcAssetId, usdcOnArbitrumOneAssetId, usdcOnSolanaAssetId, usdtAssetId, usdtOnArbitrumOneAssetId, usdtOnSolanaAssetId, wbtcAssetId, } from '@shapeshiftoss/caip';
1
+ import { arbitrumAssetId, btcAssetId, ethAssetId, flipAssetId, solAssetId, tronAssetId, usdcAssetId, usdcOnArbitrumOneAssetId, usdcOnSolanaAssetId, usdtAssetId, usdtOnArbitrumOneAssetId, usdtOnSolanaAssetId, usdtOnTronAssetId, wbtcAssetId, } from '@shapeshiftoss/caip';
2
2
  import { KnownChainIds } from '@shapeshiftoss/types';
3
3
  import { SwapperName } from '../../types.js';
4
4
  import { ChainflipNetwork } from './types.js';
@@ -9,6 +9,7 @@ export const ChainflipSupportedChainIds = [
9
9
  KnownChainIds.ArbitrumMainnet,
10
10
  KnownChainIds.BitcoinMainnet,
11
11
  KnownChainIds.SolanaMainnet,
12
+ KnownChainIds.TronMainnet,
12
13
  ];
13
14
  export const ChainflipSupportedAssetIdsByChainId = {
14
15
  [KnownChainIds.EthereumMainnet]: [ethAssetId, flipAssetId, usdcAssetId, usdtAssetId, wbtcAssetId],
@@ -19,12 +20,14 @@ export const ChainflipSupportedAssetIdsByChainId = {
19
20
  ],
20
21
  [KnownChainIds.BitcoinMainnet]: [btcAssetId],
21
22
  [KnownChainIds.SolanaMainnet]: [solAssetId, usdcOnSolanaAssetId, usdtOnSolanaAssetId],
23
+ [KnownChainIds.TronMainnet]: [tronAssetId, usdtOnTronAssetId],
22
24
  };
23
25
  export const chainIdToChainflipNetwork = {
24
26
  [KnownChainIds.EthereumMainnet]: ChainflipNetwork.Ethereum,
25
27
  [KnownChainIds.ArbitrumMainnet]: ChainflipNetwork.Arbitrum,
26
28
  [KnownChainIds.BitcoinMainnet]: ChainflipNetwork.Bitcoin,
27
29
  [KnownChainIds.SolanaMainnet]: ChainflipNetwork.Solana,
30
+ [KnownChainIds.TronMainnet]: ChainflipNetwork.Tron,
28
31
  };
29
32
  export const CHAINFLIP_SWAP_SOURCE = SwapperName.Chainflip;
30
33
  export const CHAINFLIP_BOOST_SWAP_SOURCE = `${SwapperName.Chainflip} • Boost`;
@@ -1,6 +1,7 @@
1
1
  import { evm } from '@shapeshiftoss/chain-adapters';
2
2
  import { TxStatus } from '@shapeshiftoss/unchained-client';
3
3
  import { contractAddressOrUndefined } from '@shapeshiftoss/utils';
4
+ import { getTronTransactionFees } from '../../tron-utils/getTronTransactionFees.js';
4
5
  import { getExecutableTradeStep, isExecutableTradeQuote } from '../../utils.js';
5
6
  import { isNativeEvmAsset } from '../utils/helpers/helpers.js';
6
7
  import { ChainflipStatusMessage } from './constants.js';
@@ -163,6 +164,25 @@ export const chainflipApi = {
163
164
  const ratio = simulatedUnits > 0 ? boostedUnits / simulatedUnits : 1;
164
165
  return String(Math.ceil(Number(fast.txFee) * ratio));
165
166
  },
167
+ getUnsignedTronTransaction: ({ stepIndex, tradeQuote, from, assertGetTronChainAdapter }) => {
168
+ if (!isExecutableTradeQuote(tradeQuote))
169
+ throw new Error('Unable to execute a trade rate quote');
170
+ const step = getExecutableTradeStep(tradeQuote, stepIndex);
171
+ const { accountNumber, chainflipSpecific, sellAsset } = step;
172
+ if (!chainflipSpecific?.chainflipDepositAddress)
173
+ throw Error('Missing deposit address');
174
+ if (!chainflipSpecific?.chainflipSwapId)
175
+ throw Error('Missing swap id');
176
+ const adapter = assertGetTronChainAdapter(sellAsset.chainId);
177
+ return adapter.buildSendApiTransaction({
178
+ to: chainflipSpecific.chainflipDepositAddress,
179
+ from,
180
+ value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit,
181
+ accountNumber,
182
+ chainSpecific: { contractAddress: contractAddressOrUndefined(sellAsset.assetId) },
183
+ });
184
+ },
185
+ getTronTransactionFees,
166
186
  checkTradeStatus: async ({ config, swap }) => {
167
187
  const chainflipSwapId = swap?.metadata.chainflipSwapId;
168
188
  if (chainflipSwapId == null)
@@ -12,5 +12,6 @@ export declare enum ChainflipNetwork {
12
12
  Bitcoin = "Bitcoin",
13
13
  Ethereum = "Ethereum",
14
14
  Arbitrum = "Arbitrum",
15
- Solana = "Solana"
15
+ Solana = "Solana",
16
+ Tron = "Tron"
16
17
  }
@@ -4,4 +4,5 @@ export var ChainflipNetwork;
4
4
  ChainflipNetwork["Ethereum"] = "Ethereum";
5
5
  ChainflipNetwork["Arbitrum"] = "Arbitrum";
6
6
  ChainflipNetwork["Solana"] = "Solana";
7
+ ChainflipNetwork["Tron"] = "Tron";
7
8
  })(ChainflipNetwork || (ChainflipNetwork = {}));
@@ -1,5 +1,5 @@
1
1
  import { CHAIN_NAMESPACE, fromAssetId, solAssetId } from '@shapeshiftoss/caip';
2
- import { assertUnreachable, BigAmount, bnOrZero } from '@shapeshiftoss/utils';
2
+ import { assertUnreachable, BigAmount, bnOrZero, contractAddressOrUndefined, } from '@shapeshiftoss/utils';
3
3
  import { Err, Ok } from '@sniptt/monads';
4
4
  import { v4 as uuid } from 'uuid';
5
5
  import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants.js';
@@ -67,11 +67,14 @@ export const getQuoteOrRate = async (input, deps) => {
67
67
  if (maybeQuoteResponse.isErr()) {
68
68
  const error = maybeQuoteResponse.unwrapErr();
69
69
  const cause = error.cause;
70
- if (cause?.message?.includes('code 400') &&
71
- cause?.response?.data?.detail?.includes('Amount outside asset bounds')) {
70
+ // Chainflip returns a 400 with `errors.minimalAmountNative` when the sell amount is below the
71
+ // route minimum. The `detail` wording varies ("Amount outside asset bounds", "Amount below
72
+ // minimum. Min: ..."), so key off the field rather than string-matching the message.
73
+ const minAmountCryptoBaseUnit = cause?.response?.data?.errors?.minimalAmountNative?.[0];
74
+ if (cause?.response?.status === 400 && minAmountCryptoBaseUnit !== undefined) {
72
75
  return Err(createTradeAmountTooSmallErr({
73
76
  assetId: sellAsset.assetId,
74
- minAmountCryptoBaseUnit: cause.response?.data?.errors?.minimalAmountNative?.[0],
77
+ minAmountCryptoBaseUnit,
75
78
  }));
76
79
  }
77
80
  return Err(makeSwapErrorRight({
@@ -119,6 +122,21 @@ export const getQuoteOrRate = async (input, deps) => {
119
122
  const { fast } = await sellAdapter.getFeeData(getFeeDataInput);
120
123
  return { networkFeeCryptoBaseUnit: fast.txFee };
121
124
  }
125
+ case CHAIN_NAMESPACE.Tron: {
126
+ if (!input.sendAddress)
127
+ return { networkFeeCryptoBaseUnit: undefined };
128
+ const sellAdapter = deps.assertGetTronChainAdapter(sellAsset.chainId);
129
+ const { fast } = await sellAdapter.getFeeData({
130
+ // Simulates a self-send, since we don't know the 'to' just yet at this stage
131
+ to: input.sendAddress,
132
+ value: sellAmountIncludingProtocolFeesCryptoBaseUnit,
133
+ chainSpecific: {
134
+ from: input.sendAddress,
135
+ contractAddress: contractAddressOrUndefined(sellAsset.assetId),
136
+ },
137
+ });
138
+ return { networkFeeCryptoBaseUnit: fast.txFee };
139
+ }
122
140
  default:
123
141
  throw new Error('Unsupported chainNamespace');
124
142
  }
@@ -182,6 +200,8 @@ export const getQuoteOrRate = async (input, deps) => {
182
200
  return 10;
183
201
  case CHAIN_NAMESPACE.Solana:
184
202
  return 0;
203
+ case CHAIN_NAMESPACE.Tron:
204
+ return 0;
185
205
  default:
186
206
  throw new Error('Unsupported chainNamespace');
187
207
  }
@@ -20,8 +20,8 @@ type GetChainFlipSwapArgs = ChainFlipBrokerBaseArgs & {
20
20
  numberOfChunks?: number;
21
21
  chunkIntervalBlocks?: number;
22
22
  };
23
- export declare const isSupportedChainId: (chainId: ChainId) => chainId is import("@shapeshiftoss/types").KnownChainIds.EthereumMainnet | import("@shapeshiftoss/types").KnownChainIds.ArbitrumMainnet | import("@shapeshiftoss/types").KnownChainIds.BitcoinMainnet | import("@shapeshiftoss/types").KnownChainIds.SolanaMainnet;
24
- export declare const isSupportedAssetId: (chainId: ChainId, assetId: AssetId) => chainId is import("@shapeshiftoss/types").KnownChainIds.EthereumMainnet | import("@shapeshiftoss/types").KnownChainIds.ArbitrumMainnet | import("@shapeshiftoss/types").KnownChainIds.BitcoinMainnet | import("@shapeshiftoss/types").KnownChainIds.SolanaMainnet;
23
+ export declare const isSupportedChainId: (chainId: ChainId) => chainId is import("@shapeshiftoss/types").KnownChainIds.EthereumMainnet | import("@shapeshiftoss/types").KnownChainIds.ArbitrumMainnet | import("@shapeshiftoss/types").KnownChainIds.BitcoinMainnet | import("@shapeshiftoss/types").KnownChainIds.SolanaMainnet | import("@shapeshiftoss/types").KnownChainIds.TronMainnet;
24
+ export declare const isSupportedAssetId: (chainId: ChainId, assetId: AssetId) => chainId is import("@shapeshiftoss/types").KnownChainIds.EthereumMainnet | import("@shapeshiftoss/types").KnownChainIds.ArbitrumMainnet | import("@shapeshiftoss/types").KnownChainIds.BitcoinMainnet | import("@shapeshiftoss/types").KnownChainIds.SolanaMainnet | import("@shapeshiftoss/types").KnownChainIds.TronMainnet;
25
25
  export declare const calculateChainflipMinPrice: ({ sellAmountIncludingProtocolFeesCryptoBaseUnit, buyAmountAfterFeesCryptoBaseUnit, slippageTolerancePercentageDecimal, sellAsset, buyAsset, }: {
26
26
  sellAmountIncludingProtocolFeesCryptoBaseUnit: string;
27
27
  buyAmountAfterFeesCryptoBaseUnit: string;
@@ -45,7 +45,8 @@ export const getChainFlipSwap = ({ brokerUrl, apiKey, sourceAsset, destinationAs
45
45
  swapUrl += `&numberOfChunks=${numberOfChunks}`;
46
46
  swapUrl += `&chunkIntervalBlocks=${chunkIntervalBlocks}`;
47
47
  }
48
- return chainflipService.get(swapUrl);
48
+ // Opening a deposit channel can spike past the default 10s timeout (notably on Tron).
49
+ return chainflipService.get(swapUrl, { timeout: 30_000 });
49
50
  };
50
51
  const fetchChainFlipAssets = async ({ brokerUrl, }) => {
51
52
  const result = await chainflipService.get(`${brokerUrl}/assets`);
@@ -13,9 +13,9 @@ describe('utils', () => {
13
13
  const mockDay = '2020-12-31';
14
14
  const mockTime = 'T23:59:59.000Z';
15
15
  const mockDate = `${mockDay}${mockTime}`;
16
- beforeEach(() => vi
17
- .useFakeTimers()
18
- .setSystemTime(new Date(mockDate)));
16
+ beforeEach(() => {
17
+ vi.useFakeTimers().setSystemTime(new Date(mockDate));
18
+ });
19
19
  afterEach(() => {
20
20
  vi.restoreAllMocks();
21
21
  vi.useRealTimers();
@@ -68,7 +68,7 @@ export const relayErrorCodeToTradeQuoteError = {
68
68
  [RelayErrorCode.ChainDisabled]: TradeQuoteError.TradingHalted,
69
69
  [RelayErrorCode.Erc20RouterAddressNotFound]: TradeQuoteError.UnsupportedTradePair,
70
70
  [RelayErrorCode.ExtraTransactionsNotSupported]: TradeQuoteError.UnsupportedTradePair,
71
- [RelayErrorCode.InsufficientFunds]: TradeQuoteError.SellAmountBelowTradeFee,
71
+ [RelayErrorCode.InsufficientFunds]: TradeQuoteError.InsufficientFunds,
72
72
  [RelayErrorCode.InsufficientLiquidity]: TradeQuoteError.SellAmountBelowTradeFee,
73
73
  [RelayErrorCode.InvalidAddress]: TradeQuoteError.UnsupportedTradePair,
74
74
  [RelayErrorCode.InvalidExtraTransactions]: TradeQuoteError.UnsupportedTradePair,
@@ -2,23 +2,14 @@ import { tronAssetId, tronChainId } from '@shapeshiftoss/caip';
2
2
  import { toAddressNList } from '@shapeshiftoss/chain-adapters';
3
3
  import { TxStatus } from '@shapeshiftoss/unchained-client';
4
4
  import { TronWeb } from 'tronweb';
5
- import { getTronTransactionFees } from '../../tron-utils/getTronTransactionFees.js';
6
5
  import { createDefaultStatusResponse, getExecutableTradeStep, isExecutableTradeQuote, } from '../../utils.js';
7
6
  import { getSunioTradeQuote } from './getSunioTradeQuote/getSunioTradeQuote.js';
8
7
  import { getSunioTradeRate } from './getSunioTradeRate/getSunioTradeRate.js';
8
+ import { buildSwapExactInputParameters, SUNIO_SWAP_EXACT_INPUT_SELECTOR, } from './utils/buildSwapContractCall.js';
9
9
  import { buildSwapRouteParameters } from './utils/buildSwapRouteParameters.js';
10
10
  import { SUNIO_SMART_ROUTER_CONTRACT } from './utils/constants.js';
11
+ import { getSunioTransactionFees } from './utils/getSunioTransactionFees.js';
11
12
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
12
- const convertAddressesToEvmFormat = (value) => {
13
- if (Array.isArray(value)) {
14
- return value.map(v => convertAddressesToEvmFormat(v));
15
- }
16
- if (typeof value === 'string' && value.startsWith('T') && TronWeb.isAddress(value)) {
17
- const hex = TronWeb.address.toHex(value);
18
- return hex.replace(/^41/, '0x');
19
- }
20
- return value;
21
- };
22
13
  export const sunioApi = {
23
14
  getTradeQuote: async (input, deps) => {
24
15
  const maybeTradeQuote = await getSunioTradeQuote(input, deps);
@@ -29,7 +20,7 @@ export const sunioApi = {
29
20
  return maybeTradeRate.map(rate => [rate]);
30
21
  },
31
22
  getUnsignedTronTransaction: async (args) => {
32
- const { tradeQuote, stepIndex, from, slippageTolerancePercentageDecimal, assertGetTronChainAdapter, } = args;
23
+ const { tradeQuote, stepIndex, from, slippageTolerancePercentageDecimal, assertGetTronChainAdapter, config, } = args;
33
24
  if (!isExecutableTradeQuote(tradeQuote)) {
34
25
  throw new Error('Unable to execute a trade rate quote');
35
26
  }
@@ -42,24 +33,12 @@ export const sunioApi = {
42
33
  const rpcUrl = adapter.httpProvider.getRpcUrl();
43
34
  const tronWeb = new TronWeb({
44
35
  fullHost: rpcUrl,
36
+ headers: config.VITE_TRON_GRID_API_KEY
37
+ ? { 'TRON-PRO-API-KEY': config.VITE_TRON_GRID_API_KEY }
38
+ : {},
45
39
  });
46
40
  const routeParams = buildSwapRouteParameters(sunioMetadata.route, step.sellAmountIncludingProtocolFeesCryptoBaseUnit, step.buyAmountAfterFeesCryptoBaseUnit, tradeQuote.receiveAddress, slippageTolerancePercentageDecimal);
47
- const parameters = [
48
- { type: 'address[]', value: routeParams.path },
49
- { type: 'string[]', value: routeParams.poolVersion },
50
- { type: 'uint256[]', value: routeParams.versionLen },
51
- { type: 'uint24[]', value: routeParams.fees },
52
- {
53
- type: 'tuple(uint256,uint256,address,uint256)',
54
- value: convertAddressesToEvmFormat([
55
- routeParams.swapData.amountIn,
56
- routeParams.swapData.amountOutMin,
57
- routeParams.swapData.recipient,
58
- routeParams.swapData.deadline,
59
- ]),
60
- },
61
- ];
62
- const functionSelector = 'swapExactInput(address[],string[],uint256[],uint24[],(uint256,uint256,address,uint256))';
41
+ const parameters = buildSwapExactInputParameters(routeParams);
63
42
  const isSellingNativeTrx = step.sellAsset.assetId === tronAssetId;
64
43
  const callValue = isSellingNativeTrx
65
44
  ? Number(step.sellAmountIncludingProtocolFeesCryptoBaseUnit)
@@ -68,7 +47,7 @@ export const sunioApi = {
68
47
  feeLimit: 100_000_000,
69
48
  callValue,
70
49
  };
71
- const txData = await tronWeb.transactionBuilder.triggerSmartContract(SUNIO_SMART_ROUTER_CONTRACT, functionSelector, options, parameters, from);
50
+ const txData = await tronWeb.transactionBuilder.triggerSmartContract(SUNIO_SMART_ROUTER_CONTRACT, SUNIO_SWAP_EXACT_INPUT_SELECTOR, options, parameters, from);
72
51
  if (!txData.result || !txData.result.result) {
73
52
  throw new Error('[Sun.io] Failed to build swap transaction');
74
53
  }
@@ -97,7 +76,7 @@ export const sunioApi = {
97
76
  transaction,
98
77
  };
99
78
  },
100
- getTronTransactionFees,
79
+ getTronTransactionFees: getSunioTransactionFees,
101
80
  checkTradeStatus: async ({ txHash, assertGetTronChainAdapter }) => {
102
81
  try {
103
82
  // Wait for TronGrid indexing to avoid false "REVERT"
@@ -108,12 +87,16 @@ export const sunioApi = {
108
87
  return createDefaultStatusResponse(txHash);
109
88
  }
110
89
  const contractRet = tx.ret?.[0]?.contractRet;
111
- // Only mark as confirmed if SUCCESS AND has confirmations (in a block)
112
- const status = contractRet === 'SUCCESS' && tx.confirmations > 0
113
- ? TxStatus.Confirmed
114
- : contractRet === 'REVERT'
115
- ? TxStatus.Failed
116
- : TxStatus.Pending;
90
+ // Tron reports many failure codes (REVERT, OUT_OF_ENERGY, OUT_OF_TIME, ...). A missing
91
+ // contractRet means it isn't mined yet; any non-SUCCESS value is a terminal failure.
92
+ const status = (() => {
93
+ if (!contractRet)
94
+ return TxStatus.Pending;
95
+ if (contractRet === 'SUCCESS') {
96
+ return tx.confirmations > 0 ? TxStatus.Confirmed : TxStatus.Pending;
97
+ }
98
+ return TxStatus.Failed;
99
+ })();
117
100
  return {
118
101
  status,
119
102
  buyTxHash: txHash,
@@ -0,0 +1,6 @@
1
+ import type { SwapRouteParameters } from './buildSwapRouteParameters.js';
2
+ export declare const SUNIO_SWAP_EXACT_INPUT_SELECTOR = "swapExactInput(address[],string[],uint256[],uint24[],(uint256,uint256,address,uint256))";
3
+ export declare const buildSwapExactInputParameters: (routeParams: SwapRouteParameters) => {
4
+ type: string;
5
+ value: unknown;
6
+ }[];
@@ -0,0 +1,29 @@
1
+ import { TronWeb } from 'tronweb';
2
+ export const SUNIO_SWAP_EXACT_INPUT_SELECTOR = 'swapExactInput(address[],string[],uint256[],uint24[],(uint256,uint256,address,uint256))';
3
+ const convertAddressesToEvmFormat = (value) => {
4
+ if (Array.isArray(value)) {
5
+ return value.map(v => convertAddressesToEvmFormat(v));
6
+ }
7
+ if (typeof value === 'string' && value.startsWith('T') && TronWeb.isAddress(value)) {
8
+ const hex = TronWeb.address.toHex(value);
9
+ return hex.replace(/^41/, '0x');
10
+ }
11
+ return value;
12
+ };
13
+ // Parameter list for the SmartExchangeRouter swapExactInput call, shared between fee
14
+ // estimation and execution so both encode the call identically.
15
+ export const buildSwapExactInputParameters = (routeParams) => [
16
+ { type: 'address[]', value: routeParams.path },
17
+ { type: 'string[]', value: routeParams.poolVersion },
18
+ { type: 'uint256[]', value: routeParams.versionLen },
19
+ { type: 'uint24[]', value: routeParams.fees },
20
+ {
21
+ type: 'tuple(uint256,uint256,address,uint256)',
22
+ value: convertAddressesToEvmFormat([
23
+ routeParams.swapData.amountIn,
24
+ routeParams.swapData.amountOutMin,
25
+ routeParams.swapData.recipient,
26
+ routeParams.swapData.deadline,
27
+ ]),
28
+ },
29
+ ];