@shapeshiftoss/swapper 20.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.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +5 -1
- package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +11 -2
- package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.d.ts +2 -1
- package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.js +2 -1
- package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.d.ts +2 -1
- package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.js +2 -1
- package/dist/cjs/swappers/ChainflipSwapper/ChainflipSwapper.js +1 -0
- package/dist/cjs/swappers/ChainflipSwapper/checkTradeStatus.test.d.ts +1 -0
- package/dist/cjs/swappers/ChainflipSwapper/checkTradeStatus.test.js +48 -0
- package/dist/cjs/swappers/ChainflipSwapper/endpoints.js +5 -2
- package/dist/cjs/swappers/ChainflipSwapper/types.d.ts +3 -0
- package/dist/cjs/swappers/NearIntentsSwapper/NearIntentsSwapper.js +1 -0
- package/dist/cjs/swappers/NearIntentsSwapper/checkTradeStatus.test.d.ts +1 -0
- package/dist/cjs/swappers/NearIntentsSwapper/checkTradeStatus.test.js +52 -0
- package/dist/cjs/swappers/NearIntentsSwapper/constants.d.ts +1 -1
- package/dist/cjs/swappers/NearIntentsSwapper/constants.js +4 -3
- package/dist/cjs/swappers/NearIntentsSwapper/endpoints.js +2 -1
- package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.d.ts +2 -2
- package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.js +3 -3
- package/dist/cjs/swappers/NearIntentsSwapper/utils/quoteDeadline.test.d.ts +1 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/quoteDeadline.test.js +28 -0
- package/dist/cjs/swappers/PortalsSwapper/endpoints.js +51 -47
- package/dist/cjs/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.js +1 -1
- package/dist/cjs/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.js +1 -1
- package/dist/cjs/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.d.ts +0 -1
- package/dist/cjs/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.js +3 -6
- package/dist/cjs/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.js +6 -3
- package/dist/cjs/swappers/PortalsSwapper/utils/fetchSquidStatus.d.ts +0 -1
- package/dist/cjs/swappers/PortalsSwapper/utils/fetchSquidStatus.js +1 -8
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.js +13 -5
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.test.d.ts +1 -0
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.test.js +70 -0
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.d.ts +2 -2
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.js +27 -15
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.d.ts +1 -0
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.js +93 -0
- package/dist/cjs/swappers/RelaySwapper/endpoints.js +3 -18
- package/dist/cjs/swappers/RelaySwapper/utils/relayStatus.d.ts +8 -0
- package/dist/cjs/swappers/RelaySwapper/utils/relayStatus.js +39 -0
- package/dist/cjs/swappers/RelaySwapper/utils/types.d.ts +14 -0
- package/dist/cjs/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +1 -0
- package/dist/cjs/types.d.ts +2 -0
- package/dist/cjs/utils/cowswap/index.d.ts +4 -1
- package/dist/cjs/utils/cowswap/index.js +5 -1
- package/dist/cjs/utils/helpers.d.ts +4 -1
- package/dist/cjs/utils/helpers.js +19 -1
- package/dist/cjs/utils/helpers.test.js +41 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +5 -1
- package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +11 -2
- package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.d.ts +2 -1
- package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.js +2 -1
- package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.d.ts +2 -1
- package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.js +2 -1
- package/dist/esm/swappers/ChainflipSwapper/ChainflipSwapper.js +1 -0
- package/dist/esm/swappers/ChainflipSwapper/checkTradeStatus.test.d.ts +1 -0
- package/dist/esm/swappers/ChainflipSwapper/checkTradeStatus.test.js +46 -0
- package/dist/esm/swappers/ChainflipSwapper/endpoints.js +5 -2
- package/dist/esm/swappers/ChainflipSwapper/types.d.ts +3 -0
- package/dist/esm/swappers/NearIntentsSwapper/NearIntentsSwapper.js +1 -0
- package/dist/esm/swappers/NearIntentsSwapper/checkTradeStatus.test.d.ts +1 -0
- package/dist/esm/swappers/NearIntentsSwapper/checkTradeStatus.test.js +50 -0
- package/dist/esm/swappers/NearIntentsSwapper/constants.d.ts +1 -1
- package/dist/esm/swappers/NearIntentsSwapper/constants.js +3 -2
- package/dist/esm/swappers/NearIntentsSwapper/endpoints.js +2 -1
- package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.d.ts +2 -2
- package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.js +5 -5
- package/dist/esm/swappers/NearIntentsSwapper/utils/quoteDeadline.test.d.ts +1 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/quoteDeadline.test.js +26 -0
- package/dist/esm/swappers/PortalsSwapper/endpoints.js +53 -49
- package/dist/esm/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.js +1 -1
- package/dist/esm/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.js +1 -1
- package/dist/esm/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.d.ts +0 -1
- package/dist/esm/swappers/PortalsSwapper/utils/fetchAxelarscanStatus.js +2 -4
- package/dist/esm/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.js +6 -3
- package/dist/esm/swappers/PortalsSwapper/utils/fetchSquidStatus.d.ts +0 -1
- package/dist/esm/swappers/PortalsSwapper/utils/fetchSquidStatus.js +0 -6
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.js +10 -2
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.test.d.ts +1 -0
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.test.js +68 -0
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.d.ts +2 -2
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.js +28 -16
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.d.ts +1 -0
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.test.js +91 -0
- package/dist/esm/swappers/RelaySwapper/endpoints.js +3 -18
- package/dist/esm/swappers/RelaySwapper/utils/relayStatus.d.ts +8 -0
- package/dist/esm/swappers/RelaySwapper/utils/relayStatus.js +32 -0
- package/dist/esm/swappers/RelaySwapper/utils/types.d.ts +14 -0
- package/dist/esm/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +1 -0
- package/dist/esm/types.d.ts +2 -0
- package/dist/esm/utils/cowswap/index.d.ts +4 -1
- package/dist/esm/utils/cowswap/index.js +3 -0
- package/dist/esm/utils/helpers.d.ts +4 -1
- package/dist/esm/utils/helpers.js +17 -0
- package/dist/esm/utils/helpers.test.js +42 -1
- package/package.json +7 -7
|
@@ -10,14 +10,18 @@ export const getBobGatewayTradeQuote = async (input, deps) => {
|
|
|
10
10
|
if (maybeAddresses.isErr())
|
|
11
11
|
return Err(maybeAddresses.unwrapErr());
|
|
12
12
|
const { sendAddress, receiveAddress } = maybeAddresses.unwrap();
|
|
13
|
+
const isEvmSell = isEvmChainId(sellAsset.chainId);
|
|
13
14
|
// omit the sender for utxo sells so order creation does not enforce a per-address confirmed
|
|
14
15
|
// funds check (deposits are matched via op_return, not the sending address)
|
|
15
|
-
const sender =
|
|
16
|
+
const sender = isEvmSell ? sendAddress : undefined;
|
|
17
|
+
// utxo deposits are refunded on the sell chain, so refunds go to the sending address
|
|
18
|
+
const refundAddress = isEvmSell ? undefined : sendAddress;
|
|
16
19
|
const maybeContext = await getBobGatewayTradeContext({
|
|
17
20
|
input,
|
|
18
21
|
deps,
|
|
19
22
|
sender,
|
|
20
23
|
recipient: receiveAddress,
|
|
24
|
+
refundAddress,
|
|
21
25
|
});
|
|
22
26
|
if (maybeContext.isErr())
|
|
23
27
|
return Err(maybeContext.unwrapErr());
|
|
@@ -5,9 +5,18 @@ import { getBobGatewayTradeContext } from '../utils/getBobGatewayTradeContext.js
|
|
|
5
5
|
import { dummyAddressForChainId } from '../utils/helpers.js';
|
|
6
6
|
export const getBobGatewayTradeRate = async (input, deps) => {
|
|
7
7
|
const { accountNumber, sellAsset, buyAsset, receiveAddress } = input;
|
|
8
|
+
const isBtcSell = sellAsset.chainId === btcChainId;
|
|
8
9
|
const recipient = receiveAddress ?? dummyAddressForChainId(buyAsset.chainId);
|
|
9
|
-
const sender =
|
|
10
|
-
|
|
10
|
+
const sender = isBtcSell ? undefined : dummyAddressForChainId(sellAsset.chainId);
|
|
11
|
+
// utxo deposits are refunded on the sell chain, so the refund address must be a btc address
|
|
12
|
+
const refundAddress = isBtcSell ? dummyAddressForChainId(sellAsset.chainId) : undefined;
|
|
13
|
+
const maybeContext = await getBobGatewayTradeContext({
|
|
14
|
+
input,
|
|
15
|
+
deps,
|
|
16
|
+
sender,
|
|
17
|
+
recipient,
|
|
18
|
+
refundAddress,
|
|
19
|
+
});
|
|
11
20
|
if (maybeContext.isErr())
|
|
12
21
|
return Err(maybeContext.unwrapErr());
|
|
13
22
|
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 {};
|
|
@@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid';
|
|
|
4
4
|
import { SwapperName } from '../../../types.js';
|
|
5
5
|
import { getInputOutputRate } from '../../../utils/index.js';
|
|
6
6
|
import { assertValidTrade, getBobGatewayAllowanceContract, getBobGatewayQuote, parseBobGatewayQuote, } from './helpers.js';
|
|
7
|
-
export const getBobGatewayTradeContext = async ({ input, deps, sender, recipient, }) => {
|
|
7
|
+
export const getBobGatewayTradeContext = async ({ input, deps, sender, recipient, refundAddress, }) => {
|
|
8
8
|
const { sellAsset, buyAsset, sellAmountIncludingProtocolFeesCryptoBaseUnit, affiliateBps, slippageTolerancePercentageDecimal, } = input;
|
|
9
9
|
const assertion = assertValidTrade({ sellAsset, buyAsset });
|
|
10
10
|
if (assertion.isErr())
|
|
@@ -18,6 +18,7 @@ export const getBobGatewayTradeContext = async ({ input, deps, sender, recipient
|
|
|
18
18
|
buyChainName,
|
|
19
19
|
sender,
|
|
20
20
|
recipient,
|
|
21
|
+
refundAddress,
|
|
21
22
|
amount: sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
22
23
|
affiliateBps,
|
|
23
24
|
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;
|
|
@@ -41,7 +41,7 @@ export const getBobGatewayAffiliates = (affiliateBps) => {
|
|
|
41
41
|
const affiliateAddress = getTreasuryAddressFromChainId(ethChainId);
|
|
42
42
|
return [{ address: getAddress(affiliateAddress), bps: bps.toNumber() }];
|
|
43
43
|
};
|
|
44
|
-
export const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, amount, affiliateBps, slippageTolerancePercentageDecimal, }) => {
|
|
44
|
+
export const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChainName, buyChainName, sender, recipient, refundAddress, amount, affiliateBps, slippageTolerancePercentageDecimal, }) => {
|
|
45
45
|
const slippage = decimalSlippageToBobBps(slippageTolerancePercentageDecimal ??
|
|
46
46
|
getDefaultSlippageDecimalPercentageForSwapper(SwapperName.BobGateway));
|
|
47
47
|
try {
|
|
@@ -55,6 +55,7 @@ export const getBobGatewayQuote = async ({ config, sellAsset, buyAsset, sellChai
|
|
|
55
55
|
amount,
|
|
56
56
|
maxSlippage: Number(slippage),
|
|
57
57
|
ownerAddress: sellChainName === 'bitcoin' ? recipient : sender,
|
|
58
|
+
refundAddress,
|
|
58
59
|
affiliates: getBobGatewayAffiliates(affiliateBps),
|
|
59
60
|
});
|
|
60
61
|
return Ok(quote);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Ok } from '@sniptt/monads';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { chainflipApi } from './endpoints.js';
|
|
4
|
+
import { chainflipService } from './utils/chainflipService.js';
|
|
5
|
+
vi.mock('./utils/chainflipService', () => ({
|
|
6
|
+
chainflipService: { get: vi.fn() },
|
|
7
|
+
}));
|
|
8
|
+
const makeInput = () => ({
|
|
9
|
+
config: { VITE_CHAINFLIP_API_URL: 'https://broker', VITE_CHAINFLIP_API_KEY: 'key' },
|
|
10
|
+
swap: { metadata: { swapperMetadata: { name: 'chainflip', swapId: 1234 } } },
|
|
11
|
+
});
|
|
12
|
+
const mockStatus = (status) => vi.mocked(chainflipService.get).mockResolvedValue(Ok({ data: { status } }));
|
|
13
|
+
describe('chainflip checkTradeStatus', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
it('reports the deposit tx hash while the swap is still pending', async () => {
|
|
18
|
+
mockStatus({
|
|
19
|
+
state: 'swapping',
|
|
20
|
+
swapId: '1234',
|
|
21
|
+
deposit: { transactionReference: '0xdeposit' },
|
|
22
|
+
});
|
|
23
|
+
const result = await chainflipApi.checkTradeStatus(makeInput());
|
|
24
|
+
expect(result.sellTxHash).toBe('0xdeposit');
|
|
25
|
+
expect(result.buyTxHash).toBeUndefined();
|
|
26
|
+
});
|
|
27
|
+
it('reports the deposit tx hash alongside a completed egress', async () => {
|
|
28
|
+
mockStatus({
|
|
29
|
+
state: 'completed',
|
|
30
|
+
swapId: '1234',
|
|
31
|
+
deposit: { transactionReference: '0xdeposit' },
|
|
32
|
+
swapEgress: { transactionReference: '0xegress' },
|
|
33
|
+
});
|
|
34
|
+
const result = await chainflipApi.checkTradeStatus(makeInput());
|
|
35
|
+
expect(result.sellTxHash).toBe('0xdeposit');
|
|
36
|
+
expect(result.buyTxHash).toBe('0xegress');
|
|
37
|
+
});
|
|
38
|
+
it('has no deposit tx hash before the deposit is witnessed', async () => {
|
|
39
|
+
mockStatus({ state: 'waiting', swapId: '1234' });
|
|
40
|
+
expect((await chainflipApi.checkTradeStatus(makeInput())).sellTxHash).toBeUndefined();
|
|
41
|
+
});
|
|
42
|
+
it('treats a null transaction reference as no deposit yet', async () => {
|
|
43
|
+
mockStatus({ state: 'receiving', swapId: '1234', deposit: { transactionReference: null } });
|
|
44
|
+
expect((await chainflipApi.checkTradeStatus(makeInput())).sellTxHash).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -52,13 +52,15 @@ export const chainflipApi = {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
const { data: statusResponse } = maybeStatusResponse.unwrap();
|
|
55
|
-
const buyTxHash = statusResponse.status.swapEgress?.transactionReference;
|
|
55
|
+
const buyTxHash = statusResponse.status.swapEgress?.transactionReference ?? undefined;
|
|
56
|
+
const sellTxHash = statusResponse.status.deposit?.transactionReference ?? undefined;
|
|
56
57
|
const swapperTxId = statusResponse.status.swapId;
|
|
57
58
|
const swapperTxLink = swapperTxId ? `https://scan.chainflip.io/swaps/${swapperTxId}` : undefined;
|
|
58
59
|
// Assume no outbound Tx is a pending Tx
|
|
59
60
|
if (!buyTxHash) {
|
|
60
61
|
return {
|
|
61
|
-
buyTxHash
|
|
62
|
+
buyTxHash,
|
|
63
|
+
sellTxHash,
|
|
62
64
|
status: TxStatus.Pending,
|
|
63
65
|
swapperTxId,
|
|
64
66
|
swapperTxLink,
|
|
@@ -69,6 +71,7 @@ export const chainflipApi = {
|
|
|
69
71
|
// Chainflip waits for 3 confirmations to assume complete (vs. 1 for us), which is turbo long.
|
|
70
72
|
return {
|
|
71
73
|
buyTxHash,
|
|
74
|
+
sellTxHash,
|
|
72
75
|
status: TxStatus.Confirmed,
|
|
73
76
|
swapperTxId,
|
|
74
77
|
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
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { executeEvmTransaction, executeNearTransaction, executeSolanaTransaction, executeStarknetTransaction, executeSuiTransaction, executeTonTransaction, executeTronTransaction, } from '../../utils/index.js';
|
|
2
2
|
export const nearIntentsSwapper = {
|
|
3
|
+
supportsExternalPayment: true,
|
|
3
4
|
executeEvmTransaction,
|
|
4
5
|
executeSolanaTransaction,
|
|
5
6
|
executeStarknetTransaction,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { nearIntentsApi } from './endpoints.js';
|
|
3
|
+
import { OneClickService } from './utils/oneClickService.js';
|
|
4
|
+
vi.mock('./utils/oneClickService', () => ({
|
|
5
|
+
initializeOneClickService: vi.fn(),
|
|
6
|
+
OneClickService: { getExecutionStatus: vi.fn() },
|
|
7
|
+
}));
|
|
8
|
+
const makeInput = () => ({
|
|
9
|
+
config: { VITE_NEAR_INTENTS_API_KEY: 'key' },
|
|
10
|
+
swap: {
|
|
11
|
+
metadata: { swapperMetadata: { name: 'nearIntents', depositAddress: '0xdepositaddress' } },
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
const mockExecutionStatus = (response) => vi.mocked(OneClickService.getExecutionStatus).mockResolvedValue(response);
|
|
15
|
+
describe('near intents checkTradeStatus', () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
vi.clearAllMocks();
|
|
18
|
+
});
|
|
19
|
+
it('reports the origin chain deposit tx hash', async () => {
|
|
20
|
+
mockExecutionStatus({
|
|
21
|
+
status: 'PROCESSING',
|
|
22
|
+
swapDetails: {
|
|
23
|
+
originChainTxHashes: [{ hash: '0xdeposit', explorerUrl: '' }],
|
|
24
|
+
destinationChainTxHashes: [],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
const result = await nearIntentsApi.checkTradeStatus(makeInput());
|
|
28
|
+
expect(result.sellTxHash).toBe('0xdeposit');
|
|
29
|
+
expect(result.buyTxHash).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
it('reports both sides once the swap settles', async () => {
|
|
32
|
+
mockExecutionStatus({
|
|
33
|
+
status: 'SUCCESS',
|
|
34
|
+
swapDetails: {
|
|
35
|
+
originChainTxHashes: [{ hash: '0xdeposit', explorerUrl: '' }],
|
|
36
|
+
destinationChainTxHashes: [{ hash: '0xsettlement', explorerUrl: '' }],
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
const result = await nearIntentsApi.checkTradeStatus(makeInput());
|
|
40
|
+
expect(result.sellTxHash).toBe('0xdeposit');
|
|
41
|
+
expect(result.buyTxHash).toBe('0xsettlement');
|
|
42
|
+
});
|
|
43
|
+
it('has no deposit tx hash before the deposit lands', async () => {
|
|
44
|
+
mockExecutionStatus({
|
|
45
|
+
status: 'PENDING_DEPOSIT',
|
|
46
|
+
swapDetails: { originChainTxHashes: [], destinationChainTxHashes: [] },
|
|
47
|
+
});
|
|
48
|
+
expect((await nearIntentsApi.checkTradeStatus(makeInput())).sellTxHash).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -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
|
|
4
|
+
export declare const UTXO_QUOTE_DEADLINE_MS: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const ONE_CLICK_BASE_URL = 'https://1click.chaindefuser.com';
|
|
2
2
|
export const DEFAULT_SLIPPAGE_BPS = 50;
|
|
3
|
-
|
|
4
|
-
export const
|
|
3
|
+
// 1Click refunds a deposit it cannot settle by the requested deadline, and prices a quote the same at any length
|
|
4
|
+
export const DEFAULT_QUOTE_DEADLINE_MS = 60 * 60 * 1000;
|
|
5
|
+
export const UTXO_QUOTE_DEADLINE_MS = 4 * 60 * 60 * 1000;
|
|
@@ -163,14 +163,15 @@ export const nearIntentsApi = {
|
|
|
163
163
|
const statusResponse = await OneClickService.getExecutionStatus(depositAddress);
|
|
164
164
|
const txStatus = mapNearIntentsStatus(statusResponse.status);
|
|
165
165
|
const message = getNearIntentsStatusMessage(statusResponse.status);
|
|
166
|
-
// Extract buyTxHash from destination chain transactions
|
|
167
166
|
const buyTxHash = statusResponse.swapDetails?.destinationChainTxHashes?.[0]?.hash;
|
|
167
|
+
const sellTxHash = statusResponse.swapDetails?.originChainTxHashes?.[0]?.hash;
|
|
168
168
|
// amountOut is only meaningful destination-denominated on terminal success - in-flight and
|
|
169
169
|
// refund states may carry settlement-internal or refund values
|
|
170
170
|
const actualBuyAmountCryptoBaseUnit = statusResponse.status === 'SUCCESS' ? statusResponse.swapDetails?.amountOut : undefined;
|
|
171
171
|
return {
|
|
172
172
|
status: txStatus,
|
|
173
173
|
buyTxHash,
|
|
174
|
+
sellTxHash,
|
|
174
175
|
swapperTxLink: `https://explorer.near-intents.org/transactions/${depositAddress}`,
|
|
175
176
|
message,
|
|
176
177
|
actualBuyAmountCryptoBaseUnit,
|
|
@@ -17,8 +17,8 @@ export declare const resolveNearIntentsAssets: ({ sellAsset, buyAsset, }: {
|
|
|
17
17
|
destinationAsset: string;
|
|
18
18
|
}, SwapErrorRight>>;
|
|
19
19
|
export declare const getNearIntentsQuoteDeadline: ({ sellAsset, buyAsset, }: {
|
|
20
|
-
sellAsset: Asset
|
|
21
|
-
buyAsset: Asset
|
|
20
|
+
sellAsset: Pick<Asset, 'chainId'>;
|
|
21
|
+
buyAsset: Pick<Asset, 'chainId'>;
|
|
22
22
|
}) => string;
|
|
23
23
|
export declare const buildNearIntentsQuoteRequest: ({ originAsset, destinationAsset, amount, slippageTolerancePercentageDecimal, affiliateBps, refundTo, recipient, refundType, recipientType, deadline, }: {
|
|
24
24
|
originAsset: string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CHAIN_NAMESPACE, fromAssetId, fromChainId, solanaChainId } from '@shapeshiftoss/caip';
|
|
2
2
|
import { TxStatus } from '@shapeshiftoss/unchained-client';
|
|
3
3
|
import { bnOrZero, DAO_TREASURY_NEAR, isToken } from '@shapeshiftoss/utils';
|
|
4
4
|
import { Err, Ok } from '@sniptt/monads';
|
|
5
5
|
import { zeroAddress } from 'viem';
|
|
6
6
|
import { TradeQuoteError } from '../../../types.js';
|
|
7
7
|
import { createTradeAmountTooSmallErr, makeSwapErrorRight } from '../../../utils/index.js';
|
|
8
|
-
import {
|
|
8
|
+
import { DEFAULT_QUOTE_DEADLINE_MS, DEFAULT_SLIPPAGE_BPS, UTXO_QUOTE_DEADLINE_MS, } from '../constants.js';
|
|
9
9
|
import { chainIdToNearIntentsChain, QuoteRequest } from '../types.js';
|
|
10
10
|
import { ApiError, OneClickService } from './oneClickService.js';
|
|
11
11
|
const getTokensWithRetry = async () => {
|
|
@@ -120,10 +120,10 @@ export const resolveNearIntentsAssets = async ({ sellAsset, buyAsset, }) => {
|
|
|
120
120
|
}));
|
|
121
121
|
}
|
|
122
122
|
};
|
|
123
|
-
|
|
123
|
+
const isUtxoChainId = (chainId) => fromChainId(chainId).chainNamespace === CHAIN_NAMESPACE.Utxo;
|
|
124
124
|
export const getNearIntentsQuoteDeadline = ({ sellAsset, buyAsset, }) => {
|
|
125
|
-
const deadlineMs = sellAsset.chainId
|
|
126
|
-
?
|
|
125
|
+
const deadlineMs = isUtxoChainId(sellAsset.chainId) || isUtxoChainId(buyAsset.chainId)
|
|
126
|
+
? UTXO_QUOTE_DEADLINE_MS
|
|
127
127
|
: DEFAULT_QUOTE_DEADLINE_MS;
|
|
128
128
|
return new Date(Date.now() + deadlineMs).toISOString();
|
|
129
129
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { btcChainId, dogeChainId, ethChainId, solanaChainId } from '@shapeshiftoss/caip';
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { DEFAULT_QUOTE_DEADLINE_MS, UTXO_QUOTE_DEADLINE_MS } from '../constants.js';
|
|
4
|
+
import { getNearIntentsQuoteDeadline } from './helpers.js';
|
|
5
|
+
const asset = (chainId) => ({ chainId });
|
|
6
|
+
describe('getNearIntentsQuoteDeadline', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
vi.useFakeTimers();
|
|
9
|
+
vi.setSystemTime(new Date('2026-09-10T22:00:00.000Z'));
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.useRealTimers();
|
|
13
|
+
});
|
|
14
|
+
it('gives a utxo sell leg the long deadline', () => {
|
|
15
|
+
expect(Date.parse(getNearIntentsQuoteDeadline({ sellAsset: asset(btcChainId), buyAsset: asset(ethChainId) }))).toBe(Date.now() + UTXO_QUOTE_DEADLINE_MS);
|
|
16
|
+
});
|
|
17
|
+
it('gives a utxo buy leg the long deadline, on any utxo chain', () => {
|
|
18
|
+
expect(Date.parse(getNearIntentsQuoteDeadline({ sellAsset: asset(ethChainId), buyAsset: asset(dogeChainId) }))).toBe(Date.now() + UTXO_QUOTE_DEADLINE_MS);
|
|
19
|
+
});
|
|
20
|
+
it('gives everything else the default deadline', () => {
|
|
21
|
+
expect(Date.parse(getNearIntentsQuoteDeadline({
|
|
22
|
+
sellAsset: asset(ethChainId),
|
|
23
|
+
buyAsset: asset(solanaChainId),
|
|
24
|
+
}))).toBe(Date.now() + DEFAULT_QUOTE_DEADLINE_MS);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { TxStatus } from '@shapeshiftoss/unchained-client';
|
|
2
2
|
import { checkEvmSwapStatus } from '../../utils/index.js';
|
|
3
3
|
import { getEvmTransactionFees, getUnsignedEvmTransaction } from '../../utils/evm/index.js';
|
|
4
|
+
import { fetchRelayRequestByTxHash, getRelayRequestFailureMessage, relayStatusToTxStatus, } from '../RelaySwapper/utils/relayStatus.js';
|
|
4
5
|
import { getPortalsTradeQuote } from './getPortalsTradeQuote/getPortalsTradeQuote.js';
|
|
5
6
|
import { getPortalsTradeRate } from './getPortalsTradeRate/getPortalsTradeRate.js';
|
|
6
|
-
import { fetchAxelarscanBridgeStatus
|
|
7
|
-
import { fetchSquidBridgeStatus
|
|
7
|
+
import { fetchAxelarscanBridgeStatus } from './utils/fetchAxelarscanStatus.js';
|
|
8
|
+
import { fetchSquidBridgeStatus } from './utils/fetchSquidStatus.js';
|
|
9
|
+
const bridgeStatusToTxStatus = (status) => {
|
|
10
|
+
switch (status) {
|
|
11
|
+
case 'confirmed':
|
|
12
|
+
return TxStatus.Confirmed;
|
|
13
|
+
case 'failed':
|
|
14
|
+
return TxStatus.Failed;
|
|
15
|
+
case 'pending':
|
|
16
|
+
default:
|
|
17
|
+
return TxStatus.Pending;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
8
20
|
export const portalsApi = {
|
|
9
21
|
getTradeQuote: (input, deps) => getPortalsTradeQuote(input, deps),
|
|
10
22
|
getTradeRate: (input, deps) => getPortalsTradeRate(input, deps),
|
|
11
23
|
getEvmTransactionFees,
|
|
12
24
|
getUnsignedEvmTransaction,
|
|
13
25
|
checkTradeStatus: async (input) => {
|
|
14
|
-
const { txHash, chainId, swap, assertGetEvmChainAdapter, address, fetchIsSmartContractAddressQuery, } = input;
|
|
26
|
+
const { txHash, chainId, swap, config, assertGetEvmChainAdapter, address, fetchIsSmartContractAddressQuery, } = input;
|
|
15
27
|
const isCrossChain = Boolean(swap && swap.sellAsset.chainId !== swap.buyAsset?.chainId);
|
|
16
28
|
if (!isCrossChain) {
|
|
17
29
|
return checkEvmSwapStatus({
|
|
@@ -39,64 +51,56 @@ export const portalsApi = {
|
|
|
39
51
|
if (sourceTxStatus.status === TxStatus.Failed) {
|
|
40
52
|
return sourceTxStatus;
|
|
41
53
|
}
|
|
54
|
+
const relayResult = await fetchRelayRequestByTxHash(txHash, config);
|
|
55
|
+
if (relayResult.isOk()) {
|
|
56
|
+
const relayRequest = relayResult.unwrap();
|
|
57
|
+
if (relayRequest) {
|
|
58
|
+
const relayTxStatus = relayStatusToTxStatus(relayRequest.status);
|
|
59
|
+
const txStatus = relayTxStatus === TxStatus.Unknown ? TxStatus.Pending : relayTxStatus;
|
|
60
|
+
return {
|
|
61
|
+
status: txStatus,
|
|
62
|
+
buyTxHash: relayRequest.data?.outTxs?.[0]?.hash,
|
|
63
|
+
message: txStatus === TxStatus.Failed
|
|
64
|
+
? getRelayRequestFailureMessage(relayRequest)
|
|
65
|
+
: txStatus === TxStatus.Confirmed
|
|
66
|
+
? undefined
|
|
67
|
+
: 'Bridge in progress',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
42
71
|
const axelarscanResult = await fetchAxelarscanBridgeStatus(txHash);
|
|
43
|
-
if (
|
|
72
|
+
if (axelarscanResult.isOk()) {
|
|
73
|
+
const bridgeStatus = axelarscanResult.unwrap();
|
|
74
|
+
if (bridgeStatus) {
|
|
75
|
+
const txStatus = bridgeStatusToTxStatus(bridgeStatus.status);
|
|
76
|
+
return {
|
|
77
|
+
status: txStatus,
|
|
78
|
+
buyTxHash: bridgeStatus.destinationTxHash,
|
|
79
|
+
message: txStatus === TxStatus.Pending
|
|
80
|
+
? 'Bridge in progress'
|
|
81
|
+
: txStatus === TxStatus.Failed
|
|
82
|
+
? bridgeStatus.errorMessage
|
|
83
|
+
: undefined,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (swap) {
|
|
44
88
|
const squidResult = await fetchSquidBridgeStatus(txHash, swap.sellAsset.chainId, swap.buyAsset.chainId);
|
|
45
89
|
if (squidResult.isOk()) {
|
|
46
90
|
const squidStatus = squidResult.unwrap();
|
|
47
|
-
const squidTxStatus = (
|
|
48
|
-
switch (squidStatus.status) {
|
|
49
|
-
case 'confirmed':
|
|
50
|
-
return TxStatus.Confirmed;
|
|
51
|
-
case 'failed':
|
|
52
|
-
return TxStatus.Failed;
|
|
53
|
-
case 'pending':
|
|
54
|
-
default:
|
|
55
|
-
return TxStatus.Pending;
|
|
56
|
-
}
|
|
57
|
-
})();
|
|
91
|
+
const squidTxStatus = bridgeStatusToTxStatus(squidStatus.status);
|
|
58
92
|
return {
|
|
59
93
|
status: squidTxStatus,
|
|
60
94
|
buyTxHash: squidStatus.destinationTxHash,
|
|
61
|
-
swapperTxLink: getSquidTrackingLink(txHash, squidStatus, swap.sellAsset.explorerTxLink, swap.buyAsset.explorerTxLink),
|
|
62
95
|
message: squidTxStatus === TxStatus.Pending ? 'Cross-chain swap in progress' : undefined,
|
|
63
96
|
};
|
|
64
97
|
}
|
|
65
|
-
return {
|
|
66
|
-
status: TxStatus.Pending,
|
|
67
|
-
buyTxHash: undefined,
|
|
68
|
-
swapperTxLink: getAxelarscanTrackingLink(txHash),
|
|
69
|
-
message: 'Bridge status check failed - track manually',
|
|
70
|
-
};
|
|
71
98
|
}
|
|
72
|
-
|
|
73
|
-
if (!bridgeStatus) {
|
|
74
|
-
return {
|
|
75
|
-
status: TxStatus.Pending,
|
|
76
|
-
buyTxHash: undefined,
|
|
77
|
-
message: 'Cross-chain swap in progress',
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
const txStatus = (() => {
|
|
81
|
-
switch (bridgeStatus.status) {
|
|
82
|
-
case 'confirmed':
|
|
83
|
-
return TxStatus.Confirmed;
|
|
84
|
-
case 'failed':
|
|
85
|
-
return TxStatus.Failed;
|
|
86
|
-
case 'pending':
|
|
87
|
-
default:
|
|
88
|
-
return TxStatus.Pending;
|
|
89
|
-
}
|
|
90
|
-
})();
|
|
99
|
+
// No indexer knows the tx yet - the bridge may not have picked it up, so keep polling
|
|
91
100
|
return {
|
|
92
|
-
status:
|
|
93
|
-
buyTxHash:
|
|
94
|
-
|
|
95
|
-
message: txStatus === TxStatus.Pending
|
|
96
|
-
? 'Bridge in progress'
|
|
97
|
-
: txStatus === TxStatus.Failed
|
|
98
|
-
? bridgeStatus.errorMessage
|
|
99
|
-
: undefined,
|
|
101
|
+
status: TxStatus.Pending,
|
|
102
|
+
buyTxHash: undefined,
|
|
103
|
+
message: 'Cross-chain swap in progress',
|
|
100
104
|
};
|
|
101
105
|
},
|
|
102
106
|
};
|
|
@@ -6,4 +6,3 @@ export type AxelarscanBridgeStatus = {
|
|
|
6
6
|
errorMessage?: string;
|
|
7
7
|
};
|
|
8
8
|
export declare const fetchAxelarscanBridgeStatus: (sourceTxHash: string) => Promise<Result<AxelarscanBridgeStatus | undefined, SwapErrorRight>>;
|
|
9
|
-
export declare const getAxelarscanTrackingLink: (sourceTxHash: string) => string;
|
|
@@ -13,9 +13,8 @@ export const fetchAxelarscanBridgeStatus = async (sourceTxHash) => {
|
|
|
13
13
|
return Ok(undefined);
|
|
14
14
|
}
|
|
15
15
|
const bridgeData = data.data[0];
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
bridgeData.express_executed?.transactionHash;
|
|
16
|
+
// `call` is the origin call, so only the executed hashes identify the destination leg
|
|
17
|
+
const destinationTxHash = bridgeData.executed?.transaction_hash || bridgeData.express_executed?.transactionHash;
|
|
19
18
|
const isCompleted = bridgeData.status === 'executed' ||
|
|
20
19
|
bridgeData.status === 'destination_executed' ||
|
|
21
20
|
bridgeData.status === 'express_executed' ||
|
|
@@ -44,4 +43,3 @@ export const fetchAxelarscanBridgeStatus = async (sourceTxHash) => {
|
|
|
44
43
|
}));
|
|
45
44
|
}
|
|
46
45
|
};
|
|
47
|
-
export const getAxelarscanTrackingLink = (sourceTxHash) => `https://axelarscan.io/gmp/${sourceTxHash}`;
|
|
@@ -16,9 +16,11 @@ export const fetchPortalsTradeOrder = async ({ sender, inputToken, inputAmount,
|
|
|
16
16
|
validate: validate.toString(),
|
|
17
17
|
});
|
|
18
18
|
if (!autoSlippage) {
|
|
19
|
-
|
|
19
|
+
// Portals API expects a string with at most 2 decimal places
|
|
20
|
+
params.append('slippageTolerancePercentage', slippageTolerancePercentage.toFixed(2));
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
+
// Portals defaults to their own partner fee when this is omitted - always send it, zero included
|
|
23
|
+
if (feePercentage !== undefined) {
|
|
22
24
|
params.append('feePercentage', feePercentage.toString());
|
|
23
25
|
}
|
|
24
26
|
try {
|
|
@@ -44,7 +46,8 @@ export const fetchPortalsTradeEstimate = async ({ inputToken, inputAmount, outpu
|
|
|
44
46
|
outputToken,
|
|
45
47
|
});
|
|
46
48
|
if (slippageTolerancePercentage !== undefined) {
|
|
47
|
-
|
|
49
|
+
// Portals API expects a string with at most 2 decimal places
|
|
50
|
+
params.append('slippageTolerancePercentage', slippageTolerancePercentage.toFixed(2));
|
|
48
51
|
}
|
|
49
52
|
try {
|
|
50
53
|
const response = await axios.get(url, { params });
|
|
@@ -6,4 +6,3 @@ export type SquidBridgeStatus = {
|
|
|
6
6
|
destinationTxHash?: string;
|
|
7
7
|
};
|
|
8
8
|
export declare const fetchSquidBridgeStatus: (sourceTxHash: string, sourceChainId: ChainId, destinationChainId: ChainId) => Promise<Result<SquidBridgeStatus, SwapErrorRight>>;
|
|
9
|
-
export declare const getSquidTrackingLink: (sourceTxHash: string, squidStatus: SquidBridgeStatus, sellAssetExplorerTxLink: string, buyAssetExplorerTxLink: string) => string;
|
|
@@ -44,9 +44,3 @@ export const fetchSquidBridgeStatus = async (sourceTxHash, sourceChainId, destin
|
|
|
44
44
|
}));
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
|
-
export const getSquidTrackingLink = (sourceTxHash, squidStatus, sellAssetExplorerTxLink, buyAssetExplorerTxLink) => {
|
|
48
|
-
if (squidStatus.status === 'confirmed' && squidStatus.destinationTxHash) {
|
|
49
|
-
return `${buyAssetExplorerTxLink}${squidStatus.destinationTxHash}`;
|
|
50
|
-
}
|
|
51
|
-
return `${sellAssetExplorerTxLink}${sourceTxHash}`;
|
|
52
|
-
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fromChainId } from '@shapeshiftoss/caip';
|
|
2
|
+
import { bnOrZero } from '@shapeshiftoss/utils';
|
|
2
3
|
import { Err, Ok } from '@sniptt/monads';
|
|
3
4
|
import { makeNetworkFeeEstimationFailedErr } from '../../../utils/index.js';
|
|
4
5
|
import { estimateGasWithStateOverride, getEvmNetworkFeeCryptoBaseUnit } from '../../../utils/evm/index.js';
|
|
@@ -10,7 +11,7 @@ export async function getPortalsStepData(args) {
|
|
|
10
11
|
if (args.type === 'rate') {
|
|
11
12
|
try {
|
|
12
13
|
// No placeholder estimation for provider built routes - overridden estimation (approval
|
|
13
|
-
// state need not exist yet) with the Portals estimate endpoint as
|
|
14
|
+
// state need not exist yet) with the Portals order and estimate endpoint as fallbacks
|
|
14
15
|
const gasLimit = await (async () => {
|
|
15
16
|
try {
|
|
16
17
|
const gasLimit = await estimateGasWithStateOverride({
|
|
@@ -25,6 +26,10 @@ export async function getPortalsStepData(args) {
|
|
|
25
26
|
return gasLimit;
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
29
|
+
// Portals only carry a tx gas limit on the bridge routes their estimate endpoint zeroes
|
|
30
|
+
const { gasLimit: txGasLimit } = tx;
|
|
31
|
+
if (txGasLimit && bnOrZero(txGasLimit).gt(0))
|
|
32
|
+
return txGasLimit;
|
|
28
33
|
const quoteEstimateResponse = await fetchPortalsTradeEstimate({
|
|
29
34
|
inputToken: args.inputToken,
|
|
30
35
|
outputToken: args.outputToken,
|
|
@@ -32,7 +37,10 @@ export async function getPortalsStepData(args) {
|
|
|
32
37
|
slippageTolerancePercentage: args.slippageTolerancePercentage,
|
|
33
38
|
swapperConfig: deps.config,
|
|
34
39
|
});
|
|
35
|
-
|
|
40
|
+
const estimatedGasLimit = quoteEstimateResponse.context.gasLimit.toString();
|
|
41
|
+
if (bnOrZero(estimatedGasLimit).lte(0))
|
|
42
|
+
throw new Error('no Portals gas limit');
|
|
43
|
+
return estimatedGasLimit;
|
|
36
44
|
}
|
|
37
45
|
})();
|
|
38
46
|
const networkFeeCryptoBaseUnit = await getEvmNetworkFeeCryptoBaseUnit({
|