diff --git a/apps/web/app/CryptoProviders.tsx b/apps/web/app/CryptoProviders.tsx index c87f589ba4..17c58c9d6a 100644 --- a/apps/web/app/CryptoProviders.tsx +++ b/apps/web/app/CryptoProviders.tsx @@ -17,6 +17,7 @@ export type CryptoProvidersProps = { const config = createConfig({ chains: [base, baseSepolia, mainnet], + multiInjectedProviderDiscovery: false, connectors: [coinbaseWallet()], transports: { [base.id]: http(cdpBaseRpcEndpoint), diff --git a/apps/web/src/hooks/useCapabilitiesSafe.ts b/apps/web/src/hooks/useCapabilitiesSafe.ts index c3142a5ebf..8d23d901a9 100644 --- a/apps/web/src/hooks/useCapabilitiesSafe.ts +++ b/apps/web/src/hooks/useCapabilitiesSafe.ts @@ -6,12 +6,14 @@ - Use experimental useCapabilities - Check atomicBatch (batchcall) and paymasterService for a given chain - Default to false + - Provide utilities for constructing capabilities objects */ import { Chain } from 'viem'; import { base } from 'viem/chains'; import { useAccount } from 'wagmi'; import { useCapabilities } from 'wagmi/experimental'; +import { useMemo } from 'react'; // To add a new capability, add it to this list const CAPABILITIES_LIST = ['atomicBatch', 'paymasterService', 'auxiliaryFunds'] as const; @@ -22,6 +24,12 @@ export type UseCapabilitiesSafeProps = { chainId?: Chain['id']; }; +export type PaymasterCapabilities = { + paymasterService?: { + url: string; + }; +}; + export default function useCapabilitiesSafe({ chainId }: UseCapabilitiesSafeProps) { const { connector, isConnected, chainId: currentChainId } = useAccount(); @@ -45,5 +53,35 @@ export default function useCapabilitiesSafe({ chainId }: UseCapabilitiesSafeProp return acc; }, {} as Record); - return capabilities; + // Construct paymaster capabilities object with URL + const paymasterCapabilities = useMemo((): PaymasterCapabilities => { + if (!capabilities.paymasterService || !rawCapabilities || !featureChainId) return {}; + + const capabilitiesForChain = rawCapabilities[featureChainId]; + if (capabilitiesForChain?.paymasterService?.supported) { + const paymasterUrl = + featureChainId === base.id + ? process.env.NEXT_PUBLIC_BASE_PAYMASTER_SERVICE + : process.env.NEXT_PUBLIC_BASE_SEPOLIA_PAYMASTER_SERVICE; + + if (paymasterUrl) { + return { + paymasterService: { + url: paymasterUrl, + }, + }; + } else { + console.warn( + `Paymaster service is supported but no URL configured for chain ${featureChainId}`, + ); + } + } + return {}; + }, [capabilities.paymasterService, rawCapabilities, featureChainId]); + + return { + ...capabilities, + rawCapabilities, + paymasterCapabilities, + }; } diff --git a/apps/web/src/hooks/useWriteContractsWithLogs.ts b/apps/web/src/hooks/useWriteContractsWithLogs.ts index 40ebb14780..9a0e192a2c 100644 --- a/apps/web/src/hooks/useWriteContractsWithLogs.ts +++ b/apps/web/src/hooks/useWriteContractsWithLogs.ts @@ -3,7 +3,7 @@ import { useErrors } from 'apps/web/contexts/Errors'; import { decodeRawLog, USER_OPERATION_EVENT_LOG_NAME } from 'apps/web/src/utils/transactionLogs'; import { ActionType } from 'libs/base-ui/utils/logEvent'; import { useCallback, useEffect, useState } from 'react'; -import { Chain } from 'viem'; +import { Chain, TransactionReceipt } from 'viem'; import { WriteContractsParameters } from 'viem/experimental'; import { useAccount, useSwitchChain, useWaitForTransactionReceipt } from 'wagmi'; import { useCallsStatus, useWriteContracts } from 'wagmi/experimental'; @@ -48,14 +48,31 @@ export type UseWriteContractsWithLogsProps = { eventName: string; }; +export type UseWriteContractsWithLogsReturn = { + initiateBatchCalls: ( + writeContractParameters: WriteContractsParameters, + ) => Promise; + batchCallTransactionReceiptHash: string | undefined; + batchCallsStatus: BatchCallsStatus; + transactionReceipt: TransactionReceipt | undefined; + batchCallTransactionHash: string | undefined; + batchCallsIsLoading: boolean; + batchCallsIsSuccess: boolean; + batchCallsIsError: boolean; + batchCallsError: Error | null; + batchCallsEnabled: boolean; +}; + export default function useWriteContractsWithLogs({ chain, eventName, -}: UseWriteContractsWithLogsProps) { +}: UseWriteContractsWithLogsProps): UseWriteContractsWithLogsReturn { // Errors & Analytics const { logEventWithContext } = useAnalytics(); const { logError } = useErrors(); - const { atomicBatch: atomicBatchEnabled } = useCapabilitiesSafe({ chainId: chain.id }); + const { atomicBatch: atomicBatchEnabled, paymasterCapabilities } = useCapabilitiesSafe({ + chainId: chain.id, + }); const { chain: connectedChain } = useAccount(); const [batchCallsStatus, setBatchCallsStatus] = useState(BatchCallsStatus.Idle); @@ -113,7 +130,11 @@ export default function useWriteContractsWithLogs({ try { setBatchCallsStatus(BatchCallsStatus.Initiated); logEventWithContext(`${eventName}_transaction_initiated`, ActionType.change); - await writeContractsAsync(writeContractParameters); + + await writeContractsAsync({ + ...writeContractParameters, + capabilities: paymasterCapabilities, + }); logEventWithContext(`${eventName}_transaction_approved`, ActionType.change); setBatchCallsStatus(BatchCallsStatus.Approved); @@ -131,6 +152,7 @@ export default function useWriteContractsWithLogs({ eventName, writeContractsAsync, logError, + paymasterCapabilities, ], );