@shapeshiftoss/swapper 17.6.5 → 17.6.6-alpha.1
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/constants.js +17 -8
- package/dist/cjs/swappers/NearIntentsSwapper/NearIntentsSwapper.d.ts +2 -0
- package/dist/cjs/swappers/NearIntentsSwapper/NearIntentsSwapper.js +11 -0
- package/dist/cjs/swappers/NearIntentsSwapper/constants.d.ts +3 -0
- package/dist/cjs/swappers/NearIntentsSwapper/constants.js +6 -0
- package/dist/cjs/swappers/NearIntentsSwapper/endpoints.d.ts +2 -0
- package/dist/cjs/swappers/NearIntentsSwapper/endpoints.js +165 -0
- package/dist/cjs/swappers/NearIntentsSwapper/index.d.ts +4 -0
- package/dist/cjs/swappers/NearIntentsSwapper/index.js +20 -0
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.d.ts +3 -0
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +209 -0
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.d.ts +3 -0
- package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +208 -0
- package/dist/cjs/swappers/NearIntentsSwapper/types.d.ts +6 -0
- package/dist/cjs/swappers/NearIntentsSwapper/types.js +32 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers/helpers.d.ts +12 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers/helpers.js +99 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/oneClickService.d.ts +3 -0
- package/dist/cjs/swappers/NearIntentsSwapper/utils/oneClickService.js +16 -0
- package/dist/cjs/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.js +55 -12
- package/dist/cjs/swappers/RelaySwapper/constant.js +1 -0
- package/dist/cjs/swappers/RelaySwapper/utils/fetchRelayTrade.d.ts +1 -1
- package/dist/cjs/swappers/RelaySwapper/utils/getRelayPsbtRelayer.js +2 -2
- package/dist/cjs/swappers/RelaySwapper/utils/getTrade.js +45 -0
- package/dist/cjs/swappers/RelaySwapper/utils/notifyTransactionIndexing.d.ts +1 -1
- package/dist/cjs/swappers/RelaySwapper/utils/relayTokenToAssetId.js +0 -2
- package/dist/cjs/swappers/RelaySwapper/utils/types.d.ts +1 -0
- package/dist/cjs/swappers/RelaySwapper/utils/types.js +1 -0
- package/dist/cjs/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +3153 -3153
- package/dist/cjs/swappers/ThorchainSwapper/generated/generatedTradableAssetMap.json +6 -6
- package/dist/cjs/swappers/ZrxSwapper/utils/helpers/helpers.js +1 -3
- package/dist/cjs/thorchain-utils/getL1RateOrQuote.js +20 -17
- package/dist/cjs/types.d.ts +18 -1
- package/dist/cjs/types.js +1 -0
- package/dist/cjs/utils/tenderly/index.d.ts +3 -0
- package/dist/cjs/utils/tenderly/index.js +19 -0
- package/dist/cjs/utils/tenderly/simulate.d.ts +20 -0
- package/dist/cjs/utils/tenderly/simulate.js +109 -0
- package/dist/cjs/utils/tenderly/storageSlots.d.ts +8 -0
- package/dist/cjs/utils/tenderly/storageSlots.js +94 -0
- package/dist/cjs/utils/tenderly/types.d.ts +56 -0
- package/dist/cjs/utils/tenderly/types.js +2 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/constants.js +9 -0
- package/dist/esm/swappers/NearIntentsSwapper/NearIntentsSwapper.d.ts +2 -0
- package/dist/esm/swappers/NearIntentsSwapper/NearIntentsSwapper.js +8 -0
- package/dist/esm/swappers/NearIntentsSwapper/constants.d.ts +3 -0
- package/dist/esm/swappers/NearIntentsSwapper/constants.js +3 -0
- package/dist/esm/swappers/NearIntentsSwapper/endpoints.d.ts +2 -0
- package/dist/esm/swappers/NearIntentsSwapper/endpoints.js +162 -0
- package/dist/esm/swappers/NearIntentsSwapper/index.d.ts +4 -0
- package/dist/esm/swappers/NearIntentsSwapper/index.js +4 -0
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.d.ts +3 -0
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.js +205 -0
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.d.ts +3 -0
- package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +204 -0
- package/dist/esm/swappers/NearIntentsSwapper/types.d.ts +6 -0
- package/dist/esm/swappers/NearIntentsSwapper/types.js +28 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/helpers/helpers.d.ts +12 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/helpers/helpers.js +91 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/oneClickService.d.ts +3 -0
- package/dist/esm/swappers/NearIntentsSwapper/utils/oneClickService.js +12 -0
- package/dist/esm/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.js +59 -16
- package/dist/esm/swappers/RelaySwapper/constant.js +1 -0
- package/dist/esm/swappers/RelaySwapper/utils/fetchRelayTrade.d.ts +1 -1
- package/dist/esm/swappers/RelaySwapper/utils/getRelayPsbtRelayer.js +2 -2
- package/dist/esm/swappers/RelaySwapper/utils/getTrade.js +47 -2
- package/dist/esm/swappers/RelaySwapper/utils/notifyTransactionIndexing.d.ts +1 -1
- package/dist/esm/swappers/RelaySwapper/utils/relayTokenToAssetId.js +0 -2
- package/dist/esm/swappers/RelaySwapper/utils/types.d.ts +1 -0
- package/dist/esm/swappers/RelaySwapper/utils/types.js +1 -0
- package/dist/esm/swappers/ThorchainSwapper/generated/generatedThorLongtailTokens.json +3153 -3153
- package/dist/esm/swappers/ThorchainSwapper/generated/generatedTradableAssetMap.json +6 -6
- package/dist/esm/swappers/ZrxSwapper/utils/helpers/helpers.js +1 -3
- package/dist/esm/thorchain-utils/getL1RateOrQuote.js +20 -17
- package/dist/esm/types.d.ts +18 -1
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/tenderly/index.d.ts +3 -0
- package/dist/esm/utils/tenderly/index.js +3 -0
- package/dist/esm/utils/tenderly/simulate.d.ts +20 -0
- package/dist/esm/utils/tenderly/simulate.js +102 -0
- package/dist/esm/utils/tenderly/storageSlots.d.ts +8 -0
- package/dist/esm/utils/tenderly/storageSlots.js +86 -0
- package/dist/esm/utils/tenderly/types.d.ts +56 -0
- package/dist/esm/utils/tenderly/types.js +1 -0
- package/package.json +31 -5
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { KnownChainIds } from '@shapeshiftoss/types';
|
|
2
|
+
export { QuoteRequest } from '@defuse-protocol/one-click-sdk-typescript';
|
|
3
|
+
export const nearIntentsSupportedChainIds = [
|
|
4
|
+
KnownChainIds.EthereumMainnet,
|
|
5
|
+
KnownChainIds.ArbitrumMainnet,
|
|
6
|
+
KnownChainIds.BaseMainnet,
|
|
7
|
+
KnownChainIds.GnosisMainnet,
|
|
8
|
+
KnownChainIds.BnbSmartChainMainnet,
|
|
9
|
+
KnownChainIds.PolygonMainnet,
|
|
10
|
+
KnownChainIds.AvalancheMainnet,
|
|
11
|
+
KnownChainIds.OptimismMainnet,
|
|
12
|
+
KnownChainIds.BitcoinMainnet,
|
|
13
|
+
KnownChainIds.DogecoinMainnet,
|
|
14
|
+
KnownChainIds.SolanaMainnet,
|
|
15
|
+
];
|
|
16
|
+
export const chainIdToNearIntentsChain = {
|
|
17
|
+
[KnownChainIds.EthereumMainnet]: 'eth',
|
|
18
|
+
[KnownChainIds.ArbitrumMainnet]: 'arb',
|
|
19
|
+
[KnownChainIds.BaseMainnet]: 'base',
|
|
20
|
+
[KnownChainIds.GnosisMainnet]: 'gnosis',
|
|
21
|
+
[KnownChainIds.BnbSmartChainMainnet]: 'bsc',
|
|
22
|
+
[KnownChainIds.PolygonMainnet]: 'pol',
|
|
23
|
+
[KnownChainIds.AvalancheMainnet]: 'avax',
|
|
24
|
+
[KnownChainIds.OptimismMainnet]: 'op',
|
|
25
|
+
[KnownChainIds.BitcoinMainnet]: 'btc',
|
|
26
|
+
[KnownChainIds.DogecoinMainnet]: 'doge',
|
|
27
|
+
[KnownChainIds.SolanaMainnet]: 'sol',
|
|
28
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Asset } from '@shapeshiftoss/types';
|
|
2
|
+
import { TxStatus } from '@shapeshiftoss/unchained-client';
|
|
3
|
+
import type { TransactionInstruction } from '@solana/web3.js';
|
|
4
|
+
import type { GetExecutionStatusResponse } from '../../types.js';
|
|
5
|
+
export declare const calculateAccountCreationCosts: (instructions: TransactionInstruction[]) => string;
|
|
6
|
+
export declare const getNearIntentsAsset: ({ nearNetwork, contractAddress, }: {
|
|
7
|
+
nearNetwork: string;
|
|
8
|
+
contractAddress: string;
|
|
9
|
+
}) => string;
|
|
10
|
+
export declare const assetToNearIntentsAsset: (asset: Asset) => Promise<string | null>;
|
|
11
|
+
export declare const mapNearIntentsStatus: (status: GetExecutionStatusResponse['status']) => TxStatus;
|
|
12
|
+
export declare const getNearIntentsStatusMessage: (status: GetExecutionStatusResponse['status']) => string | undefined;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ASSOCIATED_PROGRAM_ID } from '@coral-xyz/anchor/dist/cjs/utils/token';
|
|
2
|
+
import { fromAssetId, solanaChainId } from '@shapeshiftoss/caip';
|
|
3
|
+
import { TxStatus } from '@shapeshiftoss/unchained-client';
|
|
4
|
+
import { bnOrZero, isToken } from '@shapeshiftoss/utils';
|
|
5
|
+
import { zeroAddress } from 'viem';
|
|
6
|
+
import { chainIdToNearIntentsChain } from '../../types.js';
|
|
7
|
+
import { OneClickService } from '../oneClickService.js';
|
|
8
|
+
const ATA_RENT_LAMPORTS = 2040000;
|
|
9
|
+
export const calculateAccountCreationCosts = (instructions) => {
|
|
10
|
+
let totalCost = bnOrZero(0);
|
|
11
|
+
for (const ix of instructions) {
|
|
12
|
+
if (ix.programId.toString() === ASSOCIATED_PROGRAM_ID.toString()) {
|
|
13
|
+
totalCost = totalCost.plus(ATA_RENT_LAMPORTS);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return totalCost.toString();
|
|
17
|
+
};
|
|
18
|
+
export const getNearIntentsAsset = ({ nearNetwork, contractAddress, }) => {
|
|
19
|
+
// Native EVM assets: "nep141:eth.omft.near"
|
|
20
|
+
if (contractAddress === zeroAddress) {
|
|
21
|
+
return `nep141:${nearNetwork}.omft.near`;
|
|
22
|
+
}
|
|
23
|
+
// ERC20 tokens: "nep141:eth-0x{address}.omft.near"
|
|
24
|
+
return `nep141:${nearNetwork}-${contractAddress.toLowerCase()}.omft.near`;
|
|
25
|
+
};
|
|
26
|
+
const NEP245_CHAINS = ['bsc', 'pol', 'avax', 'op'];
|
|
27
|
+
export const assetToNearIntentsAsset = async (asset) => {
|
|
28
|
+
const nearNetwork = chainIdToNearIntentsChain[asset.chainId];
|
|
29
|
+
if (!nearNetwork)
|
|
30
|
+
return null;
|
|
31
|
+
// NEP-245 chains (BSC, Polygon, Avalanche, Optimism) and Solana require token lookup
|
|
32
|
+
// Asset IDs use hashed format that can't be generated from contract addresses
|
|
33
|
+
const requiresLookup = NEP245_CHAINS.includes(nearNetwork) || asset.chainId === solanaChainId;
|
|
34
|
+
if (requiresLookup) {
|
|
35
|
+
const tokens = await OneClickService.getTokens();
|
|
36
|
+
const contractAddress = isToken(asset.assetId)
|
|
37
|
+
? fromAssetId(asset.assetId).assetReference.toLowerCase()
|
|
38
|
+
: null;
|
|
39
|
+
const match = tokens.find((t) => {
|
|
40
|
+
if (t.blockchain !== nearNetwork)
|
|
41
|
+
return false;
|
|
42
|
+
return contractAddress
|
|
43
|
+
? t.contractAddress?.toLowerCase() === contractAddress
|
|
44
|
+
: !t.contractAddress;
|
|
45
|
+
});
|
|
46
|
+
if (!match)
|
|
47
|
+
return null;
|
|
48
|
+
return match.assetId;
|
|
49
|
+
}
|
|
50
|
+
// NEP-141 chains (ETH, ARB, BASE, GNOSIS, BTC, DOGE): use predictable format
|
|
51
|
+
const contractAddress = isToken(asset.assetId)
|
|
52
|
+
? fromAssetId(asset.assetId).assetReference
|
|
53
|
+
: zeroAddress;
|
|
54
|
+
return getNearIntentsAsset({ nearNetwork, contractAddress });
|
|
55
|
+
};
|
|
56
|
+
export const mapNearIntentsStatus = (status) => {
|
|
57
|
+
switch (status) {
|
|
58
|
+
case 'PENDING_DEPOSIT':
|
|
59
|
+
case 'KNOWN_DEPOSIT_TX':
|
|
60
|
+
case 'PROCESSING':
|
|
61
|
+
return TxStatus.Pending;
|
|
62
|
+
case 'SUCCESS':
|
|
63
|
+
return TxStatus.Confirmed;
|
|
64
|
+
case 'INCOMPLETE_DEPOSIT':
|
|
65
|
+
case 'REFUNDED':
|
|
66
|
+
case 'FAILED':
|
|
67
|
+
return TxStatus.Failed;
|
|
68
|
+
default:
|
|
69
|
+
return TxStatus.Unknown;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
export const getNearIntentsStatusMessage = (status) => {
|
|
73
|
+
switch (status) {
|
|
74
|
+
case 'PENDING_DEPOSIT':
|
|
75
|
+
return 'Waiting for deposit...';
|
|
76
|
+
case 'KNOWN_DEPOSIT_TX':
|
|
77
|
+
return 'Deposit detected, waiting for confirmation...';
|
|
78
|
+
case 'PROCESSING':
|
|
79
|
+
return 'Processing swap...';
|
|
80
|
+
case 'SUCCESS':
|
|
81
|
+
return undefined;
|
|
82
|
+
case 'INCOMPLETE_DEPOSIT':
|
|
83
|
+
return 'Insufficient deposit amount';
|
|
84
|
+
case 'REFUNDED':
|
|
85
|
+
return 'Swap failed, funds refunded';
|
|
86
|
+
case 'FAILED':
|
|
87
|
+
return 'Swap failed';
|
|
88
|
+
default:
|
|
89
|
+
return 'Unknown status';
|
|
90
|
+
}
|
|
91
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ApiError, OneClickService, OpenAPI } from '@defuse-protocol/one-click-sdk-typescript';
|
|
2
|
+
import { ONE_CLICK_BASE_URL } from '../constants.js';
|
|
3
|
+
let isInitialized = false;
|
|
4
|
+
export const initializeOneClickService = (apiKey) => {
|
|
5
|
+
if (isInitialized)
|
|
6
|
+
return;
|
|
7
|
+
OpenAPI.BASE = ONE_CLICK_BASE_URL;
|
|
8
|
+
OpenAPI.TOKEN = apiKey;
|
|
9
|
+
isInitialized = true;
|
|
10
|
+
};
|
|
11
|
+
// Re-export the service and types for convenience
|
|
12
|
+
export { ApiError, OneClickService };
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { fromAssetId } from '@shapeshiftoss/caip';
|
|
2
2
|
import { evm } from '@shapeshiftoss/chain-adapters';
|
|
3
|
-
import { bn, bnOrZero } from '@shapeshiftoss/utils';
|
|
3
|
+
import { bn, bnOrZero, convertBasisPointsToDecimalPercentage } from '@shapeshiftoss/utils';
|
|
4
4
|
import { Err, Ok } from '@sniptt/monads';
|
|
5
5
|
import { v4 as uuid } from 'uuid';
|
|
6
|
-
import { zeroAddress } from 'viem';
|
|
6
|
+
import { getAddress, zeroAddress } from 'viem';
|
|
7
7
|
import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../index.js';
|
|
8
8
|
import { SwapperName, TradeQuoteError } from '../../../types.js';
|
|
9
9
|
import { getInputOutputRate, makeSwapErrorRight } from '../../../utils.js';
|
|
10
|
-
import {
|
|
10
|
+
import { simulateWithStateOverrides } from '../../../utils/tenderly/index.js';
|
|
11
|
+
import { getTreasuryAddressFromChainId, isNativeEvmAsset } from '../../utils/helpers/helpers.js';
|
|
11
12
|
import { chainIdToPortalsNetwork } from '../constants.js';
|
|
12
|
-
import { fetchPortalsTradeEstimate } from '../utils/fetchPortalsTradeOrder.js';
|
|
13
|
+
import { fetchPortalsTradeEstimate, fetchPortalsTradeOrder } from '../utils/fetchPortalsTradeOrder.js';
|
|
13
14
|
import { getPortalsRouterAddressByChainId, isSupportedChainId } from '../utils/helpers.js';
|
|
14
15
|
export async function getPortalsTradeRate(input, assertGetEvmChainAdapter, swapperConfig) {
|
|
15
|
-
const { sellAsset, buyAsset, accountNumber, affiliateBps, chainId, sellAmountIncludingProtocolFeesCryptoBaseUnit, receiveAddress, } = input;
|
|
16
|
+
const { sellAsset, buyAsset, accountNumber, affiliateBps, chainId, sellAmountIncludingProtocolFeesCryptoBaseUnit, receiveAddress, supportsEIP1559, } = input;
|
|
16
17
|
const adapter = assertGetEvmChainAdapter(chainId);
|
|
17
18
|
const sellAssetChainId = sellAsset.chainId;
|
|
18
19
|
const buyAssetChainId = buyAsset.chainId;
|
|
@@ -61,16 +62,32 @@ export async function getPortalsTradeRate(input, assertGetEvmChainAdapter, swapp
|
|
|
61
62
|
: bnOrZero(getDefaultSlippageDecimalPercentageForSwapper(SwapperName.Portals))
|
|
62
63
|
.times(100)
|
|
63
64
|
.toNumber();
|
|
64
|
-
|
|
65
|
+
// Calculate affiliate fee percentage (e.g., 55 bps = 0.55%)
|
|
66
|
+
const affiliateBpsPercentage = convertBasisPointsToDecimalPercentage(affiliateBps)
|
|
67
|
+
.times(100)
|
|
68
|
+
.toNumber();
|
|
69
|
+
// Dummy address for rates (no wallet connected yet)
|
|
70
|
+
// Using Vitalik's address as a realistic test address (same approach as Bebop)
|
|
71
|
+
const RATE_DUMMY_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
|
|
72
|
+
// Use full quote endpoint (not estimate) to get transaction data for Tenderly simulation
|
|
73
|
+
// Skip validation since this is just a rate quote
|
|
74
|
+
const quoteResponse = await fetchPortalsTradeOrder({
|
|
75
|
+
sender: RATE_DUMMY_ADDRESS,
|
|
65
76
|
inputToken,
|
|
66
77
|
outputToken,
|
|
67
78
|
inputAmount: sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
68
79
|
slippageTolerancePercentage: userSlippageTolerancePercentageDecimalOrDefault,
|
|
80
|
+
partner: getTreasuryAddressFromChainId(chainId),
|
|
81
|
+
feePercentage: affiliateBpsPercentage,
|
|
82
|
+
validate: false,
|
|
69
83
|
swapperConfig,
|
|
70
84
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
if (!quoteResponse.tx) {
|
|
86
|
+
throw new Error('Portals quote response missing transaction data');
|
|
87
|
+
}
|
|
88
|
+
const { context, tx } = quoteResponse;
|
|
89
|
+
// Use outputAmount from context, not estimate
|
|
90
|
+
const buyAmountAfterFeesCryptoBaseUnit = context.outputAmount;
|
|
74
91
|
const inputOutputRate = getInputOutputRate({
|
|
75
92
|
sellAmountCryptoBaseUnit: input.sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
76
93
|
buyAmountCryptoBaseUnit: buyAmountAfterFeesCryptoBaseUnit,
|
|
@@ -80,21 +97,47 @@ export async function getPortalsTradeRate(input, assertGetEvmChainAdapter, swapp
|
|
|
80
97
|
const allowanceContract = getPortalsRouterAddressByChainId(chainId);
|
|
81
98
|
// Don't use Portals' slippageTolerancePercentage field (it's a price indicator, not actual buffer)
|
|
82
99
|
// Instead, calculate the actual buffer Portals applied from the amounts
|
|
83
|
-
const actualBufferDecimal = bnOrZero(
|
|
84
|
-
.minus(
|
|
85
|
-
.div(
|
|
100
|
+
const actualBufferDecimal = bnOrZero(context.outputAmount)
|
|
101
|
+
.minus(context.minOutputAmount)
|
|
102
|
+
.div(context.outputAmount)
|
|
86
103
|
.toString();
|
|
87
104
|
// Reverse the buffer to recover the expected output (minOutput / (1 - buffer) = output)
|
|
88
|
-
const buyAmountBeforeSlippageCryptoBaseUnit = bnOrZero(
|
|
105
|
+
const buyAmountBeforeSlippageCryptoBaseUnit = bnOrZero(context.minOutputAmount)
|
|
89
106
|
.div(bn(1).minus(actualBufferDecimal))
|
|
90
107
|
.toFixed(0);
|
|
91
108
|
const slippageTolerancePercentageDecimal = actualBufferDecimal;
|
|
92
|
-
const gasLimit =
|
|
109
|
+
const gasLimit = await (async () => {
|
|
110
|
+
const tenderlySimulation = await simulateWithStateOverrides({
|
|
111
|
+
chainId: sellAsset.chainId,
|
|
112
|
+
from: tx.from,
|
|
113
|
+
to: tx.to,
|
|
114
|
+
data: tx.data,
|
|
115
|
+
value: tx.value,
|
|
116
|
+
sellAsset,
|
|
117
|
+
spenderAddress: getAddress(context.target),
|
|
118
|
+
}, {
|
|
119
|
+
apiKey: swapperConfig.VITE_TENDERLY_API_KEY,
|
|
120
|
+
accountSlug: swapperConfig.VITE_TENDERLY_ACCOUNT_SLUG,
|
|
121
|
+
projectSlug: swapperConfig.VITE_TENDERLY_PROJECT_SLUG,
|
|
122
|
+
});
|
|
123
|
+
if (tenderlySimulation.success) {
|
|
124
|
+
return tenderlySimulation.gasLimit.toString();
|
|
125
|
+
}
|
|
126
|
+
// Fallback to estimate endpoint (i.e simulation with overrides failed, but Portals still able to do their magic here)
|
|
127
|
+
const quoteEstimateResponse = await fetchPortalsTradeEstimate({
|
|
128
|
+
inputToken,
|
|
129
|
+
outputToken,
|
|
130
|
+
inputAmount: sellAmountIncludingProtocolFeesCryptoBaseUnit,
|
|
131
|
+
slippageTolerancePercentage: userSlippageTolerancePercentageDecimalOrDefault,
|
|
132
|
+
swapperConfig,
|
|
133
|
+
});
|
|
134
|
+
return quoteEstimateResponse.context.gasLimit.toString();
|
|
135
|
+
})();
|
|
93
136
|
const { average } = await adapter.getGasFeeData();
|
|
94
137
|
const networkFeeCryptoBaseUnit = evm.calcNetworkFeeCryptoBaseUnit({
|
|
95
138
|
...average,
|
|
96
|
-
supportsEIP1559: Boolean(
|
|
97
|
-
gasLimit
|
|
139
|
+
supportsEIP1559: Boolean(supportsEIP1559),
|
|
140
|
+
gasLimit,
|
|
98
141
|
});
|
|
99
142
|
const tradeRate = {
|
|
100
143
|
id: uuid(),
|
|
@@ -49,6 +49,7 @@ export const DEFAULT_RELAY_SOLANA_USER_ADDRESS = 'CbKGgVKLJFb8bBrf58DnAkdryX6ube
|
|
|
49
49
|
export const MAXIMUM_SUPPORTED_RELAY_STEPS = 2;
|
|
50
50
|
export const relayErrorCodeToTradeQuoteError = {
|
|
51
51
|
[RelayErrorCode.AmountTooLow]: TradeQuoteError.SellAmountBelowMinimum,
|
|
52
|
+
[RelayErrorCode.ChainDisabled]: TradeQuoteError.TradingHalted,
|
|
52
53
|
[RelayErrorCode.Erc20RouterAddressNotFound]: TradeQuoteError.UnsupportedTradePair,
|
|
53
54
|
[RelayErrorCode.ExtraTransactionsNotSupported]: TradeQuoteError.UnsupportedTradePair,
|
|
54
55
|
[RelayErrorCode.InsufficientFunds]: TradeQuoteError.SellAmountBelowTradeFee,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Result } from '@sniptt/monads';
|
|
2
2
|
import type { AxiosResponse } from 'axios';
|
|
3
|
-
import type { SwapErrorRight, SwapperConfig } from '
|
|
3
|
+
import type { SwapErrorRight, SwapperConfig } from '../../../types.js';
|
|
4
4
|
import type { RelayFetchQuoteParams, RelayQuote } from './types.js';
|
|
5
5
|
export declare const fetchRelayTrade: <T extends "rate" | "quote">(params: RelayFetchQuoteParams<T>, config: SwapperConfig) => Promise<Result<AxiosResponse<RelayQuote, any>, SwapErrorRight>>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as bitcoin from '@shapeshiftoss/bitcoinjs-lib';
|
|
2
2
|
export const getRelayPsbtRelayer = (psbtHex, sellAmountCryptoBaseUnit) => {
|
|
3
3
|
const psbtBuffer = Buffer.from(psbtHex, 'hex');
|
|
4
|
-
const psbt = bitcoin.Psbt.fromBuffer(
|
|
4
|
+
const psbt = bitcoin.Psbt.fromBuffer(psbtBuffer);
|
|
5
5
|
const outputs = psbt.txOutputs;
|
|
6
6
|
for (let i = 0; i < outputs.length; i++) {
|
|
7
7
|
const output = outputs[i];
|
|
@@ -9,7 +9,7 @@ export const getRelayPsbtRelayer = (psbtHex, sellAmountCryptoBaseUnit) => {
|
|
|
9
9
|
try {
|
|
10
10
|
const address = bitcoin.address.fromOutputScript(script);
|
|
11
11
|
// Assuming the destination address is the one with the exact amount of sellAmountCryptoBaseUnit
|
|
12
|
-
if (output.value ===
|
|
12
|
+
if (output.value === Number(sellAmountCryptoBaseUnit)) {
|
|
13
13
|
return address;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { btcChainId, fromChainId, solanaChainId } from '@shapeshiftoss/caip';
|
|
2
|
-
import { isEvmChainId } from '@shapeshiftoss/chain-adapters';
|
|
2
|
+
import { evm, isEvmChainId } from '@shapeshiftoss/chain-adapters';
|
|
3
3
|
import { bnOrZero, convertBasisPointsToPercentage, convertDecimalPercentageToBasisPoints, convertPrecision, DAO_TREASURY_BASE, } from '@shapeshiftoss/utils';
|
|
4
4
|
import { Err, Ok } from '@sniptt/monads';
|
|
5
5
|
import { PublicKey } from '@solana/web3.js';
|
|
6
6
|
import axios from 'axios';
|
|
7
|
-
import { zeroAddress } from 'viem';
|
|
7
|
+
import { getAddress, zeroAddress } from 'viem';
|
|
8
8
|
import { MixPanelEvent, SwapperName, TradeQuoteError } from '../../../types.js';
|
|
9
9
|
import { getInputOutputRate, makeSwapErrorRight } from '../../../utils.js';
|
|
10
|
+
import { simulateWithStateOverrides } from '../../../utils/tenderly/index.js';
|
|
10
11
|
import { isNativeEvmAsset } from '../../utils/helpers/helpers.js';
|
|
11
12
|
import { MAXIMUM_SUPPORTED_RELAY_STEPS, relayErrorCodeToTradeQuoteError } from '../constant.js';
|
|
12
13
|
import { getRelayAssetAddress } from '../utils/getRelayAssetAddress.js';
|
|
@@ -126,6 +127,11 @@ export async function getTrade({ input, deps, relayChainMap, }) {
|
|
|
126
127
|
code: tradeQuoteErrorCode,
|
|
127
128
|
}));
|
|
128
129
|
}
|
|
130
|
+
// Fallback for unmapped error codes (shouldn't happen, but prevents crashes)
|
|
131
|
+
return Err(makeSwapErrorRight({
|
|
132
|
+
message: relayError.message || 'Unknown Relay error',
|
|
133
|
+
code: TradeQuoteError.UnknownError,
|
|
134
|
+
}));
|
|
129
135
|
}
|
|
130
136
|
const { data: quote } = maybeQuote.unwrap();
|
|
131
137
|
const { slippageTolerance, currencyOut, timeEstimate } = quote.details;
|
|
@@ -327,6 +333,45 @@ export async function getTrade({ input, deps, relayChainMap, }) {
|
|
|
327
333
|
const feeData = await adapter.getFeeData(getFeeDataInput);
|
|
328
334
|
return feeData.fast.txFee;
|
|
329
335
|
}
|
|
336
|
+
// Use Tenderly simulation with state overrides for EVM chains
|
|
337
|
+
if (isEvmChainId(sellAsset.chainId)) {
|
|
338
|
+
const firstStep = swapSteps[0];
|
|
339
|
+
const selectedItem = firstStep?.items?.[0];
|
|
340
|
+
if (selectedItem?.data && isRelayQuoteEvmItemData(selectedItem.data)) {
|
|
341
|
+
try {
|
|
342
|
+
const tenderlySimulation = await simulateWithStateOverrides({
|
|
343
|
+
chainId: sellAsset.chainId,
|
|
344
|
+
// NOTE: zeroAddress is here purely for the purpose of satisfying the type sistem
|
|
345
|
+
// That should never happen
|
|
346
|
+
from: getAddress(sendAddress ?? zeroAddress),
|
|
347
|
+
to: getAddress(selectedItem.data.to ?? zeroAddress),
|
|
348
|
+
data: (selectedItem.data.data ?? '0x'),
|
|
349
|
+
value: selectedItem.data.value ?? '0',
|
|
350
|
+
sellAsset,
|
|
351
|
+
}, {
|
|
352
|
+
apiKey: deps.config.VITE_TENDERLY_API_KEY,
|
|
353
|
+
accountSlug: deps.config.VITE_TENDERLY_ACCOUNT_SLUG,
|
|
354
|
+
projectSlug: deps.config.VITE_TENDERLY_PROJECT_SLUG,
|
|
355
|
+
});
|
|
356
|
+
if (tenderlySimulation.success) {
|
|
357
|
+
// Use Tenderly's gas estimate instead of Relay's
|
|
358
|
+
const adapter = deps.assertGetEvmChainAdapter(sellAsset.chainId);
|
|
359
|
+
const { average } = await adapter.getGasFeeData();
|
|
360
|
+
const supportsEIP1559 = 'maxFeePerGas' in average;
|
|
361
|
+
const tenderlyNetworkFee = evm.calcNetworkFeeCryptoBaseUnit({
|
|
362
|
+
...average,
|
|
363
|
+
supportsEIP1559,
|
|
364
|
+
gasLimit: tenderlySimulation.gasLimit.toString(),
|
|
365
|
+
});
|
|
366
|
+
return tenderlyNetworkFee;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
// Silently fall through to use Relay's gas estimate
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Fallback to Relay's gas amount
|
|
330
375
|
return quote.fees.gas.amount;
|
|
331
376
|
})();
|
|
332
377
|
const steps = swapSteps.map((quoteStep) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Result } from '@sniptt/monads';
|
|
2
2
|
import type { AxiosResponse } from 'axios';
|
|
3
|
-
import type { SwapErrorRight, SwapperConfig } from '
|
|
3
|
+
import type { SwapErrorRight, SwapperConfig } from '../../../types.js';
|
|
4
4
|
import type { RelayQuote } from './types.js';
|
|
5
5
|
type NotifyTransactionIndexingParams = {
|
|
6
6
|
requestId: string;
|
|
@@ -20,8 +20,6 @@ export const relayTokenToAssetId = (relayToken) => {
|
|
|
20
20
|
if (!isNativeAsset) {
|
|
21
21
|
const assetNamespace = (() => {
|
|
22
22
|
switch (true) {
|
|
23
|
-
case CHAIN_REFERENCE.BnbSmartChainMainnet === chainReference:
|
|
24
|
-
return ASSET_NAMESPACE.bep20;
|
|
25
23
|
case isEvmChainId(chainId):
|
|
26
24
|
return ASSET_NAMESPACE.erc20;
|
|
27
25
|
case CHAIN_REFERENCE.SolanaMainnet === chainReference:
|
|
@@ -131,6 +131,7 @@ export type RelaySolanaInstruction = {
|
|
|
131
131
|
};
|
|
132
132
|
export declare enum RelayErrorCode {
|
|
133
133
|
AmountTooLow = "AMOUNT_TOO_LOW",
|
|
134
|
+
ChainDisabled = "CHAIN_DISABLED",
|
|
134
135
|
Erc20RouterAddressNotFound = "ERC20_ROUTER_ADDRESS_NOT_FOUND",
|
|
135
136
|
ExtraTransactionsNotSupported = "EXTRA_TXS_NOT_SUPPORTED",
|
|
136
137
|
InsufficientFunds = "INSUFFICIENT_FUNDS",
|
|
@@ -10,6 +10,7 @@ export const isRelayQuoteSolanaItemData = (item) => {
|
|
|
10
10
|
export var RelayErrorCode;
|
|
11
11
|
(function (RelayErrorCode) {
|
|
12
12
|
RelayErrorCode["AmountTooLow"] = "AMOUNT_TOO_LOW";
|
|
13
|
+
RelayErrorCode["ChainDisabled"] = "CHAIN_DISABLED";
|
|
13
14
|
RelayErrorCode["Erc20RouterAddressNotFound"] = "ERC20_ROUTER_ADDRESS_NOT_FOUND";
|
|
14
15
|
RelayErrorCode["ExtraTransactionsNotSupported"] = "EXTRA_TXS_NOT_SUPPORTED";
|
|
15
16
|
RelayErrorCode["InsufficientFunds"] = "INSUFFICIENT_FUNDS";
|