@reservoir0x/relay-kit-ui
Version:
Relay is the Fastest and Cheapest Way to Bridge and Transact Across Chains.
245 lines • 11.4 kB
JavaScript
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
import { useMemo, useState, useEffect, useContext } from 'react';
import { parseUnits } from 'viem';
import {} from '@reservoir0x/relay-sdk';
import { calculateFillTime, extractDepositRequestId } from '../../../utils/relayTransaction.js';
import { useQuote, useRequests, useExecutionStatus } from '@reservoir0x/relay-kit-hooks';
import { useRelayClient } from '../../../hooks/index.js';
import { EventNames } from '../../../constants/events.js';
import { ProviderOptionsContext } from '../../../providers/RelayKitProvider.js';
import { useAccount } from 'wagmi';
import { calculatePriceTimeEstimate, extractDepositAddress, extractQuoteId } from '../../../utils/quote.js';
import { getDeadAddress } from '@reservoir0x/relay-sdk';
import { useQueryClient } from '@tanstack/react-query';
import { bitcoin } from '../../../utils/bitcoin.js';
import { errorToJSON } from '../../../utils/errors.js';
import { sha256 } from '../../../utils/hashing.js';
import { get15MinuteInterval } from '../../../utils/time.js';
export var TransactionProgressStep;
(function (TransactionProgressStep) {
TransactionProgressStep[TransactionProgressStep["WaitingForDeposit"] = 0] = "WaitingForDeposit";
TransactionProgressStep[TransactionProgressStep["Validating"] = 1] = "Validating";
TransactionProgressStep[TransactionProgressStep["Success"] = 2] = "Success";
TransactionProgressStep[TransactionProgressStep["Error"] = 3] = "Error";
})(TransactionProgressStep || (TransactionProgressStep = {}));
export const DepositAddressModalRenderer = ({ open, address, fromChain, fromToken, toToken, debouncedInputAmountValue, debouncedOutputAmountValue, recipient, invalidateBalanceQueries, children, onSuccess, onAnalyticEvent, onSwapError }) => {
const queryClient = useQueryClient();
const [progressStep, setProgressStep] = useState(TransactionProgressStep.WaitingForDeposit);
const [swapError, setSwapError] = useState(null);
const relayClient = useRelayClient();
const providerOptionsContext = useContext(ProviderOptionsContext);
const { connector } = useAccount();
const deadAddress = getDeadAddress(fromChain?.vmType, fromChain?.id);
const quoteParameters = fromToken && toToken
? {
user: deadAddress,
originChainId: fromToken.chainId,
destinationChainId: toToken.chainId,
originCurrency: fromToken.address,
destinationCurrency: toToken.address,
recipient: recipient,
tradeType: 'EXACT_INPUT',
appFees: providerOptionsContext.appFees,
amount: parseUnits(debouncedInputAmountValue, fromToken.decimals).toString(),
referrer: relayClient?.source ?? undefined,
useDepositAddress: true
}
: undefined;
const { data: quoteData, isLoading: isFetchingQuote, isRefetching, error: quoteError, queryKey } = useQuote(relayClient ? relayClient : undefined, undefined, quoteParameters, (options, config) => {
const interval = get15MinuteInterval();
const quoteRequestId = sha256({ ...options, interval });
onAnalyticEvent?.(EventNames.QUOTE_REQUESTED, {
parameters: options,
httpConfig: config,
quote_request_id: quoteRequestId,
chain_id_in: options?.originChainId,
chain_id_out: options?.destinationChainId
});
}, ({ steps, details }, options) => {
const interval = get15MinuteInterval();
const quoteRequestId = sha256({ ...options, interval });
onAnalyticEvent?.(EventNames.QUOTE_RECEIVED, {
parameters: options,
wallet_connector: connector?.name,
quote_id: steps ? extractQuoteId(steps) : undefined,
quote_request_id: quoteRequestId,
amount_in: details?.currencyIn?.amountFormatted,
amount_in_raw: details?.currencyIn?.amount,
currency_in: details?.currencyIn?.currency?.symbol,
chain_id_in: details?.currencyIn?.currency?.chainId,
amount_out: details?.currencyOut?.amountFormatted,
amount_out_raw: details?.currencyOut?.amount,
currency_out: details?.currencyOut?.currency?.symbol,
chain_id_out: details?.currencyOut?.currency?.chainId,
slippage_tolerance_destination_percentage: details?.slippageTolerance?.destination?.percent,
slippage_tolerance_origin_percentage: details?.slippageTolerance?.origin?.percent,
steps
});
}, {
enabled: Boolean(open &&
progressStep === TransactionProgressStep.WaitingForDeposit &&
relayClient &&
debouncedInputAmountValue &&
debouncedInputAmountValue.length > 0 &&
Number(debouncedInputAmountValue) !== 0 &&
fromToken !== undefined &&
toToken !== undefined),
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchInterval: false,
refetchOnMount: false,
retryOnMount: false,
staleTime: Infinity
}, (e) => {
const errorMessage = errorToJSON(e?.response?.data?.message ? new Error(e?.response?.data?.message) : e);
const interval = get15MinuteInterval();
const quoteRequestId = sha256({ ...quoteParameters, interval });
onAnalyticEvent?.(EventNames.QUOTE_ERROR, {
wallet_connector: connector?.name,
error_message: errorMessage,
parameters: quoteParameters,
quote_request_id: quoteRequestId
});
});
const quote = isFetchingQuote || isRefetching ? undefined : quoteData;
const requestId = useMemo(() => extractDepositRequestId(quote?.steps), [quote]);
const depositAddress = useMemo(() => extractDepositAddress(quote?.steps), [quote]);
useEffect(() => {
if (!open) {
if (quote) {
onAnalyticEvent?.(EventNames.DEPOSIT_ADDRESS_MODAL_CLOSED);
}
setSwapError(null);
queryClient.invalidateQueries({ queryKey });
}
else {
setProgressStep(TransactionProgressStep.WaitingForDeposit);
onAnalyticEvent?.(EventNames.DEPOSIT_ADDRESS_MODAL_OPEN);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open]);
const { data: executionStatus } = useExecutionStatus(relayClient ? relayClient : undefined, {
requestId: requestId ?? undefined,
referrer: relayClient?.source
}, undefined, undefined, {
enabled: requestId !== null && open,
refetchInterval(query) {
const observableStates = ['waiting', 'pending', 'delayed'];
if (!query.state.data?.status ||
(requestId && observableStates.includes(query.state.data?.status))) {
return 1000;
}
return 0;
}
});
useEffect(() => {
if (executionStatus?.status === 'failure' ||
executionStatus?.status === 'refund' ||
quoteError) {
const swapError = new Error(executionStatus?.details ??
'Oops! Something went wrong while processing your transaction.');
if (progressStep !== TransactionProgressStep.Error) {
onSwapError?.(swapError.message, quote);
}
setProgressStep(TransactionProgressStep.Error);
onAnalyticEvent?.(EventNames.DEPOSIT_ADDRESS_SWAP_ERROR, {
error_message: errorToJSON(executionStatus?.details ?? quoteError),
wallet_connector: connector?.name,
quote_id: requestId,
amount_in: parseFloat(`${debouncedInputAmountValue}`),
currency_in: fromToken?.symbol,
chain_id_in: fromToken?.chainId,
amount_out: parseFloat(`${debouncedOutputAmountValue}`),
currency_out: toToken?.symbol,
chain_id_out: toToken?.chainId,
txHashes: executionStatus?.txHashes ?? []
});
setSwapError(swapError);
invalidateBalanceQueries();
}
else if (executionStatus?.status === 'success') {
if (progressStep !== TransactionProgressStep.Success) {
onSuccess?.(quote, executionStatus);
}
setProgressStep(TransactionProgressStep.Success);
invalidateBalanceQueries();
}
else if (executionStatus?.status === 'pending') {
const timeEstimateMs = ((quote?.details?.timeEstimate ?? 0) +
(fromChain && fromChain.id === bitcoin.id ? 600 : 0)) *
1000;
const isDelayedTx = timeEstimateMs >
(relayClient?.maxPollingAttemptsBeforeTimeout ?? 30) *
(relayClient?.pollingInterval ?? 5000);
if (isDelayedTx) {
setProgressStep(TransactionProgressStep.Success);
}
else {
setProgressStep(TransactionProgressStep.Validating);
}
}
}, [executionStatus?.status, quoteError]);
const allTxHashes = useMemo(() => {
const isRefund = executionStatus?.status === 'refund';
const _allTxHashes = [];
executionStatus?.txHashes?.forEach((txHash) => {
_allTxHashes.push({
txHash,
chainId: isRefund
? fromToken?.chainId
: toToken?.chainId
});
});
executionStatus?.inTxHashes?.forEach((txHash) => {
_allTxHashes.push({
txHash,
chainId: fromToken?.chainId
});
});
return _allTxHashes;
}, [executionStatus?.txHashes, executionStatus?.inTxHashes]);
const { data: transactions, isLoading: isLoadingTransaction } = useRequests((progressStep === TransactionProgressStep.Success ||
progressStep === TransactionProgressStep.Error) &&
allTxHashes[0]
? {
user: address,
hash: allTxHashes[0]?.txHash
}
: undefined, relayClient?.baseApiUrl, {
enabled: (progressStep === TransactionProgressStep.Success ||
progressStep === TransactionProgressStep.Error) &&
allTxHashes[0]
? true
: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchInterval: false,
retryOnMount: false
});
const transaction = transactions[0];
const { fillTime, seconds } = calculateFillTime(transaction);
const timeEstimate = calculatePriceTimeEstimate(quote?.details);
const toChain = toToken?.chainId
? relayClient?.chains.find((chain) => chain.id === toToken?.chainId)
: null;
return (_jsx(_Fragment, { children: children({
progressStep,
setProgressStep,
quote,
isFetchingQuote: isFetchingQuote || isRefetching,
quoteError,
swapError,
setSwapError,
allTxHashes,
transaction,
fillTime,
seconds,
requestId,
depositAddress,
executionStatus,
isLoadingTransaction,
toChain,
timeEstimate
}) }));
};
//# sourceMappingURL=DepositAddressModalRenderer.js.map