@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.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/exactOutputFiltering.test.d.ts +1 -0
- package/dist/cjs/exactOutputFiltering.test.js +70 -0
- package/dist/cjs/swapper.d.ts +3 -3
- package/dist/cjs/swapper.js +29 -6
- package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossStepData.d.ts +1 -0
- package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossStepData.js +2 -2
- package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossTradeContext.js +1 -0
- package/dist/cjs/swappers/BebopSwapper/utils/getBebopStepData.d.ts +1 -0
- package/dist/cjs/swappers/BebopSwapper/utils/getBebopStepData.js +2 -2
- package/dist/cjs/swappers/BebopSwapper/utils/getBebopTradeContext.js +1 -0
- 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/DebridgeSwapper/utils/getDebridgeStepData.d.ts +1 -0
- package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeStepData.js +2 -2
- package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeTradeContext.js +1 -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 +4 -1
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.d.ts +2 -1
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +14 -9
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.d.ts +2 -1
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +14 -9
- package/dist/cjs/swappers/NearIntentsSwapper/types.d.ts +3 -1
- package/dist/cjs/swappers/NearIntentsSwapper/utils/exactOutput.test.d.ts +1 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/exactOutput.test.js +61 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.d.ts +2 -2
- package/dist/cjs/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.js +4 -2
- package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.d.ts +5 -5
- package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.js +30 -26
- 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.d.ts +1 -0
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.js +16 -8
- 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 +3 -2
- package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsTradeContext.js +34 -16
- 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 +9 -18
- package/dist/cjs/swappers/RelaySwapper/getTradeQuote/getTradeQuote.d.ts +2 -1
- package/dist/cjs/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +5 -2
- package/dist/cjs/swappers/RelaySwapper/getTradeRate/getTradeRate.d.ts +2 -1
- package/dist/cjs/swappers/RelaySwapper/getTradeRate/getTradeRate.js +5 -2
- package/dist/cjs/swappers/RelaySwapper/utils/getRelayTradeContext.d.ts +2 -2
- package/dist/cjs/swappers/RelaySwapper/utils/getRelayTradeContext.js +22 -10
- package/dist/cjs/swappers/RelaySwapper/utils/helpers.d.ts +2 -2
- 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 +18 -1
- package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.d.ts +1 -0
- package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.js +2 -2
- package/dist/cjs/swappers/SunioSwapper/utils/getSunioTradeContext.js +6 -1
- package/dist/cjs/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +1 -0
- package/dist/cjs/types.d.ts +21 -2
- package/dist/cjs/types.js +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 +9 -0
- package/dist/cjs/utils/helpers.js +23 -1
- package/dist/cjs/utils/helpers.test.js +41 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/exactOutputFiltering.test.d.ts +1 -0
- package/dist/esm/exactOutputFiltering.test.js +68 -0
- package/dist/esm/swapper.d.ts +3 -3
- package/dist/esm/swapper.js +29 -6
- package/dist/esm/swappers/AcrossSwapper/utils/getAcrossStepData.d.ts +1 -0
- package/dist/esm/swappers/AcrossSwapper/utils/getAcrossStepData.js +2 -2
- package/dist/esm/swappers/AcrossSwapper/utils/getAcrossTradeContext.js +1 -0
- package/dist/esm/swappers/BebopSwapper/utils/getBebopStepData.d.ts +1 -0
- package/dist/esm/swappers/BebopSwapper/utils/getBebopStepData.js +2 -2
- package/dist/esm/swappers/BebopSwapper/utils/getBebopTradeContext.js +1 -0
- 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/DebridgeSwapper/utils/getDebridgeStepData.d.ts +1 -0
- package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeStepData.js +2 -2
- package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeTradeContext.js +1 -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 +6 -3
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.d.ts +2 -1
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +7 -3
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.d.ts +2 -1
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +7 -3
- package/dist/esm/swappers/NearIntentsSwapper/types.d.ts +3 -1
- package/dist/esm/swappers/NearIntentsSwapper/utils/exactOutput.test.d.ts +1 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/exactOutput.test.js +59 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.d.ts +2 -2
- package/dist/esm/swappers/NearIntentsSwapper/utils/getNearIntentsTradeContext.js +4 -2
- package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.d.ts +5 -5
- package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.js +32 -28
- 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.d.ts +1 -0
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.js +13 -5
- 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 +3 -2
- package/dist/esm/swappers/PortalsSwapper/utils/getPortalsTradeContext.js +35 -17
- 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 +11 -20
- package/dist/esm/swappers/RelaySwapper/getTradeQuote/getTradeQuote.d.ts +2 -1
- package/dist/esm/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +3 -1
- package/dist/esm/swappers/RelaySwapper/getTradeRate/getTradeRate.d.ts +2 -1
- package/dist/esm/swappers/RelaySwapper/getTradeRate/getTradeRate.js +3 -1
- package/dist/esm/swappers/RelaySwapper/utils/getRelayTradeContext.d.ts +2 -2
- package/dist/esm/swappers/RelaySwapper/utils/getRelayTradeContext.js +23 -11
- package/dist/esm/swappers/RelaySwapper/utils/helpers.d.ts +2 -2
- 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 +18 -1
- package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.d.ts +1 -0
- package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.js +2 -2
- package/dist/esm/swappers/SunioSwapper/utils/getSunioTradeContext.js +6 -1
- package/dist/esm/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +1 -0
- package/dist/esm/types.d.ts +21 -2
- package/dist/esm/types.js +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 +9 -0
- package/dist/esm/utils/helpers.js +20 -0
- package/dist/esm/utils/helpers.test.js +42 -1
- package/package.json +6 -6
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { estimateGasWithStateOverride } from '../../../utils/evm/index.js';
|
|
3
|
+
import { USDC_MAINNET } from '../../../utils/test-data/assets.js';
|
|
4
|
+
import { fetchPortalsTradeEstimate } from './fetchPortalsTradeOrder.js';
|
|
5
|
+
import { getPortalsStepData } from './getPortalsStepData.js';
|
|
6
|
+
vi.mock('../../../utils/evm', async (importOriginal) => ({
|
|
7
|
+
...(await importOriginal()),
|
|
8
|
+
estimateGasWithStateOverride: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
vi.mock('./fetchPortalsTradeOrder', async (importOriginal) => ({
|
|
11
|
+
...(await importOriginal()),
|
|
12
|
+
fetchPortalsTradeEstimate: vi.fn(),
|
|
13
|
+
}));
|
|
14
|
+
const GAS_PRICE = '1000000000';
|
|
15
|
+
const deps = {
|
|
16
|
+
assertGetEvmChainAdapter: () => ({
|
|
17
|
+
getGasFeeData: () => Promise.resolve({
|
|
18
|
+
average: { gasPrice: GAS_PRICE, maxFeePerGas: '0', maxPriorityFeePerGas: '0' },
|
|
19
|
+
}),
|
|
20
|
+
}),
|
|
21
|
+
config: {},
|
|
22
|
+
};
|
|
23
|
+
const tx = (gasLimit) => ({
|
|
24
|
+
to: '0x4cd00e387622c35bddb9b4c962c136462338bc31',
|
|
25
|
+
from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
|
|
26
|
+
data: '0xdeadbeef',
|
|
27
|
+
value: '0',
|
|
28
|
+
gasLimit,
|
|
29
|
+
});
|
|
30
|
+
const rate = (portalsTx) => getPortalsStepData({
|
|
31
|
+
type: 'rate',
|
|
32
|
+
input: { supportsEIP1559: false },
|
|
33
|
+
deps,
|
|
34
|
+
tx: portalsTx,
|
|
35
|
+
sellAsset: USDC_MAINNET,
|
|
36
|
+
sellAmountCryptoBaseUnit: '1000000000',
|
|
37
|
+
spenderAddress: '0x4cd00e387622c35bddb9b4c962c136462338bc31',
|
|
38
|
+
inputToken: 'ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
39
|
+
outputToken: 'arbitrum:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
40
|
+
inputAmount: '1000000000',
|
|
41
|
+
slippageTolerancePercentage: 2.5,
|
|
42
|
+
});
|
|
43
|
+
const estimateEndpointGasLimit = (gasLimit) => vi.mocked(fetchPortalsTradeEstimate).mockResolvedValue({
|
|
44
|
+
context: { gasLimit },
|
|
45
|
+
});
|
|
46
|
+
describe('getPortalsStepData rate gas limit', () => {
|
|
47
|
+
beforeEach(() => vi.clearAllMocks());
|
|
48
|
+
it('falls back to the order gas limit on bridge routes the estimate endpoint zeroes', async () => {
|
|
49
|
+
vi.mocked(estimateGasWithStateOverride).mockRejectedValue(new Error('execution reverted'));
|
|
50
|
+
estimateEndpointGasLimit(0);
|
|
51
|
+
const actual = await rate(tx('76384'));
|
|
52
|
+
expect(actual.unwrap()).toEqual({ networkFeeCryptoBaseUnit: '76384000000000' });
|
|
53
|
+
expect(fetchPortalsTradeEstimate).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
it('falls back to the estimate endpoint when the order carries no gas limit', async () => {
|
|
56
|
+
vi.mocked(estimateGasWithStateOverride).mockRejectedValue(new Error('execution reverted'));
|
|
57
|
+
estimateEndpointGasLimit(273203);
|
|
58
|
+
const actual = await rate(tx(undefined));
|
|
59
|
+
expect(actual.unwrap()).toEqual({ networkFeeCryptoBaseUnit: '273203000000000' });
|
|
60
|
+
});
|
|
61
|
+
it('errors rather than pricing a zero gas limit as a free trade', async () => {
|
|
62
|
+
vi.mocked(estimateGasWithStateOverride).mockRejectedValue(new Error('execution reverted'));
|
|
63
|
+
estimateEndpointGasLimit(0);
|
|
64
|
+
const actual = await rate(tx(undefined));
|
|
65
|
+
expect(actual.isErr()).toBe(true);
|
|
66
|
+
expect(actual.unwrapErr().message).toContain('getPortalsStepData');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -10,16 +10,17 @@ type PortalsTradeContext = {
|
|
|
10
10
|
stepDataArgs: {
|
|
11
11
|
deps: SwapperDeps;
|
|
12
12
|
sellAsset: Asset;
|
|
13
|
+
sellAmountCryptoBaseUnit: string;
|
|
13
14
|
spenderAddress: string;
|
|
14
15
|
tx: PortalsTx;
|
|
15
16
|
};
|
|
16
17
|
};
|
|
17
|
-
export declare const getPortalsTradeContext: ({ input, deps, sellChainId,
|
|
18
|
+
export declare const getPortalsTradeContext: ({ input, deps, sellChainId, orderContext, outputToken, tx, }: {
|
|
18
19
|
input: PortalsTradeQuoteInput | PortalsTradeRateInput;
|
|
19
20
|
deps: SwapperDeps;
|
|
20
21
|
sellChainId: PortalsSupportedChainId;
|
|
21
|
-
inputToken: string;
|
|
22
22
|
orderContext: PortalsTradeOrderResponse['context'];
|
|
23
|
+
outputToken: string;
|
|
23
24
|
tx: PortalsTx;
|
|
24
25
|
}) => Result<PortalsTradeContext, SwapErrorRight>;
|
|
25
26
|
export {};
|
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import { bn, bnOrZero } from '@shapeshiftoss/utils';
|
|
1
|
+
import { BigNumber, bn, bnOrZero } from '@shapeshiftoss/utils';
|
|
2
2
|
import { Err, Ok } from '@sniptt/monads';
|
|
3
3
|
import { SwapperName, TradeQuoteError } from '../../../types.js';
|
|
4
4
|
import { getInputOutputRate, makeSwapErrorRight } from '../../../utils/index.js';
|
|
5
5
|
import { buildAffiliateFee } from '../../../utils/affiliateFee.js';
|
|
6
6
|
import { getPortalsRouterAddressByChainId } from './helpers.js';
|
|
7
|
-
export const getPortalsTradeContext = ({ input, deps, sellChainId,
|
|
8
|
-
const { sellAsset, buyAsset, affiliateBps
|
|
9
|
-
const { orderId, outputAmount, minOutputAmount, target, feeAmount, feeToken } = orderContext;
|
|
7
|
+
export const getPortalsTradeContext = ({ input, deps, sellChainId, orderContext, outputToken, tx, }) => {
|
|
8
|
+
const { sellAsset, buyAsset, affiliateBps } = input;
|
|
9
|
+
const { orderId, inputAmount, outputAmount, minOutputAmount, target, feeAmount, feeToken, slippageTolerancePercentage, } = orderContext;
|
|
10
|
+
// Portals can fill less than we asked for - price against what the transaction actually spends
|
|
11
|
+
const sellAmountIncludingProtocolFeesCryptoBaseUnit = inputAmount;
|
|
10
12
|
const isCrossChain = sellAsset.chainId !== buyAsset.chainId;
|
|
11
|
-
|
|
13
|
+
// Portals report the slippage they applied, not the one we requested - bridge routes apply none
|
|
14
|
+
const appliedSlippageDecimal = bnOrZero(slippageTolerancePercentage).div(100);
|
|
15
|
+
// Unvalidated orders report the post-slippage minimum in both amount fields
|
|
16
|
+
const hasSlippageBuffer = bnOrZero(outputAmount).gt(minOutputAmount);
|
|
17
|
+
const preSlippageOutputAmount = bnOrZero(minOutputAmount)
|
|
18
|
+
.div(bn(1).minus(appliedSlippageDecimal))
|
|
19
|
+
.toFixed(0);
|
|
20
|
+
const buyAmountAfterFeesCryptoBaseUnit = hasSlippageBuffer
|
|
21
|
+
? outputAmount
|
|
22
|
+
: preSlippageOutputAmount;
|
|
23
|
+
const bufferSlippageDecimal = hasSlippageBuffer
|
|
24
|
+
? bnOrZero(outputAmount).minus(minOutputAmount).div(outputAmount)
|
|
25
|
+
: appliedSlippageDecimal;
|
|
26
|
+
const slippageTolerancePercentageDecimal = BigNumber.max(appliedSlippageDecimal, bufferSlippageDecimal).toString();
|
|
12
27
|
const rate = getInputOutputRate({
|
|
13
28
|
sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
14
29
|
buyAmountCryptoBaseUnit: buyAmountAfterFeesCryptoBaseUnit,
|
|
@@ -24,16 +39,13 @@ export const getPortalsTradeContext = ({ input, deps, sellChainId, inputToken, o
|
|
|
24
39
|
details: { chainId: sellChainId },
|
|
25
40
|
}));
|
|
26
41
|
}
|
|
27
|
-
// Portals
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
.div(bn(1).minus(actualBufferDecimal))
|
|
35
|
-
.toFixed(0);
|
|
36
|
-
const protocolFeeAsset = feeToken === inputToken ? sellAsset : buyAsset;
|
|
42
|
+
// Portals lower-case echoed tokens, and take their fee in the sell asset on ERC20 sells
|
|
43
|
+
const isBuyAssetFee = feeToken?.toLowerCase() === outputToken.toLowerCase();
|
|
44
|
+
const protocolFeeAsset = isBuyAssetFee ? buyAsset : sellAsset;
|
|
45
|
+
// Portals report an output already net of their fee
|
|
46
|
+
const buyAmountBeforeFeesCryptoBaseUnit = isBuyAssetFee && feeAmount
|
|
47
|
+
? bnOrZero(buyAmountAfterFeesCryptoBaseUnit).plus(feeAmount).toFixed(0)
|
|
48
|
+
: buyAmountAfterFeesCryptoBaseUnit;
|
|
37
49
|
const protocolFees = (() => {
|
|
38
50
|
if (!feeToken || !feeAmount)
|
|
39
51
|
return;
|
|
@@ -51,7 +63,7 @@ export const getPortalsTradeContext = ({ input, deps, sellChainId, inputToken, o
|
|
|
51
63
|
rate,
|
|
52
64
|
swapperName: SwapperName.Portals,
|
|
53
65
|
affiliateBps,
|
|
54
|
-
slippageTolerancePercentageDecimal
|
|
66
|
+
slippageTolerancePercentageDecimal,
|
|
55
67
|
},
|
|
56
68
|
stepCommon: {
|
|
57
69
|
estimatedExecutionTimeMs: isCrossChain ? 300000 : 0,
|
|
@@ -74,6 +86,12 @@ export const getPortalsTradeContext = ({ input, deps, sellChainId, inputToken, o
|
|
|
74
86
|
}),
|
|
75
87
|
},
|
|
76
88
|
protocolFees,
|
|
77
|
-
stepDataArgs: {
|
|
89
|
+
stepDataArgs: {
|
|
90
|
+
deps,
|
|
91
|
+
sellAsset,
|
|
92
|
+
sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
93
|
+
spenderAddress: allowanceContract,
|
|
94
|
+
tx,
|
|
95
|
+
},
|
|
78
96
|
});
|
|
79
97
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { USDC_ARBITRUM, USDC_MAINNET } from '../../../utils/test-data/assets.js';
|
|
3
|
+
import { getPortalsTradeContext } from './getPortalsTradeContext.js';
|
|
4
|
+
const deps = {};
|
|
5
|
+
const tx = {
|
|
6
|
+
to: '0x4cd00e387622c35bddb9b4c962c136462338bc31',
|
|
7
|
+
from: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
|
|
8
|
+
data: '0xdeadbeef',
|
|
9
|
+
value: '0',
|
|
10
|
+
};
|
|
11
|
+
const makeInput = (buyAsset = USDC_ARBITRUM) => ({
|
|
12
|
+
sellAsset: USDC_MAINNET,
|
|
13
|
+
buyAsset,
|
|
14
|
+
affiliateBps: '0',
|
|
15
|
+
sellAmountIncludingProtocolFeesCryptoBaseUnit: '4631313795',
|
|
16
|
+
});
|
|
17
|
+
const makeOrderContext = (overrides) => ({
|
|
18
|
+
orderId: 'eaae8ea5-30af-4463-97ab-1c5b1fe7def4',
|
|
19
|
+
target: '0x4cd00e387622c35bddb9b4c962c136462338bc31',
|
|
20
|
+
inputAmount: '4631313795',
|
|
21
|
+
...overrides,
|
|
22
|
+
});
|
|
23
|
+
const unwrap = (args) => getPortalsTradeContext(args).unwrap();
|
|
24
|
+
describe('getPortalsTradeContext', () => {
|
|
25
|
+
it('does not gross up a bridge route Portals applied no slippage to', () => {
|
|
26
|
+
const { stepCommon, tradeCommon } = unwrap({
|
|
27
|
+
input: makeInput(),
|
|
28
|
+
deps,
|
|
29
|
+
sellChainId: USDC_MAINNET.chainId,
|
|
30
|
+
orderContext: makeOrderContext({
|
|
31
|
+
outputAmount: '4616564490',
|
|
32
|
+
minOutputAmount: '4616564490',
|
|
33
|
+
slippageTolerancePercentage: 0,
|
|
34
|
+
}),
|
|
35
|
+
outputToken: 'arbitrum:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
36
|
+
tx,
|
|
37
|
+
});
|
|
38
|
+
expect(stepCommon.buyAmountAfterFeesCryptoBaseUnit).toBe('4616564490');
|
|
39
|
+
expect(tradeCommon.slippageTolerancePercentageDecimal).toBe('0');
|
|
40
|
+
});
|
|
41
|
+
it('reverses the applied slippage on an unvalidated order collapsed to its minimum', () => {
|
|
42
|
+
const { stepCommon, tradeCommon } = unwrap({
|
|
43
|
+
input: makeInput(USDC_MAINNET),
|
|
44
|
+
deps,
|
|
45
|
+
sellChainId: USDC_MAINNET.chainId,
|
|
46
|
+
orderContext: makeOrderContext({
|
|
47
|
+
outputAmount: '2360574345',
|
|
48
|
+
minOutputAmount: '2360574345',
|
|
49
|
+
slippageTolerancePercentage: 2.5,
|
|
50
|
+
}),
|
|
51
|
+
outputToken: 'ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
52
|
+
tx,
|
|
53
|
+
});
|
|
54
|
+
// Within 0.01% of the 2420957576 the same order returns when validated
|
|
55
|
+
expect(stepCommon.buyAmountAfterFeesCryptoBaseUnit).toBe('2421101892');
|
|
56
|
+
expect(tradeCommon.slippageTolerancePercentageDecimal).toBe('0.025');
|
|
57
|
+
});
|
|
58
|
+
it('keeps the reported output of a validated order and advertises the wider buffer', () => {
|
|
59
|
+
const { stepCommon, tradeCommon } = unwrap({
|
|
60
|
+
input: makeInput(USDC_MAINNET),
|
|
61
|
+
deps,
|
|
62
|
+
sellChainId: USDC_MAINNET.chainId,
|
|
63
|
+
orderContext: makeOrderContext({
|
|
64
|
+
outputAmount: '2420957576',
|
|
65
|
+
minOutputAmount: '2360574345',
|
|
66
|
+
slippageTolerancePercentage: 2.5,
|
|
67
|
+
}),
|
|
68
|
+
outputToken: 'ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
69
|
+
tx,
|
|
70
|
+
});
|
|
71
|
+
expect(stepCommon.buyAmountAfterFeesCryptoBaseUnit).toBe('2420957576');
|
|
72
|
+
expect(tradeCommon.slippageTolerancePercentageDecimal).toBe('0.025');
|
|
73
|
+
});
|
|
74
|
+
it('prices against the input amount Portals filled rather than the one requested', () => {
|
|
75
|
+
const { stepCommon } = unwrap({
|
|
76
|
+
input: makeInput(),
|
|
77
|
+
deps,
|
|
78
|
+
sellChainId: USDC_MAINNET.chainId,
|
|
79
|
+
orderContext: makeOrderContext({
|
|
80
|
+
// Portals withhold 0.01% of the requested 4631313795 on cross-chain orders
|
|
81
|
+
inputAmount: '4630850664',
|
|
82
|
+
outputAmount: '4616564490',
|
|
83
|
+
minOutputAmount: '4616564490',
|
|
84
|
+
slippageTolerancePercentage: 0,
|
|
85
|
+
}),
|
|
86
|
+
outputToken: 'arbitrum:0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
87
|
+
tx,
|
|
88
|
+
});
|
|
89
|
+
expect(stepCommon.sellAmountIncludingProtocolFeesCryptoBaseUnit).toBe('4630850664');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -6,11 +6,12 @@ import { getUnsignedSolanaTransaction } from '../../utils/solana/getUnsignedSola
|
|
|
6
6
|
import { getTronTransactionFees, getUnsignedTronTransaction } from '../../utils/tron/index.js';
|
|
7
7
|
import { getUnsignedUtxoTransaction, getUtxoTransactionFees } from '../../utils/utxo/index.js';
|
|
8
8
|
import { chainIdToRelayChainId } from './constant.js';
|
|
9
|
-
import { getTradeQuote } from './getTradeQuote/getTradeQuote.js';
|
|
10
|
-
import { getTradeRate } from './getTradeRate/getTradeRate.js';
|
|
9
|
+
import { getExactOutputTradeQuote, getTradeQuote } from './getTradeQuote/getTradeQuote.js';
|
|
10
|
+
import { getExactOutputTradeRate, getTradeRate } from './getTradeRate/getTradeRate.js';
|
|
11
11
|
import { getLatestRelayStatusMessage } from './utils/getLatestRelayStatusMessage.js';
|
|
12
12
|
import { notifyTransactionIndexing } from './utils/notifyTransactionIndexing.js';
|
|
13
13
|
import { getRelayRequestConfig, relayService } from './utils/relayService.js';
|
|
14
|
+
import { getRelayTrackingLink, relayStatusToTxStatus } from './utils/relayStatus.js';
|
|
14
15
|
// Keep track of the trades we already notified the relay indexer about
|
|
15
16
|
const txIndexingMap = new Map();
|
|
16
17
|
export const relayApi = {
|
|
@@ -20,6 +21,12 @@ export const relayApi = {
|
|
|
20
21
|
getTradeRate: (input, deps) => {
|
|
21
22
|
return getTradeRate(input, deps, chainIdToRelayChainId);
|
|
22
23
|
},
|
|
24
|
+
getExactOutputTradeQuote: (input, deps) => {
|
|
25
|
+
return getExactOutputTradeQuote(input, deps, chainIdToRelayChainId);
|
|
26
|
+
},
|
|
27
|
+
getExactOutputTradeRate: (input, deps) => {
|
|
28
|
+
return getExactOutputTradeRate(input, deps, chainIdToRelayChainId);
|
|
29
|
+
},
|
|
23
30
|
getEvmTransactionFees,
|
|
24
31
|
getUnsignedEvmTransaction,
|
|
25
32
|
getUnsignedUtxoTransaction,
|
|
@@ -60,7 +67,7 @@ export const relayApi = {
|
|
|
60
67
|
}
|
|
61
68
|
// relay.link tracks the swap by its origin chain transaction
|
|
62
69
|
const swapperTxId = txHash;
|
|
63
|
-
const swapperTxLink =
|
|
70
|
+
const swapperTxLink = getRelayTrackingLink(txHash);
|
|
64
71
|
const maybeStatusResponse = await relayService.get(`${config.VITE_RELAY_API_URL}/intents/status/v3?requestId=${relayMetadata.relayId}`, getRelayRequestConfig(config));
|
|
65
72
|
if (maybeStatusResponse.isErr()) {
|
|
66
73
|
return {
|
|
@@ -72,23 +79,7 @@ export const relayApi = {
|
|
|
72
79
|
};
|
|
73
80
|
}
|
|
74
81
|
const { data: statusResponse } = maybeStatusResponse.unwrap();
|
|
75
|
-
const status = (
|
|
76
|
-
switch (statusResponse.status) {
|
|
77
|
-
case 'success':
|
|
78
|
-
return TxStatus.Confirmed;
|
|
79
|
-
case 'waiting':
|
|
80
|
-
case 'delayed':
|
|
81
|
-
case 'pending':
|
|
82
|
-
case 'depositing':
|
|
83
|
-
case 'submitted':
|
|
84
|
-
return TxStatus.Pending;
|
|
85
|
-
case 'failure':
|
|
86
|
-
case 'refund':
|
|
87
|
-
return TxStatus.Failed;
|
|
88
|
-
default:
|
|
89
|
-
return TxStatus.Unknown;
|
|
90
|
-
}
|
|
91
|
-
})();
|
|
82
|
+
const status = relayStatusToTxStatus(statusResponse.status);
|
|
92
83
|
// Relay refers to in Txs as "inTxHashes" but to out Txs as simply "txHashes" when they really mean "outTxHashes"
|
|
93
84
|
// One thing to note is that for same-chain Txs, there is no "out Tx" per se since the in Tx *is* the out Tx
|
|
94
85
|
const outTxHashes = statusResponse.txHashes;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Result } from '@sniptt/monads';
|
|
2
2
|
import type { SwapErrorRight, SwapperDeps, TradeQuote } from '../../../types.js';
|
|
3
3
|
import type { chainIdToRelayChainId as relayChainMapImplementation } from '../constant.js';
|
|
4
|
-
import type { RelayTradeQuoteInput } from '../utils/types.js';
|
|
4
|
+
import type { RelayExactOutputTradeQuoteInput, RelayTradeQuoteInput } from '../utils/types.js';
|
|
5
5
|
export declare const getTradeQuote: (input: RelayTradeQuoteInput, deps: SwapperDeps, relayChainMap: typeof relayChainMapImplementation) => Promise<Result<TradeQuote[], SwapErrorRight>>;
|
|
6
|
+
export declare const getExactOutputTradeQuote: (input: RelayExactOutputTradeQuoteInput, deps: SwapperDeps, relayChainMap: typeof relayChainMapImplementation) => Promise<Result<TradeQuote[], SwapErrorRight>>;
|
|
@@ -3,7 +3,7 @@ import { assertQuoteAddresses } from '../../../utils/index.js';
|
|
|
3
3
|
import { FALLBACK_QUOTE_DEADLINE_MS } from '../../../utils/helpers.js';
|
|
4
4
|
import { getRelayStepData } from '../utils/getRelayStepData.js';
|
|
5
5
|
import { getRelayTradeContext } from '../utils/getRelayTradeContext.js';
|
|
6
|
-
|
|
6
|
+
const getQuote = async (input, deps, relayChainMap) => {
|
|
7
7
|
const { accountNumber } = input;
|
|
8
8
|
const addresses = assertQuoteAddresses(input);
|
|
9
9
|
if (addresses.isErr())
|
|
@@ -49,3 +49,5 @@ export const getTradeQuote = async (input, deps, relayChainMap) => {
|
|
|
49
49
|
};
|
|
50
50
|
return Ok([tradeQuote]);
|
|
51
51
|
};
|
|
52
|
+
export const getTradeQuote = (input, deps, relayChainMap) => getQuote(input, deps, relayChainMap);
|
|
53
|
+
export const getExactOutputTradeQuote = (input, deps, relayChainMap) => getQuote(input, deps, relayChainMap);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Result } from '@sniptt/monads';
|
|
2
2
|
import type { SwapErrorRight, SwapperDeps, TradeRate } from '../../../types.js';
|
|
3
3
|
import type { chainIdToRelayChainId as relayChainMapImplementation } from '../constant.js';
|
|
4
|
-
import type { RelayTradeRateInput } from '../utils/types.js';
|
|
4
|
+
import type { RelayExactOutputTradeRateInput, RelayTradeRateInput } from '../utils/types.js';
|
|
5
5
|
export declare const getTradeRate: (input: RelayTradeRateInput, deps: SwapperDeps, relayChainMap: typeof relayChainMapImplementation) => Promise<Result<TradeRate[], SwapErrorRight>>;
|
|
6
|
+
export declare const getExactOutputTradeRate: (input: RelayExactOutputTradeRateInput, deps: SwapperDeps, relayChainMap: typeof relayChainMapImplementation) => Promise<Result<TradeRate[], SwapErrorRight>>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Err, Ok } from '@sniptt/monads';
|
|
2
2
|
import { getRelayStepData } from '../utils/getRelayStepData.js';
|
|
3
3
|
import { getRelayTradeContext } from '../utils/getRelayTradeContext.js';
|
|
4
|
-
|
|
4
|
+
const getRate = async (input, deps, relayChainMap) => {
|
|
5
5
|
const maybeContext = await getRelayTradeContext({ input, deps, relayChainMap });
|
|
6
6
|
if (maybeContext.isErr())
|
|
7
7
|
return Err(maybeContext.unwrapErr());
|
|
@@ -36,3 +36,5 @@ export const getTradeRate = async (input, deps, relayChainMap) => {
|
|
|
36
36
|
};
|
|
37
37
|
return Ok([tradeRate]);
|
|
38
38
|
};
|
|
39
|
+
export const getTradeRate = (input, deps, relayChainMap) => getRate(input, deps, relayChainMap);
|
|
40
|
+
export const getExactOutputTradeRate = (input, deps, relayChainMap) => getRate(input, deps, relayChainMap);
|
|
@@ -2,7 +2,7 @@ import type { Result } from '@sniptt/monads';
|
|
|
2
2
|
import type { QuoteFeeData, SwapErrorRight, SwapperDeps, TradeCommon, TradeStepCommon } from '../../../types.js';
|
|
3
3
|
import type { chainIdToRelayChainId as relayChainMapImplementation } from '../constant.js';
|
|
4
4
|
import type { GetRelayStepDataArgs } from './getRelayStepData.js';
|
|
5
|
-
import type { RelayQuoteItem, RelayTradeQuoteInput, RelayTradeRateInput } from './types.js';
|
|
5
|
+
import type { RelayExactOutputTradeQuoteInput, RelayExactOutputTradeRateInput, RelayQuoteItem, RelayTradeQuoteInput, RelayTradeRateInput } from './types.js';
|
|
6
6
|
type RelayTradeContext = {
|
|
7
7
|
tradeCommon: TradeCommon;
|
|
8
8
|
stepCommon: Omit<TradeStepCommon, 'feeData' | 'allowanceContract'>;
|
|
@@ -15,7 +15,7 @@ type RelayTradeContext = {
|
|
|
15
15
|
relayId: string;
|
|
16
16
|
};
|
|
17
17
|
export declare const getRelayTradeContext: ({ input, deps, relayChainMap, }: {
|
|
18
|
-
input: RelayTradeQuoteInput | RelayTradeRateInput;
|
|
18
|
+
input: RelayTradeQuoteInput | RelayTradeRateInput | RelayExactOutputTradeQuoteInput | RelayExactOutputTradeRateInput;
|
|
19
19
|
deps: SwapperDeps;
|
|
20
20
|
relayChainMap: typeof relayChainMapImplementation;
|
|
21
21
|
}) => Promise<Result<RelayTradeContext, SwapErrorRight>>;
|
|
@@ -7,7 +7,7 @@ import { zeroAddress } from 'viem';
|
|
|
7
7
|
import { MixPanelEvent, SwapperName, TradeQuoteError } from '../../../types.js';
|
|
8
8
|
import { getInputOutputRate, makeSwapErrorRight } from '../../../utils/index.js';
|
|
9
9
|
import { buildAffiliateFee } from '../../../utils/affiliateFee.js';
|
|
10
|
-
import { isNativeEvmAsset } from '../../../utils/helpers.js';
|
|
10
|
+
import { getTradeAmount, isNativeEvmAsset } from '../../../utils/helpers.js';
|
|
11
11
|
import { MAXIMUM_SUPPORTED_RELAY_STEPS, relayErrorCodeToTradeQuoteError } from '../constant.js';
|
|
12
12
|
import { getRelayAssetAddress } from '../utils/getRelayAssetAddress.js';
|
|
13
13
|
import { relayTokenToAsset } from '../utils/relayTokenToAsset.js';
|
|
@@ -16,7 +16,9 @@ import { fetchRelayTrade } from './fetchRelayTrade.js';
|
|
|
16
16
|
import { assertValidTrade, getRelayAllowanceContract, resolveRelayAddresses } from './helpers.js';
|
|
17
17
|
import { isRelayError } from './types.js';
|
|
18
18
|
export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
19
|
-
const { sellAsset, buyAsset,
|
|
19
|
+
const { sellAsset, buyAsset, affiliateBps } = input;
|
|
20
|
+
const amount = getTradeAmount(input);
|
|
21
|
+
const isExactOutput = amount.direction === 'exactOut';
|
|
20
22
|
const xpub = 'xpub' in input ? input.xpub : undefined;
|
|
21
23
|
const slippageToleranceBps = input.slippageTolerancePercentageDecimal
|
|
22
24
|
? convertDecimalPercentageToBasisPoints(input.slippageTolerancePercentageDecimal).toFixed()
|
|
@@ -35,8 +37,8 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
35
37
|
originCurrency: getRelayAssetAddress(sellAsset),
|
|
36
38
|
destinationChainId: buyRelayChainId,
|
|
37
39
|
destinationCurrency: getRelayAssetAddress(buyAsset),
|
|
38
|
-
tradeType: 'EXACT_INPUT',
|
|
39
|
-
amount:
|
|
40
|
+
tradeType: isExactOutput ? 'EXACT_OUTPUT' : 'EXACT_INPUT',
|
|
41
|
+
amount: amount.cryptoBaseUnit,
|
|
40
42
|
recipient,
|
|
41
43
|
user: sendAddress,
|
|
42
44
|
refundTo,
|
|
@@ -78,10 +80,19 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
78
80
|
code: TradeQuoteError.UnknownError,
|
|
79
81
|
}));
|
|
80
82
|
}
|
|
81
|
-
const { slippageTolerance, currencyOut, timeEstimate } = quote.details;
|
|
82
|
-
const
|
|
83
|
+
const { slippageTolerance, currencyIn, currencyOut, timeEstimate } = quote.details;
|
|
84
|
+
const sellAmountCryptoBaseUnit = currencyIn.amount;
|
|
85
|
+
const buyAmountAfterFeesCryptoBaseUnit = isExactOutput
|
|
86
|
+
? currencyOut.minimumAmount
|
|
87
|
+
: currencyOut.amount;
|
|
88
|
+
if (isExactOutput && !bnOrZero(buyAmountAfterFeesCryptoBaseUnit).eq(amount.cryptoBaseUnit)) {
|
|
89
|
+
return Err(makeSwapErrorRight({
|
|
90
|
+
message: `Relay guarantees ${buyAmountAfterFeesCryptoBaseUnit} against a requested exact output of ${amount.cryptoBaseUnit}`,
|
|
91
|
+
code: TradeQuoteError.InvalidResponse,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
83
94
|
const rate = getInputOutputRate({
|
|
84
|
-
sellAmountCryptoBaseUnit
|
|
95
|
+
sellAmountCryptoBaseUnit,
|
|
85
96
|
buyAmountCryptoBaseUnit: buyAmountAfterFeesCryptoBaseUnit,
|
|
86
97
|
sellAsset,
|
|
87
98
|
buyAsset,
|
|
@@ -242,7 +253,7 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
242
253
|
})();
|
|
243
254
|
// Add back relayer service and gas fees (relayer is including both) since they are downsides,
|
|
244
255
|
// and add appFees — these are quote-level and identical across every step
|
|
245
|
-
const buyAmountBeforeFeesCryptoBaseUnit = bnOrZero(
|
|
256
|
+
const buyAmountBeforeFeesCryptoBaseUnit = bnOrZero(buyAmountAfterFeesCryptoBaseUnit)
|
|
246
257
|
.plus(relayerFeesBuyAssetCryptoBaseUnit)
|
|
247
258
|
.plus(appFeesBaseUnit)
|
|
248
259
|
.toFixed();
|
|
@@ -256,6 +267,7 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
256
267
|
id: relayId,
|
|
257
268
|
rate,
|
|
258
269
|
swapperName: SwapperName.Relay,
|
|
270
|
+
isExactOutput,
|
|
259
271
|
affiliateBps,
|
|
260
272
|
slippageTolerancePercentageDecimal,
|
|
261
273
|
},
|
|
@@ -263,7 +275,7 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
263
275
|
rate,
|
|
264
276
|
buyAmountBeforeFeesCryptoBaseUnit,
|
|
265
277
|
buyAmountAfterFeesCryptoBaseUnit,
|
|
266
|
-
sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
278
|
+
sellAmountIncludingProtocolFeesCryptoBaseUnit: sellAmountCryptoBaseUnit,
|
|
267
279
|
buyAsset,
|
|
268
280
|
sellAsset,
|
|
269
281
|
source: SwapperName.Relay,
|
|
@@ -273,7 +285,7 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
273
285
|
affiliateBps,
|
|
274
286
|
sellAsset,
|
|
275
287
|
buyAsset,
|
|
276
|
-
sellAmountCryptoBaseUnit
|
|
288
|
+
sellAmountCryptoBaseUnit,
|
|
277
289
|
buyAmountCryptoBaseUnit: buyAmountAfterFeesCryptoBaseUnit,
|
|
278
290
|
fixedAssetId: chainIdToFeeAssetId(baseChainId),
|
|
279
291
|
fixedAsset: deps.assetsById[chainIdToFeeAssetId(baseChainId)],
|
|
@@ -291,7 +303,7 @@ export const getRelayTradeContext = async ({ input, deps, relayChainMap, }) => {
|
|
|
291
303
|
relayStepInputs,
|
|
292
304
|
stepDataArgs: {
|
|
293
305
|
sellAsset,
|
|
294
|
-
sellAmountCryptoBaseUnit
|
|
306
|
+
sellAmountCryptoBaseUnit,
|
|
295
307
|
orderId,
|
|
296
308
|
from: sendAddress,
|
|
297
309
|
xpub,
|
|
@@ -4,7 +4,7 @@ import type { Result } from '@sniptt/monads';
|
|
|
4
4
|
import type { TransactionInstruction } from '@solana/web3.js';
|
|
5
5
|
import type { SwapErrorRight } from '../../../types.js';
|
|
6
6
|
import type { chainIdToRelayChainId as relayChainMapImplementation } from '../constant.js';
|
|
7
|
-
import type { RelayQuoteItem, RelaySolanaInstruction, RelayTradeQuoteInput, RelayTradeRateInput } from './types.js';
|
|
7
|
+
import type { RelayExactOutputTradeQuoteInput, RelayExactOutputTradeRateInput, RelayQuoteItem, RelaySolanaInstruction, RelayTradeQuoteInput, RelayTradeRateInput } from './types.js';
|
|
8
8
|
export declare const assertValidTrade: ({ sellAsset, buyAsset, relayChainMap, }: {
|
|
9
9
|
sellAsset: Asset;
|
|
10
10
|
buyAsset: Asset;
|
|
@@ -14,7 +14,7 @@ export declare const assertValidTrade: ({ sellAsset, buyAsset, relayChainMap, }:
|
|
|
14
14
|
buyRelayChainId: number;
|
|
15
15
|
}, SwapErrorRight>;
|
|
16
16
|
export declare const resolveRelayAddresses: ({ input, sellChainId, buyChainId, }: {
|
|
17
|
-
input: RelayTradeQuoteInput | RelayTradeRateInput;
|
|
17
|
+
input: RelayTradeQuoteInput | RelayTradeRateInput | RelayExactOutputTradeQuoteInput | RelayExactOutputTradeRateInput;
|
|
18
18
|
sellChainId: ChainId;
|
|
19
19
|
buyChainId: ChainId;
|
|
20
20
|
}) => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TxStatus } from '@shapeshiftoss/unchained-client';
|
|
2
|
+
import type { Result } from '@sniptt/monads';
|
|
3
|
+
import type { SwapErrorRight, SwapperConfig } from '../../../types.js';
|
|
4
|
+
import type { RelayRequest, RelayStatus } from './types.js';
|
|
5
|
+
export declare const getRelayTrackingLink: (txHash: string) => string;
|
|
6
|
+
export declare const relayStatusToTxStatus: (status: RelayStatus['status'] | undefined) => TxStatus;
|
|
7
|
+
export declare const fetchRelayRequestByTxHash: (txHash: string, config: SwapperConfig) => Promise<Result<RelayRequest | undefined, SwapErrorRight>>;
|
|
8
|
+
export declare const getRelayRequestFailureMessage: (request: RelayRequest) => string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TxStatus } from '@shapeshiftoss/unchained-client';
|
|
2
|
+
import { getRelayRequestConfig, relayService } from './relayService.js';
|
|
3
|
+
export const getRelayTrackingLink = (txHash) => `https://relay.link/transaction/${txHash}`;
|
|
4
|
+
export const relayStatusToTxStatus = (status) => {
|
|
5
|
+
switch (status) {
|
|
6
|
+
case 'success':
|
|
7
|
+
return TxStatus.Confirmed;
|
|
8
|
+
case 'waiting':
|
|
9
|
+
case 'delayed':
|
|
10
|
+
case 'pending':
|
|
11
|
+
case 'depositing':
|
|
12
|
+
case 'submitted':
|
|
13
|
+
return TxStatus.Pending;
|
|
14
|
+
case 'failure':
|
|
15
|
+
case 'refund':
|
|
16
|
+
return TxStatus.Failed;
|
|
17
|
+
default:
|
|
18
|
+
return TxStatus.Unknown;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
// Relay index requests by origin tx hash, resolving a swap we hold no relayId for
|
|
22
|
+
export const fetchRelayRequestByTxHash = async (txHash, config) => {
|
|
23
|
+
const maybeResponse = await relayService.get(`${config.VITE_RELAY_API_URL}/requests/v2?hash=${txHash}`, getRelayRequestConfig(config));
|
|
24
|
+
// Match the origin tx ourselves rather than trusting the listing to have filtered on it
|
|
25
|
+
return maybeResponse.map(({ data }) => data.requests?.find(({ data: request }) => request?.inTxs?.some(({ hash }) => hash?.toLowerCase() === txHash.toLowerCase())));
|
|
26
|
+
};
|
|
27
|
+
export const getRelayRequestFailureMessage = (request) => {
|
|
28
|
+
const { failReason, refundFailReason } = request.data ?? {};
|
|
29
|
+
// Relay report 'N/A' rather than omitting the reason when there isn't one
|
|
30
|
+
const reason = [failReason, refundFailReason].find(value => value && value !== 'N/A');
|
|
31
|
+
return reason ?? 'Bridge failed';
|
|
32
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { GetEvmTradeQuoteInput, GetEvmTradeRateInput, GetSolanaTradeQuoteInput, GetSolanaTradeRateInput, GetTronTradeQuoteInput, GetTronTradeRateInput, GetUtxoTradeQuoteInput, GetUtxoTradeRateInput } from '../../../types.js';
|
|
1
|
+
import type { GetEvmTradeQuoteInput, GetEvmTradeRateInput, GetSolanaTradeQuoteInput, GetSolanaTradeRateInput, GetTronTradeQuoteInput, GetTronTradeRateInput, GetUtxoTradeQuoteInput, GetUtxoTradeRateInput, WithExactBuyAmount } from '../../../types.js';
|
|
2
2
|
export type RelayTradeQuoteInput = GetEvmTradeQuoteInput | GetUtxoTradeQuoteInput | GetSolanaTradeQuoteInput | GetTronTradeQuoteInput;
|
|
3
3
|
export type RelayTradeRateInput = GetEvmTradeRateInput | GetUtxoTradeRateInput | GetSolanaTradeRateInput | GetTronTradeRateInput;
|
|
4
|
+
export type RelayExactOutputTradeQuoteInput = WithExactBuyAmount<RelayTradeQuoteInput>;
|
|
5
|
+
export type RelayExactOutputTradeRateInput = WithExactBuyAmount<RelayTradeRateInput>;
|
|
4
6
|
export type RelayTransactionMetadata = {
|
|
5
7
|
to?: string;
|
|
6
8
|
data?: string;
|
|
@@ -10,6 +12,20 @@ export type RelayMetadata = {
|
|
|
10
12
|
relayId: string;
|
|
11
13
|
data?: string;
|
|
12
14
|
};
|
|
15
|
+
export type RelayRequestTransaction = {
|
|
16
|
+
hash?: string;
|
|
17
|
+
chainId?: number;
|
|
18
|
+
};
|
|
19
|
+
export type RelayRequestData = {
|
|
20
|
+
failReason?: string;
|
|
21
|
+
refundFailReason?: string;
|
|
22
|
+
inTxs?: RelayRequestTransaction[];
|
|
23
|
+
outTxs?: RelayRequestTransaction[];
|
|
24
|
+
};
|
|
25
|
+
export type RelayRequest = {
|
|
26
|
+
status?: RelayStatus['status'];
|
|
27
|
+
data?: RelayRequestData;
|
|
28
|
+
};
|
|
13
29
|
export type RelayStatus = {
|
|
14
30
|
status: 'success' | 'failure' | 'pending' | 'submitted' | 'depositing' | 'refund' | 'delayed' | 'waiting';
|
|
15
31
|
details?: string;
|
|
@@ -64,6 +80,7 @@ export type RelayFees = {
|
|
|
64
80
|
app: RelayCurrencyData;
|
|
65
81
|
};
|
|
66
82
|
export type QuoteDetails = {
|
|
83
|
+
currencyIn: RelayCurrencyData;
|
|
67
84
|
currencyOut: RelayCurrencyData;
|
|
68
85
|
rate: string;
|
|
69
86
|
slippageTolerance: {
|
|
@@ -3,6 +3,7 @@ import type { StepDataArgs, SwapErrorRight } from '../../../types.js';
|
|
|
3
3
|
import type { SunioRoute, SunioTransactionData } from '../types.js';
|
|
4
4
|
type BaseArgs = {
|
|
5
5
|
route: SunioRoute;
|
|
6
|
+
sellAmountCryptoBaseUnit: string;
|
|
6
7
|
};
|
|
7
8
|
export type GetSunioStepDataArgs = StepDataArgs<BaseArgs>;
|
|
8
9
|
type SunioRateStepData = {
|
|
@@ -3,12 +3,12 @@ import { Err, Ok } from '@sniptt/monads';
|
|
|
3
3
|
import { makeNetworkFeeEstimationFailedErr } from '../../../utils/index.js';
|
|
4
4
|
import { estimateSunioNetworkFeeCryptoBaseUnit } from './estimateSunioNetworkFee.js';
|
|
5
5
|
export async function getSunioStepData(args) {
|
|
6
|
-
const { type, route, sellAsset, from, input, deps } = args;
|
|
6
|
+
const { type, route, sellAsset, sellAmountCryptoBaseUnit, from, input, deps } = args;
|
|
7
7
|
const estimateArgs = {
|
|
8
8
|
rpcUrl: deps.config.VITE_TRON_NODE_URL,
|
|
9
9
|
apiKey: deps.config.VITE_TRON_GRID_API_KEY,
|
|
10
10
|
route,
|
|
11
|
-
sellAmountCryptoBaseUnit
|
|
11
|
+
sellAmountCryptoBaseUnit,
|
|
12
12
|
isSellingNativeTrx: !contractAddressOrUndefined(sellAsset.assetId),
|
|
13
13
|
address: from,
|
|
14
14
|
slippageTolerancePercentageDecimal: input.slippageTolerancePercentageDecimal,
|
|
@@ -80,7 +80,12 @@ export const getSunioTradeContext = async ({ input, deps, }) => {
|
|
|
80
80
|
}),
|
|
81
81
|
},
|
|
82
82
|
protocolFees,
|
|
83
|
-
stepDataArgs: {
|
|
83
|
+
stepDataArgs: {
|
|
84
|
+
deps,
|
|
85
|
+
sellAsset,
|
|
86
|
+
sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
87
|
+
route: bestRoute,
|
|
88
|
+
},
|
|
84
89
|
});
|
|
85
90
|
}
|
|
86
91
|
catch (error) {
|
|
@@ -1016,6 +1016,7 @@
|
|
|
1016
1016
|
"eip155:1/erc20:0x826180541412d574cf1336d22c0c0a287822678a",
|
|
1017
1017
|
"eip155:1/erc20:0x2c06ba9e7f0daccbc1f6a33ea67e85bb68fbee3a",
|
|
1018
1018
|
"eip155:1/erc20:0xcbb8f1bda10b9696c57e13bc128fe674769dcec0",
|
|
1019
|
+
"eip155:1/erc20:0x72dfb2e44f59c5ad2bafe84314e5b99a7cd5075e",
|
|
1019
1020
|
"eip155:43114/erc20:0xc891eb4cbdeff6e073e859e987815ed1505c2acd",
|
|
1020
1021
|
"eip155:43114/erc20:0xd24c2ad096400b6fbcd2ad8b24e7acbc21a1da64",
|
|
1021
1022
|
"eip155:43114/erc20:0x47c3118ad183712acd42648e9e522e13690f29a0",
|