UNPKG

@0xsequence/connect

Version:
157 lines 7.61 kB
"use strict"; 'use client'; Object.defineProperty(exports, "__esModule", { value: true }); exports.useWaasFeeOptions = useWaasFeeOptions; const hooks_1 = require("@0xsequence/hooks"); const indexer_1 = require("@0xsequence/indexer"); const react_1 = require("react"); const viem_1 = require("viem"); const wagmi_1 = require("wagmi"); const deferred_js_1 = require("../utils/deferred.js"); // --- Shared State Management --- let sharedPendingConfirmation = undefined; let sharedDeferred = undefined; let listeners = []; const notifyListeners = (state) => listeners.forEach(listener => listener(state)); /** * Hook for handling WaaS (Wallet as a Service) fee options for unsponsored transactions * * This hook provides functionality to: * - Get available fee options for a transaction in Native Token and ERC20's * - Provide user wallet balances for each fee option * - Confirm or reject fee selections * * @param options - Configuration options for the hook {@link WaasFeeOptionsConfig} * @returns Array containing the confirmation state and control functions {@link UseWaasFeeOptionsReturnType} * * @example * ```tsx * // Use the hook with default balance checking, this will fetch the user's wallet balances for each fee option and provide them in the UseWaasFeeOptionsReturn * const [ * pendingFeeOptionConfirmation, * confirmPendingFeeOption, * rejectPendingFeeOption * ] = useWaasFeeOptions(); * * // Or skip balance checking if needed * // const [pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption] = * // useWaasFeeOptions({ skipFeeBalanceCheck: true }); * * const [selectedFeeOptionTokenName, setSelectedFeeOptionTokenName] = useState<string>(); * const [feeOptionAlert, setFeeOptionAlert] = useState<AlertProps>(); * * // Initialize with first option when fee options become available * useEffect(() => { * if (pendingFeeOptionConfirmation) { * console.log('Pending fee options: ', pendingFeeOptionConfirmation.options) * } * }, [pendingFeeOptionConfirmation]); * * ``` */ function useWaasFeeOptions(options) { const { skipFeeBalanceCheck = false } = options || {}; const connections = (0, wagmi_1.useConnections)(); const waasConnector = connections.find((c) => c.connector.id.includes('waas'))?.connector; const [pendingFeeOptionConfirmation, setPendingFeeOptionConfirmation] = (0, react_1.useState)(sharedPendingConfirmation); const indexerClient = (0, hooks_1.useIndexerClient)(options?.chainIdOverride ? options.chainIdOverride : (connections[0]?.chainId ?? 1)); /** * Confirms the selected fee option * @param id - The fee confirmation ID * @param feeTokenAddress - The address of the token to use for fee payment (null for native token) */ function confirmPendingFeeOption(id, feeTokenAddress) { if (sharedDeferred && sharedPendingConfirmation?.id === id) { sharedDeferred.resolve({ id, feeTokenAddress, confirmed: true }); sharedDeferred = undefined; notifyListeners(undefined); } } /** * Rejects the current fee option confirmation * @param id - The fee confirmation ID to reject */ function rejectPendingFeeOption(id) { if (sharedDeferred && sharedPendingConfirmation?.id === id) { sharedDeferred.resolve({ id, feeTokenAddress: undefined, confirmed: false }); sharedDeferred = undefined; sharedPendingConfirmation = undefined; notifyListeners(undefined); } } (0, react_1.useEffect)(() => { // Subscribe to shared state changes listeners.push(setPendingFeeOptionConfirmation); // Set initial state in case it changed between component initialization and effect execution setPendingFeeOptionConfirmation(sharedPendingConfirmation); return () => { listeners = listeners.filter(l => l !== setPendingFeeOptionConfirmation); }; }, []); (0, react_1.useEffect)(() => { if (!waasConnector) { return; } const waasProvider = waasConnector.sequenceWaasProvider; if (!waasProvider) { return; } const originalHandler = waasProvider.feeConfirmationHandler; waasProvider.feeConfirmationHandler = { async confirmFeeOption(id, options, txs, chainId) { const pending = new deferred_js_1.Deferred(); // Store the deferred promise in the shared scope sharedDeferred = pending; // Clear any previous stale state immediately sharedPendingConfirmation = undefined; notifyListeners(undefined); const accountAddress = connections[0]?.accounts[0]; if (!accountAddress) { throw new Error('No account address available'); } if (!skipFeeBalanceCheck) { const optionsWithBalances = await Promise.all(options.map(async (option) => { if (option.token.contractAddress) { const tokenBalances = await indexerClient.getTokenBalancesByContract({ filter: { accountAddresses: [accountAddress], contractStatus: indexer_1.ContractVerificationStatus.ALL, contractAddresses: [option.token.contractAddress] }, omitMetadata: true }); const tokenBalance = tokenBalances.balances[0]?.balance; return { ...option, balanceFormatted: option.token.decimals ? (0, viem_1.formatUnits)(BigInt(tokenBalances.balances[0]?.balance ?? '0'), option.token.decimals) : (tokenBalances.balances[0]?.balance ?? '0'), balance: tokenBalances.balances[0]?.balance ?? '0', hasEnoughBalanceForFee: tokenBalance ? BigInt(option.value) <= BigInt(tokenBalance) : false }; } const nativeBalance = await indexerClient.getNativeTokenBalance({ accountAddress }); return { ...option, balanceFormatted: (0, viem_1.formatUnits)(BigInt(nativeBalance.balance.balance), 18), balance: nativeBalance.balance.balance, hasEnoughBalanceForFee: BigInt(option.value) <= BigInt(nativeBalance.balance.balance) }; })); sharedPendingConfirmation = { id, options: optionsWithBalances, chainId }; notifyListeners(sharedPendingConfirmation); } else { sharedPendingConfirmation = { id, options, chainId }; notifyListeners(sharedPendingConfirmation); } return pending.promise; } }; return () => { waasProvider.feeConfirmationHandler = originalHandler; }; }, [waasConnector, indexerClient]); return [pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption]; } //# sourceMappingURL=useWaasFeeOptions.js.map