From b7a5ce46dff45af718329d0ca298ac36313355c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Tue, 29 Oct 2024 12:26:47 +0100 Subject: [PATCH 01/12] Add hooks --- src/constants.ts | 12 +++-- src/hooks/index.ts | 5 ++ src/hooks/useConfirmSafeOperation.ts | 75 ++++++++++++++++++++++++++ src/hooks/usePendingSafeOperations.ts | 50 +++++++++++++++++ src/hooks/useSafe.ts | 13 ++++- src/hooks/useSafeOperation.ts | 38 +++++++++++++ src/hooks/useSafeOperations.ts | 43 +++++++++++++++ src/hooks/useSendSafeOperation.ts | 77 +++++++++++++++++++++++++++ src/hooks/useSendTransaction.ts | 1 - src/index.ts | 2 + src/types/index.ts | 13 ++++- 11 files changed, 321 insertions(+), 8 deletions(-) create mode 100644 src/hooks/useConfirmSafeOperation.ts create mode 100644 src/hooks/usePendingSafeOperations.ts create mode 100644 src/hooks/useSafeOperation.ts create mode 100644 src/hooks/useSafeOperations.ts create mode 100644 src/hooks/useSendSafeOperation.ts diff --git a/src/constants.ts b/src/constants.ts index 61eacfd..db46c2c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,14 +6,18 @@ export enum QueryKey { Threshold = 'threshold', IsDeployed = 'isDeployed', Owners = 'owners', - SafeInfo = 'safeInfo' + SafeInfo = 'safeInfo', + SafeOperations = 'safeOperations', + PendingSafeOperations = 'pendingSafeOperations', } export enum MutationKey { - SendTransaction = 'sendTransaction', - ConfirmTransaction = 'confirmTransaction', + SendTransaction = 'sendTransaction', + ConfirmTransaction = 'confirmTransaction', UpdateThreshold = 'updateThreshold', SwapOwner = 'swapOwner', AddOwner = 'addOwner', - RemoveOwner = 'removeOwner' + RemoveOwner = 'removeOwner', + SendSafeOperation = 'sendSafeOperation', + ConfirmSafeOperation = 'confirmSafeOperation' } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 4bf66e3..59bd8cf 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -15,3 +15,8 @@ export * from './useTransaction.js' export * from './useTransactions.js' export * from './useUpdateThreshold.js' export * from './useWaitForTransaction.js' +export * from './useSafeOperation.js' +export * from './usePendingSafeOperations.js' +export * from './useSendSafeOperation.js' +export * from './useConfirmSafeOperation.js' +export * from './useSafeOperations.js' diff --git a/src/hooks/useConfirmSafeOperation.ts b/src/hooks/useConfirmSafeOperation.ts new file mode 100644 index 0000000..b8b5213 --- /dev/null +++ b/src/hooks/useConfirmSafeOperation.ts @@ -0,0 +1,75 @@ +import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' +import { + ConfirmSafeOperationProps, + SafeClientResult, + safeOperations +} from '@safe-global/sdk-starter-kit' +import { useConfig } from '@/hooks/useConfig.js' +import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' +import { MutationKey, QueryKey } from '@/constants.js' +import { invalidateQueries } from '@/queryClient.js' + +export type ConfirmSafeOperationVariables = ConfirmSafeOperationProps + +export type UseConfirmSafeOperationParams = ConfigParam +export type UseConfirmSafeOperationReturnType = Omit< + UseMutationResult, + 'mutate' | 'mutateAsync' +> & { + confirmSafeOperation: UseMutateFunction< + SafeClientResult, + Error, + ConfirmSafeOperationVariables, + unknown + > + confirmSafeOperationAsync: UseMutateAsyncFunction< + SafeClientResult, + Error, + ConfirmSafeOperationVariables, + unknown + > +} + +/** + * Hook to confirm pending Safe Operations. + * @param params Parameters to customize the hook behavior. + * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. + * @returns Object containing the mutation state and the confirmSafeOperation function. + */ +export function useConfirmSafeOperation( + params: UseConfirmSafeOperationParams = {} +): UseConfirmSafeOperationReturnType { + const [config] = useConfig({ config: params.config }) + + const { mutate, mutateAsync, ...result } = useSignerClientMutation< + SafeClientResult, + ConfirmSafeOperationVariables + >({ + ...params, + mutationKey: [MutationKey.ConfirmSafeOperation], + mutationSafeClientFn: async (signerClient, { safeOperationHash }) => { + if (!config?.safeOperationOptions) + throw new Error('SafeOperationOptions are not specified in SafeConfig') + + const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions + const signerClientWithSafeOperations = await signerClient.extend( + safeOperations({ bundlerUrl }, paymasterOptions) + ) + + const result = await signerClientWithSafeOperations.confirmSafeOperation({ + safeOperationHash + }) + + if (result.safeOperations?.userOperationHash) { + invalidateQueries([QueryKey.SafeOperations, QueryKey.SafeInfo]) + } else if (result.safeOperations?.safeOperationHash) { + invalidateQueries([QueryKey.PendingSafeOperations]) + } + + return result + } + }) + + return { ...result, confirmSafeOperation: mutate, confirmSafeOperationAsync: mutateAsync } +} diff --git a/src/hooks/usePendingSafeOperations.ts b/src/hooks/usePendingSafeOperations.ts new file mode 100644 index 0000000..bcf5b80 --- /dev/null +++ b/src/hooks/usePendingSafeOperations.ts @@ -0,0 +1,50 @@ +import { type UseQueryResult } from '@tanstack/react-query' +import { ListOptions } from '@safe-global/api-kit' +import { useConfig } from '@/hooks/useConfig.js' +import { useIsDeployed } from '@/hooks/useSafeInfo/useIsDeployed.js' +import { usePublicClientQuery } from '@/hooks/usePublicClientQuery.js' +import type { ConfigParam, SafeConfig } from '@/types/index.js' +import { QueryKey } from '@/constants.js' +import { ListResponse, SafeOperationResponse } from '@safe-global/types-kit' +import { safeOperations } from '@safe-global/sdk-starter-kit' + +export type UsePendingSafeOperationsParams = ConfigParam & ListOptions +export type UsePendingSafeOperationsReturnType = UseQueryResult> + +/** + * Hook to get all pending Safe Operations for the connected Safe. + * @param params Parameters to customize the hook behavior. + * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. + * @returns Query result object containing the list of pending Safe Operations. + */ +export function usePendingSafeOperations( + params: UsePendingSafeOperationsParams = {} +): UsePendingSafeOperationsReturnType { + const [config] = useConfig({ config: params.config }) + const { data: isDeployed } = useIsDeployed({ config }) + + return usePublicClientQuery({ + ...params, + querySafeClientFn: async (safeClient) => { + if (!isDeployed) { + throw new Error('Safe is not deployed') + } + + if (!config?.safeOperationOptions) + throw new Error('SafeOperationOptions are not specified in SafeConfig') + + const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions + const safeOperationsClient = await safeClient.extend( + safeOperations({ bundlerUrl }, paymasterOptions) + ) + + const pendingSafeOperations = await safeOperationsClient.getPendingSafeOperations({ + limit: params.limit, + offset: params.offset + }) + + return pendingSafeOperations + }, + queryKey: [QueryKey.PendingSafeOperations] + }) +} diff --git a/src/hooks/useSafe.ts b/src/hooks/useSafe.ts index dac7f79..16dcdad 100644 --- a/src/hooks/useSafe.ts +++ b/src/hooks/useSafe.ts @@ -4,11 +4,14 @@ import { useBalance, useChain, UseConnectSignerReturnType, + usePendingSafeOperations, usePendingTransactions, useSafeInfo, + useSafeOperation, useSignerAddress, useTransaction, - useTransactions + useTransactions, + useSafeOperations } from '@/hooks/index.js' import { MissingSafeProviderError } from '@/errors/MissingSafeProviderError.js' import { SafeContext } from '@/SafeContext.js' @@ -22,6 +25,9 @@ export type UseSafeReturnType = UseConnectSignerReturnType & { getTransactions: typeof useTransactions getSafeInfo: typeof useSafeInfo getSignerAddress: typeof useSignerAddress + getSafeOperation: typeof useSafeOperation + getSafeOperations: typeof useSafeOperations + getPendingSafeOperations: typeof usePendingSafeOperations } /** @@ -49,6 +55,9 @@ export function useSafe(): UseSafeReturnType { getTransaction: useTransaction, getTransactions: useTransactions, getSafeInfo: useSafeInfo, - getSignerAddress: useSignerAddress + getSignerAddress: useSignerAddress, + getSafeOperation: useSafeOperation, + getSafeOperations: useSafeOperations, + getPendingSafeOperations: usePendingSafeOperations } } diff --git a/src/hooks/useSafeOperation.ts b/src/hooks/useSafeOperation.ts new file mode 100644 index 0000000..e343703 --- /dev/null +++ b/src/hooks/useSafeOperation.ts @@ -0,0 +1,38 @@ +import { useCallback, useMemo } from 'react' +import { Hash } from 'viem' +import { useQuery, type UseQueryResult } from '@tanstack/react-query' +import { useConfig } from '@/hooks/useConfig.js' +import { SafeMultisigTransactionResponse } from '@safe-global/types-kit' +import { usePublicClient } from '@/hooks/usePublicClient.js' +import type { ConfigParam, SafeConfig } from '@/types/index.js' + +export type UseSafeOperationParams = ConfigParam & { safeOperationHash: Hash } +export type UseSafeOperationReturnType = UseQueryResult + +/** + * Hook to get the status of a specific Safe Operation. + * @param params Parameters to customize the hook behavior. + * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. + * @param params.safeOperationHash Hash of Safe Operation to be fetched. + * @returns Query result object containing the transaction object. + */ +export function useSafeOperation(params: UseSafeOperationParams): UseSafeOperationReturnType { + const [config] = useConfig({ config: params.config }) + + const safeClient = usePublicClient({ config }) + + const getSafeOperation = useCallback(async () => { + if (!safeClient) { + throw new Error('SafeClient not initialized') + } + + return safeClient.apiKit.getSafeOperation(params.safeOperationHash) + }, [safeClient]) + + const queryKey = useMemo( + () => ['getSafeOperation', params.safeOperationHash], + [params.safeOperationHash] + ) + + return useQuery({ queryKey, queryFn: getSafeOperation }) +} diff --git a/src/hooks/useSafeOperations.ts b/src/hooks/useSafeOperations.ts new file mode 100644 index 0000000..ec33a1f --- /dev/null +++ b/src/hooks/useSafeOperations.ts @@ -0,0 +1,43 @@ +import { useCallback } from 'react' +import { useQuery, type UseQueryResult } from '@tanstack/react-query' +import { ListOptions } from '@safe-global/api-kit' +import { useConfig } from '@/hooks/useConfig.js' +import { usePublicClient } from '@/hooks/usePublicClient.js' +import type { ConfigParam, SafeConfig } from '@/types/index.js' +import { QueryKey } from '@/constants.js' +import { useAddress } from '@/hooks/useSafeInfo/useAddress.js' +import { ListResponse, SafeOperationResponse } from '@safe-global/types-kit' + +export type UseSafeOperationsParams = ConfigParam & ListOptions & { ordering?: string } +export type UseSafeOperationsReturnType = UseQueryResult> + +/**s + * Hook to get all Safe Operations for the connected Safe. + * @param params Parameters to customize the hook behavior. + * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. + * @returns Query result object containing the list of Safe Operations. + */ +export function useSafeOperations( + params: UseSafeOperationsParams = {} +): UseSafeOperationsReturnType { + const [config] = useConfig({ config: params.config }) + const { data: address } = useAddress({ config }) + const safeClient = usePublicClient({ config }) + + const getSafeOperations = useCallback(async () => { + if (!safeClient || !address) { + throw new Error('SafeClient not initialized') + } + + const response = await safeClient.apiKit.getSafeOperationsByAddress({ + safeAddress: address, + limit: params.limit, + offset: params.offset, + ordering: params.ordering + }) + + return response + }, [safeClient, address]) + + return useQuery({ queryKey: [QueryKey.SafeOperations, config], queryFn: getSafeOperations }) +} diff --git a/src/hooks/useSendSafeOperation.ts b/src/hooks/useSendSafeOperation.ts new file mode 100644 index 0000000..6fe95cd --- /dev/null +++ b/src/hooks/useSendSafeOperation.ts @@ -0,0 +1,77 @@ +import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' +import { + SafeClientResult, + safeOperations, + SendSafeOperationProps +} from '@safe-global/sdk-starter-kit' +import { useConfig } from '@/hooks/useConfig.js' +import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' +import { MutationKey, QueryKey } from '@/constants.js' +import { invalidateQueries } from '@/queryClient.js' + +export type SendSafeOperationVariables = SendSafeOperationProps + +export type UseSendSafeOperationParams = ConfigParam +export type UseSendSafeOperationReturnType = Omit< + UseMutationResult, + 'mutate' | 'mutateAsync' +> & { + sendSafeOperation: UseMutateFunction + sendSafeOperationAsync: UseMutateAsyncFunction< + SafeClientResult, + Error, + SendSafeOperationVariables, + unknown + > +} + +/** + * Hook to send or propose Safe Operations. + * @param params Parameters to customize the hook behavior. + * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. + * @returns Object containing the mutation state and the sendSafeOperation function. + */ +export function useSendSafeOperation( + params: UseSendSafeOperationParams = {} +): UseSendSafeOperationReturnType { + const [config] = useConfig({ config: params.config }) + const { mutate, mutateAsync, ...result } = useSignerClientMutation< + SafeClientResult, + SendSafeOperationVariables + >({ + ...params, + mutationKey: [MutationKey.SendSafeOperation], + mutationSafeClientFn: async (signerClient, { transactions = [], ...paymasterSendOptions }) => { + if (!config?.safeOperationOptions) + throw new Error('SafeOperationOptions are not specified in SafeConfig') + + const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions + const signerClientWithSafeOperations = await signerClient.extend( + safeOperations({ bundlerUrl }, paymasterOptions) + ) + + try { + console.log('sendSafeOperation', { transactions, ...paymasterSendOptions }) + const result = await signerClientWithSafeOperations.sendSafeOperation({ + transactions, + ...paymasterSendOptions + }) + console.log('result', result) + + if (result.safeOperations?.userOperationHash) { + invalidateQueries([QueryKey.SafeOperations, QueryKey.SafeInfo]) + } else if (result.safeOperations?.safeOperationHash) { + invalidateQueries([QueryKey.PendingSafeOperations]) + } + + return result + } catch (error) { + console.error('error', error) + throw new Error("Couldn't send SafeOperation") + } + } + }) + + return { ...result, sendSafeOperation: mutate, sendSafeOperationAsync: mutateAsync } +} diff --git a/src/hooks/useSendTransaction.ts b/src/hooks/useSendTransaction.ts index 3c18f57..e1a4ea6 100644 --- a/src/hooks/useSendTransaction.ts +++ b/src/hooks/useSendTransaction.ts @@ -51,7 +51,6 @@ export function useSendTransaction( if (result.transactions?.ethereumTxHash) { await waitForTransactionReceipt(result.transactions.ethereumTxHash) - invalidateQueries([QueryKey.PendingTransactions, QueryKey.SafeInfo]) await waitForTransactionIndexed(result.transactions) diff --git a/src/index.ts b/src/index.ts index 34910aa..2751aa7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,8 @@ export * from '@/hooks/useConfirmTransaction.js' export * from '@/hooks/useSendTransaction.js' export * from '@/hooks/useUpdateOwners/index.js' export * from '@/hooks/useUpdateThreshold.js' +export * from '@/hooks/useSendSafeOperation.js' +export * from '@/hooks/useConfirmSafeOperation.js' export * from '@/types/index.js' diff --git a/src/types/index.ts b/src/types/index.ts index a93b35d..5a38166 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,8 +1,13 @@ import { SafeMultisigTransactionResponse } from '@safe-global/types-kit' import type { SdkStarterKitConfig } from '@safe-global/sdk-starter-kit' +import type { PaymasterOptions } from '@safe-global/relay-kit' import type { Address, CustomTransport, HttpTransport } from 'viem' import type { Chain as ChainType } from 'viem/chains' +type BundlerOptions = { + bundlerUrl: string +} + export * from './guards.js' export type EIP1193Provider = Exclude @@ -11,7 +16,12 @@ export type CreateConfigParams< Provider extends SdkStarterKitConfig['provider'] = SdkStarterKitConfig['provider'], Signer extends SdkStarterKitConfig['signer'] = SdkStarterKitConfig['signer'], Chain extends ChainType = ChainType -> = { chain: Chain; provider: Provider; signer: Signer } & SdkStarterKitConfig +> = { + chain: Chain + provider: Provider + signer: Signer + safeOperationOptions?: BundlerOptions & PaymasterOptions +} & SdkStarterKitConfig export type SafeConfig< Provider extends SdkStarterKitConfig['provider'] = SdkStarterKitConfig['provider'], @@ -21,6 +31,7 @@ export type SafeConfig< chain: Chain provider: Provider signer: Signer + safeOperationOptions?: BundlerOptions & PaymasterOptions } & (Provider extends string ? { transport: HttpTransport } : { transport: CustomTransport }) export type SafeConfigWithSigner = SafeConfig & { signer: string } From 6a63e2a7b0f08d9db65dece06083d09b0777cb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Tue, 29 Oct 2024 16:31:11 +0100 Subject: [PATCH 02/12] extend safeOperations on the Context --- src/SafeContext.ts | 4 +-- src/SafeProvider.ts | 4 +-- src/createClient.ts | 34 ++++++++++++++++++--- src/hooks/useConfirmSafeOperation.ts | 15 +++------ src/hooks/usePendingSafeOperations.ts | 10 +++--- src/hooks/usePublicClient.ts | 3 +- src/hooks/usePublicClientQuery.ts | 3 +- src/hooks/useSendSafeOperation.ts | 18 +++++------ src/hooks/useSignerClient.ts | 3 +- src/hooks/useSignerClientMutation.ts | 3 +- src/hooks/useUpdateOwners/useAddOwner.ts | 4 +-- src/hooks/useUpdateOwners/useRemoveOwner.ts | 4 +-- src/hooks/useUpdateOwners/useSwapOwner.ts | 4 +-- src/types/index.ts | 21 ++++++++++++- 14 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/SafeContext.ts b/src/SafeContext.ts index 7eb07fd..76046bc 100644 --- a/src/SafeContext.ts +++ b/src/SafeContext.ts @@ -1,7 +1,7 @@ import { createContext } from 'react' import { Config } from 'wagmi' -import { SafeClient } from '@safe-global/sdk-starter-kit' -import type { SafeConfig } from '@/types/index.js' + +import type { SafeClient, SafeConfig } from '@/types/index.js' export type SafeContextType = { isInitialized: boolean diff --git a/src/SafeProvider.ts b/src/SafeProvider.ts index 78453e1..ca1d2a6 100644 --- a/src/SafeProvider.ts +++ b/src/SafeProvider.ts @@ -1,14 +1,14 @@ import { createElement, useCallback, useEffect, useMemo, useState } from 'react' import { QueryClientProvider } from '@tanstack/react-query' import { createConfig, WagmiProvider } from 'wagmi' -import { SafeClient } from '@safe-global/sdk-starter-kit' import { InitializeSafeProviderError } from '@/errors/InitializeSafeProviderError.js' -import type { SafeConfig } from '@/types/index.js' import { isSafeConfigWithSigner } from '@/types/guards.js' import { createPublicClient, createSignerClient } from '@/createClient.js' import { queryClient } from '@/queryClient.js' import { SafeContext } from '@/SafeContext.js' +import type { SafeClient, SafeConfig } from '@/types/index.js' + export type SafeProviderProps = { config: SafeConfig } diff --git a/src/createClient.ts b/src/createClient.ts index 57069d2..63a5946 100644 --- a/src/createClient.ts +++ b/src/createClient.ts @@ -1,5 +1,5 @@ +import { createSafeClient, safeOperations } from '@safe-global/sdk-starter-kit' import type { SafeConfig, SafeConfigWithSigner } from '@/types/index.js' -import { createSafeClient } from '@safe-global/sdk-starter-kit' const getPublicClientConfig = ({ provider, safeAddress, safeOptions }: SafeConfig) => ({ signer: undefined, @@ -12,16 +12,40 @@ const getPublicClientConfig = ({ provider, safeAddress, safeOptions }: SafeConfi * @param config Config object for the Safe client * @returns Safe client instance with public method capabilities */ -export const createPublicClient = (config: SafeConfig) => - createSafeClient(getPublicClientConfig(config)) +export const createPublicClient = async (config: SafeConfig) => { + const publicClient = await createSafeClient(getPublicClientConfig(config)) + + if (config.safeOperationOptions) { + const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions + const publicClientWithSafeOperations = await publicClient.extend( + safeOperations({ bundlerUrl }, paymasterOptions) + ) + + return publicClientWithSafeOperations + } + + return publicClient +} /** * Creates a SafeClient instance with signer capabilities. * @param config Config object for the Safe client with mandatory `signer` property * @returns Safe client instance with signer capabilities */ -export const createSignerClient = ({ signer, ...config }: SafeConfigWithSigner) => - createSafeClient({ +export const createSignerClient = async ({ signer, ...config }: SafeConfigWithSigner) => { + const signerClient = await createSafeClient({ ...getPublicClientConfig({ ...config, signer: undefined }), signer }) + + if (config.safeOperationOptions) { + const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions + const publicClientWithSafeOperations = await signerClient.extend( + safeOperations({ bundlerUrl }, paymasterOptions) + ) + + return publicClientWithSafeOperations + } + + return signerClient +} diff --git a/src/hooks/useConfirmSafeOperation.ts b/src/hooks/useConfirmSafeOperation.ts index b8b5213..90d8a0c 100644 --- a/src/hooks/useConfirmSafeOperation.ts +++ b/src/hooks/useConfirmSafeOperation.ts @@ -1,9 +1,5 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' -import { - ConfirmSafeOperationProps, - SafeClientResult, - safeOperations -} from '@safe-global/sdk-starter-kit' +import { ConfirmSafeOperationProps, SafeClientResult } from '@safe-global/sdk-starter-kit' import { useConfig } from '@/hooks/useConfig.js' import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' @@ -52,12 +48,11 @@ export function useConfirmSafeOperation( if (!config?.safeOperationOptions) throw new Error('SafeOperationOptions are not specified in SafeConfig') - const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions - const signerClientWithSafeOperations = await signerClient.extend( - safeOperations({ bundlerUrl }, paymasterOptions) - ) + if (!signerClient.confirmSafeOperation) { + throw new Error('You should add safeOperationOptions to the SafeConfig') + } - const result = await signerClientWithSafeOperations.confirmSafeOperation({ + const result = await signerClient.confirmSafeOperation({ safeOperationHash }) diff --git a/src/hooks/usePendingSafeOperations.ts b/src/hooks/usePendingSafeOperations.ts index bcf5b80..6d53131 100644 --- a/src/hooks/usePendingSafeOperations.ts +++ b/src/hooks/usePendingSafeOperations.ts @@ -6,7 +6,6 @@ import { usePublicClientQuery } from '@/hooks/usePublicClientQuery.js' import type { ConfigParam, SafeConfig } from '@/types/index.js' import { QueryKey } from '@/constants.js' import { ListResponse, SafeOperationResponse } from '@safe-global/types-kit' -import { safeOperations } from '@safe-global/sdk-starter-kit' export type UsePendingSafeOperationsParams = ConfigParam & ListOptions export type UsePendingSafeOperationsReturnType = UseQueryResult> @@ -33,12 +32,11 @@ export function usePendingSafeOperations( if (!config?.safeOperationOptions) throw new Error('SafeOperationOptions are not specified in SafeConfig') - const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions - const safeOperationsClient = await safeClient.extend( - safeOperations({ bundlerUrl }, paymasterOptions) - ) + if (!safeClient.getPendingSafeOperations) { + throw new Error('You should add safeOperationOptions to the SafeConfig') + } - const pendingSafeOperations = await safeOperationsClient.getPendingSafeOperations({ + const pendingSafeOperations = await safeClient.getPendingSafeOperations({ limit: params.limit, offset: params.offset }) diff --git a/src/hooks/usePublicClient.ts b/src/hooks/usePublicClient.ts index e18f5ef..cb9385e 100644 --- a/src/hooks/usePublicClient.ts +++ b/src/hooks/usePublicClient.ts @@ -1,6 +1,5 @@ import { useContext, useEffect, useState } from 'react' -import { type SafeClient } from '@safe-global/sdk-starter-kit' -import type { ConfigParam, SafeConfig } from '@/types/index.js' +import type { ConfigParam, SafeClient, SafeConfig } from '@/types/index.js' import { SafeContext } from '@/SafeContext.js' import { useCompareObject } from '@/hooks/helpers/useCompare.js' import { createPublicClient } from '@/createClient.js' diff --git a/src/hooks/usePublicClientQuery.ts b/src/hooks/usePublicClientQuery.ts index 9864025..4be71aa 100644 --- a/src/hooks/usePublicClientQuery.ts +++ b/src/hooks/usePublicClientQuery.ts @@ -1,9 +1,8 @@ import { useCallback } from 'react' import { useQuery, type UseQueryResult } from '@tanstack/react-query' -import { SafeClient } from '@safe-global/sdk-starter-kit' import { useConfig } from '@/hooks/useConfig.js' import { usePublicClient } from '@/hooks/usePublicClient.js' -import type { ConfigParam, SafeConfig } from '@/types/index.js' +import type { ConfigParam, SafeConfig, SafeClient } from '@/types/index.js' export type UsePublicClientQueryParams = ConfigParam & { querySafeClientFn: (safeClient: SafeClient) => Promise | T diff --git a/src/hooks/useSendSafeOperation.ts b/src/hooks/useSendSafeOperation.ts index 6fe95cd..4eef989 100644 --- a/src/hooks/useSendSafeOperation.ts +++ b/src/hooks/useSendSafeOperation.ts @@ -1,9 +1,5 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' -import { - SafeClientResult, - safeOperations, - SendSafeOperationProps -} from '@safe-global/sdk-starter-kit' +import { SafeClientResult, SendSafeOperationProps } from '@safe-global/sdk-starter-kit' import { useConfig } from '@/hooks/useConfig.js' import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' @@ -46,14 +42,14 @@ export function useSendSafeOperation( if (!config?.safeOperationOptions) throw new Error('SafeOperationOptions are not specified in SafeConfig') - const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions - const signerClientWithSafeOperations = await signerClient.extend( - safeOperations({ bundlerUrl }, paymasterOptions) - ) - try { console.log('sendSafeOperation', { transactions, ...paymasterSendOptions }) - const result = await signerClientWithSafeOperations.sendSafeOperation({ + + if (!signerClient.sendSafeOperation) { + throw new Error('You should add safeOperationOptions to the SafeConfig') + } + + const result = await signerClient.sendSafeOperation({ transactions, ...paymasterSendOptions }) diff --git a/src/hooks/useSignerClient.ts b/src/hooks/useSignerClient.ts index 0e91955..66b378c 100644 --- a/src/hooks/useSignerClient.ts +++ b/src/hooks/useSignerClient.ts @@ -1,6 +1,5 @@ import { useContext, useEffect, useState } from 'react' -import { type SafeClient } from '@safe-global/sdk-starter-kit' -import type { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import type { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' import { SafeContext } from '@/SafeContext.js' import { useCompareObject } from '@/hooks/helpers/useCompare.js' import { createSignerClient } from '@/createClient.js' diff --git a/src/hooks/useSignerClientMutation.ts b/src/hooks/useSignerClientMutation.ts index 8a7a6d9..a33f35c 100644 --- a/src/hooks/useSignerClientMutation.ts +++ b/src/hooks/useSignerClientMutation.ts @@ -1,9 +1,8 @@ import { useCallback } from 'react' import { useMutation, type UseMutationResult } from '@tanstack/react-query' -import { SafeClient } from '@safe-global/sdk-starter-kit' import { useConfig } from '@/hooks/useConfig.js' import { useSignerClient } from '@/hooks//useSignerClient.js' -import type { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import type { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' export type UseSignerClientMutationParams = ConfigParam & { diff --git a/src/hooks/useUpdateOwners/useAddOwner.ts b/src/hooks/useUpdateOwners/useAddOwner.ts index 1c4ce8c..0c64346 100644 --- a/src/hooks/useUpdateOwners/useAddOwner.ts +++ b/src/hooks/useUpdateOwners/useAddOwner.ts @@ -1,6 +1,6 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' -import { SafeClient, SafeClientResult } from '@safe-global/sdk-starter-kit' -import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import { SafeClientResult } from '@safe-global/sdk-starter-kit' +import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { useSendTransaction } from '@/hooks/useSendTransaction.js' import { MutationKey } from '@/constants.js' diff --git a/src/hooks/useUpdateOwners/useRemoveOwner.ts b/src/hooks/useUpdateOwners/useRemoveOwner.ts index a5ae292..3d67fc0 100644 --- a/src/hooks/useUpdateOwners/useRemoveOwner.ts +++ b/src/hooks/useUpdateOwners/useRemoveOwner.ts @@ -1,6 +1,6 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' -import { SafeClient, SafeClientResult } from '@safe-global/sdk-starter-kit' -import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import { SafeClientResult } from '@safe-global/sdk-starter-kit' +import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' import { useSendTransaction } from '@/hooks/useSendTransaction.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey } from '@/constants.js' diff --git a/src/hooks/useUpdateOwners/useSwapOwner.ts b/src/hooks/useUpdateOwners/useSwapOwner.ts index 33d1521..8f71a45 100644 --- a/src/hooks/useUpdateOwners/useSwapOwner.ts +++ b/src/hooks/useUpdateOwners/useSwapOwner.ts @@ -1,6 +1,6 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' -import { SafeClient, SafeClientResult } from '@safe-global/sdk-starter-kit' -import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import { SafeClientResult } from '@safe-global/sdk-starter-kit' +import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { useSendTransaction } from '@/hooks/useSendTransaction.js' import { MutationKey } from '@/constants.js' diff --git a/src/types/index.ts b/src/types/index.ts index 5a38166..2d0fc48 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,8 +1,19 @@ -import { SafeMultisigTransactionResponse } from '@safe-global/types-kit' +import { + SafeMultisigTransactionResponse, + SafeOperationResponse, + ListResponse +} from '@safe-global/types-kit' import type { SdkStarterKitConfig } from '@safe-global/sdk-starter-kit' import type { PaymasterOptions } from '@safe-global/relay-kit' import type { Address, CustomTransport, HttpTransport } from 'viem' import type { Chain as ChainType } from 'viem/chains' +import { + ConfirmSafeOperationProps, + SafeClient as SafeClientType, + SafeClientResult, + SendSafeOperationProps +} from '@safe-global/sdk-starter-kit' +import { ListOptions } from '@safe-global/api-kit' type BundlerOptions = { bundlerUrl: string @@ -12,6 +23,14 @@ export * from './guards.js' export type EIP1193Provider = Exclude +type SafeOperationsClient = { + sendSafeOperation?: (props: SendSafeOperationProps) => Promise + confirmSafeOperation?: (props: ConfirmSafeOperationProps) => Promise + getPendingSafeOperations?: (options?: ListOptions) => Promise> +} + +export type SafeClient = SafeClientType & SafeOperationsClient + export type CreateConfigParams< Provider extends SdkStarterKitConfig['provider'] = SdkStarterKitConfig['provider'], Signer extends SdkStarterKitConfig['signer'] = SdkStarterKitConfig['signer'], From 62ebee0e1a46563e749bc642f97fc4232ec50acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Tue, 29 Oct 2024 17:00:52 +0100 Subject: [PATCH 03/12] Improve exception handling --- src/hooks/useConfirmSafeOperation.ts | 8 ++---- src/hooks/usePendingSafeOperations.ts | 8 ++---- src/hooks/useSendSafeOperation.ts | 41 ++++++++++----------------- 3 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/hooks/useConfirmSafeOperation.ts b/src/hooks/useConfirmSafeOperation.ts index 90d8a0c..372a444 100644 --- a/src/hooks/useConfirmSafeOperation.ts +++ b/src/hooks/useConfirmSafeOperation.ts @@ -45,12 +45,8 @@ export function useConfirmSafeOperation( ...params, mutationKey: [MutationKey.ConfirmSafeOperation], mutationSafeClientFn: async (signerClient, { safeOperationHash }) => { - if (!config?.safeOperationOptions) - throw new Error('SafeOperationOptions are not specified in SafeConfig') - - if (!signerClient.confirmSafeOperation) { - throw new Error('You should add safeOperationOptions to the SafeConfig') - } + if (!config?.safeOperationOptions || !signerClient.confirmSafeOperation) + throw new Error('Property safeOperationOptions are not specified in SafeConfig') const result = await signerClient.confirmSafeOperation({ safeOperationHash diff --git a/src/hooks/usePendingSafeOperations.ts b/src/hooks/usePendingSafeOperations.ts index 6d53131..f9af4ca 100644 --- a/src/hooks/usePendingSafeOperations.ts +++ b/src/hooks/usePendingSafeOperations.ts @@ -29,12 +29,8 @@ export function usePendingSafeOperations( throw new Error('Safe is not deployed') } - if (!config?.safeOperationOptions) - throw new Error('SafeOperationOptions are not specified in SafeConfig') - - if (!safeClient.getPendingSafeOperations) { - throw new Error('You should add safeOperationOptions to the SafeConfig') - } + if (!config?.safeOperationOptions || !safeClient.getPendingSafeOperations) + throw new Error('Property safeOperationOptions are not specified in SafeConfig') const pendingSafeOperations = await safeClient.getPendingSafeOperations({ limit: params.limit, diff --git a/src/hooks/useSendSafeOperation.ts b/src/hooks/useSendSafeOperation.ts index 4eef989..ce6679d 100644 --- a/src/hooks/useSendSafeOperation.ts +++ b/src/hooks/useSendSafeOperation.ts @@ -39,33 +39,22 @@ export function useSendSafeOperation( ...params, mutationKey: [MutationKey.SendSafeOperation], mutationSafeClientFn: async (signerClient, { transactions = [], ...paymasterSendOptions }) => { - if (!config?.safeOperationOptions) - throw new Error('SafeOperationOptions are not specified in SafeConfig') - - try { - console.log('sendSafeOperation', { transactions, ...paymasterSendOptions }) - - if (!signerClient.sendSafeOperation) { - throw new Error('You should add safeOperationOptions to the SafeConfig') - } - - const result = await signerClient.sendSafeOperation({ - transactions, - ...paymasterSendOptions - }) - console.log('result', result) - - if (result.safeOperations?.userOperationHash) { - invalidateQueries([QueryKey.SafeOperations, QueryKey.SafeInfo]) - } else if (result.safeOperations?.safeOperationHash) { - invalidateQueries([QueryKey.PendingSafeOperations]) - } - - return result - } catch (error) { - console.error('error', error) - throw new Error("Couldn't send SafeOperation") + if (!config?.safeOperationOptions || !signerClient.sendSafeOperation) + throw new Error('Property safeOperationOptions are not specified in SafeConfig') + + const result = await signerClient.sendSafeOperation({ + transactions, + ...paymasterSendOptions + }) + console.log('result', result) + + if (result.safeOperations?.userOperationHash) { + invalidateQueries([QueryKey.SafeOperations, QueryKey.SafeInfo]) + } else if (result.safeOperations?.safeOperationHash) { + invalidateQueries([QueryKey.PendingSafeOperations]) } + + return result } }) From edacdfc5dd61124dc2991d1790dd7876559543f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Wed, 30 Oct 2024 18:04:21 +0100 Subject: [PATCH 04/12] Some improvements --- src/constants.ts | 6 ++-- src/createClient.ts | 41 +++++++++++++-------------- src/hooks/useConfirmSafeOperation.ts | 9 +++--- src/hooks/usePendingSafeOperations.ts | 6 ++-- src/hooks/useSafe.ts | 10 +++---- src/hooks/useSendSafeOperation.ts | 9 +++--- src/types/index.ts | 6 ++-- 7 files changed, 44 insertions(+), 43 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index db46c2c..f02f218 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -8,12 +8,12 @@ export enum QueryKey { Owners = 'owners', SafeInfo = 'safeInfo', SafeOperations = 'safeOperations', - PendingSafeOperations = 'pendingSafeOperations', + PendingSafeOperations = 'pendingSafeOperations' } export enum MutationKey { - SendTransaction = 'sendTransaction', - ConfirmTransaction = 'confirmTransaction', + SendTransaction = 'sendTransaction', + ConfirmTransaction = 'confirmTransaction', UpdateThreshold = 'updateThreshold', SwapOwner = 'swapOwner', AddOwner = 'addOwner', diff --git a/src/createClient.ts b/src/createClient.ts index 63a5946..e47dac0 100644 --- a/src/createClient.ts +++ b/src/createClient.ts @@ -1,5 +1,18 @@ import { createSafeClient, safeOperations } from '@safe-global/sdk-starter-kit' -import type { SafeConfig, SafeConfigWithSigner } from '@/types/index.js' +import type { + SafeClient, + SafeConfig, + SafeConfigWithSigner, + SafeOperationOptions +} from '@/types/index.js' + +const extendWithSafeOperations = async ( + client: SafeClient, + operationOptions: SafeOperationOptions +) => { + const { bundlerUrl, ...paymasterOptions } = operationOptions + return await client.extend(safeOperations({ bundlerUrl }, paymasterOptions)) +} const getPublicClientConfig = ({ provider, safeAddress, safeOptions }: SafeConfig) => ({ signer: undefined, @@ -15,16 +28,9 @@ const getPublicClientConfig = ({ provider, safeAddress, safeOptions }: SafeConfi export const createPublicClient = async (config: SafeConfig) => { const publicClient = await createSafeClient(getPublicClientConfig(config)) - if (config.safeOperationOptions) { - const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions - const publicClientWithSafeOperations = await publicClient.extend( - safeOperations({ bundlerUrl }, paymasterOptions) - ) - - return publicClientWithSafeOperations - } - - return publicClient + return config.safeOperationOptions + ? await extendWithSafeOperations(publicClient, config.safeOperationOptions) + : publicClient } /** @@ -38,14 +44,7 @@ export const createSignerClient = async ({ signer, ...config }: SafeConfigWithSi signer }) - if (config.safeOperationOptions) { - const { bundlerUrl, ...paymasterOptions } = config.safeOperationOptions - const publicClientWithSafeOperations = await signerClient.extend( - safeOperations({ bundlerUrl }, paymasterOptions) - ) - - return publicClientWithSafeOperations - } - - return signerClient + return config.safeOperationOptions + ? await extendWithSafeOperations(signerClient, config.safeOperationOptions) + : signerClient } diff --git a/src/hooks/useConfirmSafeOperation.ts b/src/hooks/useConfirmSafeOperation.ts index 372a444..c236f04 100644 --- a/src/hooks/useConfirmSafeOperation.ts +++ b/src/hooks/useConfirmSafeOperation.ts @@ -1,6 +1,5 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { ConfirmSafeOperationProps, SafeClientResult } from '@safe-global/sdk-starter-kit' -import { useConfig } from '@/hooks/useConfig.js' import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey, QueryKey } from '@/constants.js' @@ -36,8 +35,6 @@ export type UseConfirmSafeOperationReturnType = Omit< export function useConfirmSafeOperation( params: UseConfirmSafeOperationParams = {} ): UseConfirmSafeOperationReturnType { - const [config] = useConfig({ config: params.config }) - const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, ConfirmSafeOperationVariables @@ -45,8 +42,10 @@ export function useConfirmSafeOperation( ...params, mutationKey: [MutationKey.ConfirmSafeOperation], mutationSafeClientFn: async (signerClient, { safeOperationHash }) => { - if (!config?.safeOperationOptions || !signerClient.confirmSafeOperation) - throw new Error('Property safeOperationOptions are not specified in SafeConfig') + if (!signerClient.confirmSafeOperation) + throw new Error( + 'To use Safe Operations, you need to specify the safeOperationOptions in the SafeProvider configuration.' + ) const result = await signerClient.confirmSafeOperation({ safeOperationHash diff --git a/src/hooks/usePendingSafeOperations.ts b/src/hooks/usePendingSafeOperations.ts index f9af4ca..0be7bee 100644 --- a/src/hooks/usePendingSafeOperations.ts +++ b/src/hooks/usePendingSafeOperations.ts @@ -29,8 +29,10 @@ export function usePendingSafeOperations( throw new Error('Safe is not deployed') } - if (!config?.safeOperationOptions || !safeClient.getPendingSafeOperations) - throw new Error('Property safeOperationOptions are not specified in SafeConfig') + if (!safeClient.getPendingSafeOperations) + throw new Error( + 'To use Safe Operations, you need to specify the safeOperationOptions in the SafeProvider configuration.' + ) const pendingSafeOperations = await safeClient.getPendingSafeOperations({ limit: params.limit, diff --git a/src/hooks/useSafe.ts b/src/hooks/useSafe.ts index 16dcdad..a43b8a5 100644 --- a/src/hooks/useSafe.ts +++ b/src/hooks/useSafe.ts @@ -4,13 +4,13 @@ import { useBalance, useChain, UseConnectSignerReturnType, - usePendingSafeOperations, usePendingTransactions, useSafeInfo, - useSafeOperation, useSignerAddress, useTransaction, useTransactions, + usePendingSafeOperations, + useSafeOperation, useSafeOperations } from '@/hooks/index.js' import { MissingSafeProviderError } from '@/errors/MissingSafeProviderError.js' @@ -25,9 +25,9 @@ export type UseSafeReturnType = UseConnectSignerReturnType & { getTransactions: typeof useTransactions getSafeInfo: typeof useSafeInfo getSignerAddress: typeof useSignerAddress + getPendingSafeOperations: typeof usePendingSafeOperations getSafeOperation: typeof useSafeOperation getSafeOperations: typeof useSafeOperations - getPendingSafeOperations: typeof usePendingSafeOperations } /** @@ -56,8 +56,8 @@ export function useSafe(): UseSafeReturnType { getTransactions: useTransactions, getSafeInfo: useSafeInfo, getSignerAddress: useSignerAddress, + getPendingSafeOperations: usePendingSafeOperations, getSafeOperation: useSafeOperation, - getSafeOperations: useSafeOperations, - getPendingSafeOperations: usePendingSafeOperations + getSafeOperations: useSafeOperations } } diff --git a/src/hooks/useSendSafeOperation.ts b/src/hooks/useSendSafeOperation.ts index ce6679d..62d936a 100644 --- a/src/hooks/useSendSafeOperation.ts +++ b/src/hooks/useSendSafeOperation.ts @@ -1,6 +1,5 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult, SendSafeOperationProps } from '@safe-global/sdk-starter-kit' -import { useConfig } from '@/hooks/useConfig.js' import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey, QueryKey } from '@/constants.js' @@ -31,7 +30,6 @@ export type UseSendSafeOperationReturnType = Omit< export function useSendSafeOperation( params: UseSendSafeOperationParams = {} ): UseSendSafeOperationReturnType { - const [config] = useConfig({ config: params.config }) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, SendSafeOperationVariables @@ -39,14 +37,15 @@ export function useSendSafeOperation( ...params, mutationKey: [MutationKey.SendSafeOperation], mutationSafeClientFn: async (signerClient, { transactions = [], ...paymasterSendOptions }) => { - if (!config?.safeOperationOptions || !signerClient.sendSafeOperation) - throw new Error('Property safeOperationOptions are not specified in SafeConfig') + if (!signerClient.sendSafeOperation) + throw new Error( + 'To use Safe Operations, you need to specify the safeOperationOptions in the SafeProvider configuration.' + ) const result = await signerClient.sendSafeOperation({ transactions, ...paymasterSendOptions }) - console.log('result', result) if (result.safeOperations?.userOperationHash) { invalidateQueries([QueryKey.SafeOperations, QueryKey.SafeInfo]) diff --git a/src/types/index.ts b/src/types/index.ts index 2d0fc48..15f45e8 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -31,6 +31,8 @@ type SafeOperationsClient = { export type SafeClient = SafeClientType & SafeOperationsClient +export type SafeOperationOptions = BundlerOptions & PaymasterOptions + export type CreateConfigParams< Provider extends SdkStarterKitConfig['provider'] = SdkStarterKitConfig['provider'], Signer extends SdkStarterKitConfig['signer'] = SdkStarterKitConfig['signer'], @@ -39,7 +41,7 @@ export type CreateConfigParams< chain: Chain provider: Provider signer: Signer - safeOperationOptions?: BundlerOptions & PaymasterOptions + safeOperationOptions?: SafeOperationOptions } & SdkStarterKitConfig export type SafeConfig< @@ -50,7 +52,7 @@ export type SafeConfig< chain: Chain provider: Provider signer: Signer - safeOperationOptions?: BundlerOptions & PaymasterOptions + safeOperationOptions?: SafeOperationOptions } & (Provider extends string ? { transport: HttpTransport } : { transport: CustomTransport }) export type SafeConfigWithSigner = SafeConfig & { signer: string } From 52a2f1e7a7c54502870c39d6a76dc7ec40870a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Wed, 6 Nov 2024 15:58:02 +0100 Subject: [PATCH 05/12] Update config hooks --- src/hooks/useDynamicSafeAction.ts | 57 +++++++++++++++++++++ src/hooks/usePendingSafeOperations.ts | 9 ---- src/hooks/useUpdateOwners/useAddOwner.ts | 7 +-- src/hooks/useUpdateOwners/useRemoveOwner.ts | 6 +-- src/hooks/useUpdateOwners/useSwapOwner.ts | 6 +-- src/hooks/useUpdateThreshold.ts | 6 +-- 6 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 src/hooks/useDynamicSafeAction.ts diff --git a/src/hooks/useDynamicSafeAction.ts b/src/hooks/useDynamicSafeAction.ts new file mode 100644 index 0000000..6fd9272 --- /dev/null +++ b/src/hooks/useDynamicSafeAction.ts @@ -0,0 +1,57 @@ +import { UseMutateAsyncFunction, UseMutateFunction } from '@tanstack/react-query' +import { SafeClientResult } from '@safe-global/sdk-starter-kit' +import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' +import { + useSendSafeOperation, + UseSendSafeOperationReturnType +} from '@/hooks/useSendSafeOperation.js' +import { useSendTransaction, UseSendTransactionReturnType } from '@/hooks/useSendTransaction.js' +import { + useConfirmSafeOperation, + UseConfirmSafeOperationReturnType +} from '@/hooks/useConfirmSafeOperation.js' +import { + useConfirmTransaction, + UseConfirmTransactionReturnType +} from '@/hooks/useConfirmTransaction.js' + +export type UseDynamicSafeActionParams = ConfigParam + +export type UseDynamicSafeActionReturnType = { + send: UseMutateFunction + sendAsync: UseMutateAsyncFunction + confirm: UseMutateFunction + confirmAsync: UseMutateAsyncFunction +} + +/** + * Hook to dynamically choose between Safe Operations and Transactions. + * @param params Parameters to customize the hook behavior. + * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. + * @returns Object containing the mutation state and the send and confirm functions. + */ +export function useDynamicSafeAction( + params: UseDynamicSafeActionParams = {} +): UseDynamicSafeActionReturnType { + const isSafeOperation = !!params.config?.safeOperationOptions + + // Use the appropriate hooks based on the presence of safeOperations in the config + const { sendSafeOperation, sendSafeOperationAsync }: UseSendSafeOperationReturnType = + useSendSafeOperation(params) + + const { sendTransaction, sendTransactionAsync }: UseSendTransactionReturnType = + useSendTransaction(params) + + const { confirmSafeOperation, confirmSafeOperationAsync }: UseConfirmSafeOperationReturnType = + useConfirmSafeOperation(params) + + const { confirmTransaction, confirmTransactionAsync }: UseConfirmTransactionReturnType = + useConfirmTransaction(params) + + return { + send: isSafeOperation ? sendSafeOperation : sendTransaction, + sendAsync: isSafeOperation ? sendSafeOperationAsync : sendTransactionAsync, + confirm: isSafeOperation ? confirmSafeOperation : confirmTransaction, + confirmAsync: isSafeOperation ? confirmSafeOperationAsync : confirmTransactionAsync + } +} diff --git a/src/hooks/usePendingSafeOperations.ts b/src/hooks/usePendingSafeOperations.ts index 0be7bee..c9d2f58 100644 --- a/src/hooks/usePendingSafeOperations.ts +++ b/src/hooks/usePendingSafeOperations.ts @@ -1,7 +1,5 @@ import { type UseQueryResult } from '@tanstack/react-query' import { ListOptions } from '@safe-global/api-kit' -import { useConfig } from '@/hooks/useConfig.js' -import { useIsDeployed } from '@/hooks/useSafeInfo/useIsDeployed.js' import { usePublicClientQuery } from '@/hooks/usePublicClientQuery.js' import type { ConfigParam, SafeConfig } from '@/types/index.js' import { QueryKey } from '@/constants.js' @@ -19,16 +17,9 @@ export type UsePendingSafeOperationsReturnType = UseQueryResult { - if (!isDeployed) { - throw new Error('Safe is not deployed') - } - if (!safeClient.getPendingSafeOperations) throw new Error( 'To use Safe Operations, you need to specify the safeOperationOptions in the SafeProvider configuration.' diff --git a/src/hooks/useUpdateOwners/useAddOwner.ts b/src/hooks/useUpdateOwners/useAddOwner.ts index 0c64346..612fc94 100644 --- a/src/hooks/useUpdateOwners/useAddOwner.ts +++ b/src/hooks/useUpdateOwners/useAddOwner.ts @@ -2,7 +2,8 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@t import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' -import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useDynamicSafeAction } from '../useDynamicSafeAction.js' + import { MutationKey } from '@/constants.js' export type AddOwnerVariables = Parameters[0] @@ -23,7 +24,7 @@ export type UseAddOwnerReturnType = Omit< * @returns Object containing the mutation state and the function to add an owner. */ export function useAddOwner(params: UseAddOwnerParams = {}): UseAddOwnerReturnType { - const { sendTransactionAsync } = useSendTransaction({ config: params.config }) + const { sendAsync } = useDynamicSafeAction({ config: params.config }) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -33,7 +34,7 @@ export function useAddOwner(params: UseAddOwnerParams = {}): UseAddOwnerReturnTy mutationKey: [MutationKey.AddOwner], mutationSafeClientFn: async (safeClient, params) => { const addOwnerTx = await safeClient.createAddOwnerTransaction(params) - return sendTransactionAsync({ transactions: [addOwnerTx] }) + return sendAsync({ transactions: [addOwnerTx] }) } }) diff --git a/src/hooks/useUpdateOwners/useRemoveOwner.ts b/src/hooks/useUpdateOwners/useRemoveOwner.ts index 3d67fc0..d542b17 100644 --- a/src/hooks/useUpdateOwners/useRemoveOwner.ts +++ b/src/hooks/useUpdateOwners/useRemoveOwner.ts @@ -1,7 +1,7 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' -import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useDynamicSafeAction } from '../useDynamicSafeAction.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey } from '@/constants.js' @@ -23,7 +23,7 @@ export type UseRemoveOwnerReturnType = Omit< * @returns Object containing the mutation state and the function to remove an owner. */ export function useRemoveOwner(params: UseRemoveOwnerParams = {}): UseRemoveOwnerReturnType { - const { sendTransactionAsync } = useSendTransaction({ config: params.config }) + const { sendAsync } = useDynamicSafeAction({ config: params.config }) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -33,7 +33,7 @@ export function useRemoveOwner(params: UseRemoveOwnerParams = {}): UseRemoveOwne mutationKey: [MutationKey.RemoveOwner], mutationSafeClientFn: async (safeClient, params) => { const removeOwnerTx = await safeClient.createRemoveOwnerTransaction(params) - return sendTransactionAsync({ transactions: [removeOwnerTx] }) + return sendAsync({ transactions: [removeOwnerTx] }) } }) diff --git a/src/hooks/useUpdateOwners/useSwapOwner.ts b/src/hooks/useUpdateOwners/useSwapOwner.ts index 8f71a45..5c82f7d 100644 --- a/src/hooks/useUpdateOwners/useSwapOwner.ts +++ b/src/hooks/useUpdateOwners/useSwapOwner.ts @@ -2,7 +2,7 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@t import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' -import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useDynamicSafeAction } from '../useDynamicSafeAction.js' import { MutationKey } from '@/constants.js' export type SwapOwnerVariables = Parameters[0] @@ -23,7 +23,7 @@ export type UseSwapOwnerReturnType = Omit< * @returns Object containing the mutation state and the function to swap an owner. */ export function useSwapOwner(params: UseSwapOwnerParams = {}): UseSwapOwnerReturnType { - const { sendTransactionAsync } = useSendTransaction({ config: params.config }) + const { sendAsync } = useDynamicSafeAction({ config: params.config }) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -33,7 +33,7 @@ export function useSwapOwner(params: UseSwapOwnerParams = {}): UseSwapOwnerRetur mutationKey: [MutationKey.SwapOwner], mutationSafeClientFn: async (safeClient, params) => { const swapOwnerTx = await safeClient.createSwapOwnerTransaction(params) - return sendTransactionAsync({ transactions: [swapOwnerTx] }) + return sendAsync({ transactions: [swapOwnerTx] }) } }) diff --git a/src/hooks/useUpdateThreshold.ts b/src/hooks/useUpdateThreshold.ts index 64a010e..054a323 100644 --- a/src/hooks/useUpdateThreshold.ts +++ b/src/hooks/useUpdateThreshold.ts @@ -1,7 +1,7 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' -import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useDynamicSafeAction } from './useDynamicSafeAction.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey } from '@/constants.js' @@ -31,7 +31,7 @@ export type UseUpdateThresholdReturnType = Omit< export function useUpdateThreshold( params: UseUpdateThresholdParams = {} ): UseUpdateThresholdReturnType { - const { sendTransactionAsync } = useSendTransaction({ config: params.config }) + const { sendAsync } = useDynamicSafeAction({ config: params.config }) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -42,7 +42,7 @@ export function useUpdateThreshold( mutationSafeClientFn: async (signerClient, updateThresholdParams) => { const updateThresholdTx = await signerClient.createChangeThresholdTransaction(updateThresholdParams) - return sendTransactionAsync({ transactions: [updateThresholdTx] }) + return sendAsync({ transactions: [updateThresholdTx] }) } }) From 79fed23673788819047ed839ea6c06efec457cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Wed, 6 Nov 2024 17:09:19 +0100 Subject: [PATCH 06/12] Fix useDynamicSafeAction not picking correct context --- src/hooks/useDynamicSafeAction.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/useDynamicSafeAction.ts b/src/hooks/useDynamicSafeAction.ts index 6fd9272..ea78ec0 100644 --- a/src/hooks/useDynamicSafeAction.ts +++ b/src/hooks/useDynamicSafeAction.ts @@ -14,6 +14,7 @@ import { useConfirmTransaction, UseConfirmTransactionReturnType } from '@/hooks/useConfirmTransaction.js' +import { useConfig } from './useConfig.js' export type UseDynamicSafeActionParams = ConfigParam @@ -33,7 +34,9 @@ export type UseDynamicSafeActionReturnType = { export function useDynamicSafeAction( params: UseDynamicSafeActionParams = {} ): UseDynamicSafeActionReturnType { - const isSafeOperation = !!params.config?.safeOperationOptions + const [config] = useConfig({ config: params.config }) + + const isSafeOperation = !!config?.safeOperationOptions // Use the appropriate hooks based on the presence of safeOperations in the config const { sendSafeOperation, sendSafeOperationAsync }: UseSendSafeOperationReturnType = From 231ec7f3e655a37962a24ed3d3384ae629ed9876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Thu, 7 Nov 2024 13:55:04 +0100 Subject: [PATCH 07/12] Fix tests --- src/hooks/useUpdateOwners/useAddOwner.test.ts | 12 ++++++++---- src/hooks/useUpdateOwners/useRemoveOwner.test.ts | 12 ++++++++---- src/hooks/useUpdateOwners/useSwapOwner.test.ts | 12 ++++++++---- src/hooks/useUpdateThreshold.test.ts | 12 ++++++++---- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/hooks/useUpdateOwners/useAddOwner.test.ts b/src/hooks/useUpdateOwners/useAddOwner.test.ts index 8f1e357..1c0097f 100644 --- a/src/hooks/useUpdateOwners/useAddOwner.test.ts +++ b/src/hooks/useUpdateOwners/useAddOwner.test.ts @@ -4,13 +4,14 @@ import { SafeClient } from '@safe-global/sdk-starter-kit' import * as useSendTransaction from '@/hooks/useSendTransaction.js' import * as useSignerClientMutation from '@/hooks/useSignerClientMutation.js' import { useAddOwner } from '@/hooks/useUpdateOwners/useAddOwner.js' +import * as useConfig from '@/hooks//useConfig.js' import { accounts, ethereumTxHash, safeMultisigTransaction, signerPrivateKeys } from '@test/fixtures/index.js' -import { configPredictedSafe } from '@test/config.js' +import { configExistingSafe, configPredictedSafe } from '@test/config.js' import { createCustomMutationResult } from '@test/fixtures/mutationResult/index.js' import { renderHookInQueryClientProvider } from '@test/utils.js' import { MutationKey } from '@/constants.js' @@ -30,6 +31,7 @@ describe('useAddOwner', () => { const useSendTransactionSpy = jest.spyOn(useSendTransaction, 'useSendTransaction') const useSignerClientMutationSpy = jest.spyOn(useSignerClientMutation, 'useSignerClientMutation') + const useConfigSpy = jest.spyOn(useConfig, 'useConfig') const createAddOwnerTxResultMock = safeMultisigTransaction const createAddOwnerTxMock = jest.fn().mockResolvedValue(createAddOwnerTxResultMock) @@ -59,6 +61,8 @@ describe('useAddOwner', () => { useSendTransactionSpy.mockReturnValue({ sendTransactionAsync: sendTransactionAsyncMock } as unknown as useSendTransaction.UseSendTransactionReturnType) + + useConfigSpy.mockReturnValue([configExistingSafe, () => {}]) }) afterEach(() => { @@ -71,7 +75,7 @@ describe('useAddOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.AddOwner] @@ -79,7 +83,7 @@ describe('useAddOwner', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.AddOwner], mutationSafeClientFn: expect.any(Function) @@ -97,7 +101,7 @@ describe('useAddOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useRemoveOwner.test.ts b/src/hooks/useUpdateOwners/useRemoveOwner.test.ts index 48ef90f..7b24b78 100644 --- a/src/hooks/useUpdateOwners/useRemoveOwner.test.ts +++ b/src/hooks/useUpdateOwners/useRemoveOwner.test.ts @@ -3,6 +3,7 @@ import { waitFor } from '@testing-library/dom' import { SafeClient } from '@safe-global/sdk-starter-kit' import * as useSendTransaction from '@/hooks/useSendTransaction.js' import * as useSignerClientMutation from '@/hooks/useSignerClientMutation.js' +import * as useConfig from '@/hooks//useConfig.js' import { useRemoveOwner } from '@/hooks/useUpdateOwners/useRemoveOwner.js' import { accounts, @@ -10,7 +11,7 @@ import { safeMultisigTransaction, signerPrivateKeys } from '@test/fixtures/index.js' -import { configPredictedSafe } from '@test/config.js' +import { configExistingSafe, configPredictedSafe } from '@test/config.js' import { createCustomMutationResult } from '@test/fixtures/mutationResult/index.js' import { renderHookInQueryClientProvider } from '@test/utils.js' import { MutationKey } from '@/constants.js' @@ -30,6 +31,7 @@ describe('useRemoveOwner', () => { const useSendTransactionSpy = jest.spyOn(useSendTransaction, 'useSendTransaction') const useSignerClientMutationSpy = jest.spyOn(useSignerClientMutation, 'useSignerClientMutation') + const useConfigSpy = jest.spyOn(useConfig, 'useConfig') const createRemoveOwnerTxResultMock = safeMultisigTransaction const createRemoveOwnerTxMock = jest.fn().mockResolvedValue(createRemoveOwnerTxResultMock) @@ -60,6 +62,8 @@ describe('useRemoveOwner', () => { useSendTransactionSpy.mockReturnValue({ sendTransactionAsync: sendTransactionAsyncMock } as unknown as useSendTransaction.UseSendTransactionReturnType) + + useConfigSpy.mockReturnValue([configExistingSafe, () => {}]) }) afterEach(() => { @@ -72,7 +76,7 @@ describe('useRemoveOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.RemoveOwner] @@ -80,7 +84,7 @@ describe('useRemoveOwner', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.RemoveOwner], mutationSafeClientFn: expect.any(Function) @@ -98,7 +102,7 @@ describe('useRemoveOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useSwapOwner.test.ts b/src/hooks/useUpdateOwners/useSwapOwner.test.ts index 227241e..7d800ff 100644 --- a/src/hooks/useUpdateOwners/useSwapOwner.test.ts +++ b/src/hooks/useUpdateOwners/useSwapOwner.test.ts @@ -3,6 +3,7 @@ import { waitFor } from '@testing-library/dom' import { SafeClient } from '@safe-global/sdk-starter-kit' import * as useSendTransaction from '@/hooks/useSendTransaction.js' import * as useSignerClientMutation from '@/hooks/useSignerClientMutation.js' +import * as useConfig from '@/hooks//useConfig.js' import { useSwapOwner } from '@/hooks/useUpdateOwners/useSwapOwner.js' import { accounts, @@ -10,7 +11,7 @@ import { safeMultisigTransaction, signerPrivateKeys } from '@test/fixtures/index.js' -import { configPredictedSafe } from '@test/config.js' +import { configExistingSafe, configPredictedSafe } from '@test/config.js' import { createCustomMutationResult } from '@test/fixtures/mutationResult/index.js' import { renderHookInQueryClientProvider } from '@test/utils.js' import { MutationKey } from '@/constants.js' @@ -28,6 +29,7 @@ describe('useSwapOwner', () => { const useSendTransactionSpy = jest.spyOn(useSendTransaction, 'useSendTransaction') const useSignerClientMutationSpy = jest.spyOn(useSignerClientMutation, 'useSignerClientMutation') + const useConfigSpy = jest.spyOn(useConfig, 'useConfig') const createSwapOwnerTxResultMock = safeMultisigTransaction const createSwapOwnerTxMock = jest.fn().mockResolvedValue(createSwapOwnerTxResultMock) @@ -57,6 +59,8 @@ describe('useSwapOwner', () => { useSendTransactionSpy.mockReturnValue({ sendTransactionAsync: sendTransactionAsyncMock } as unknown as useSendTransaction.UseSendTransactionReturnType) + + useConfigSpy.mockReturnValue([configExistingSafe, () => {}]) }) afterEach(() => { @@ -69,7 +73,7 @@ describe('useSwapOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.SwapOwner] @@ -77,7 +81,7 @@ describe('useSwapOwner', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.SwapOwner], mutationSafeClientFn: expect.any(Function) @@ -95,7 +99,7 @@ describe('useSwapOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateThreshold.test.ts b/src/hooks/useUpdateThreshold.test.ts index 72bdf61..a3a0f99 100644 --- a/src/hooks/useUpdateThreshold.test.ts +++ b/src/hooks/useUpdateThreshold.test.ts @@ -4,8 +4,9 @@ import { SafeClient } from '@safe-global/sdk-starter-kit' import { useUpdateThreshold } from '@/hooks/useUpdateThreshold.js' import * as useSendTransaction from '@/hooks/useSendTransaction.js' import * as useSignerClientMutation from '@/hooks/useSignerClientMutation.js' +import * as useConfig from '@/hooks//useConfig.js' import { ethereumTxHash, safeMultisigTransaction, signerPrivateKeys } from '@test/fixtures/index.js' -import { configPredictedSafe } from '@test/config.js' +import { configExistingSafe, configPredictedSafe } from '@test/config.js' import { createCustomMutationResult } from '@test/fixtures/mutationResult/index.js' import { renderHookInQueryClientProvider } from '@test/utils.js' import { MutationKey } from '@/constants.js' @@ -27,6 +28,7 @@ describe('useUpdateThreshold', () => { const useSendTransactionSpy = jest.spyOn(useSendTransaction, 'useSendTransaction') const useSignerClientMutationSpy = jest.spyOn(useSignerClientMutation, 'useSignerClientMutation') + const useConfigSpy = jest.spyOn(useConfig, 'useConfig') const createChangeThresholdTxMock = jest.fn().mockResolvedValue(changeThresholdTxMock) @@ -55,6 +57,8 @@ describe('useUpdateThreshold', () => { useSendTransactionSpy.mockReturnValue({ sendTransactionAsync: sendTransactionAsyncMock } as unknown as useSendTransaction.UseSendTransactionReturnType) + + useConfigSpy.mockReturnValue([configExistingSafe, () => {}]) }) afterEach(() => { @@ -67,7 +71,7 @@ describe('useUpdateThreshold', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.UpdateThreshold] @@ -75,7 +79,7 @@ describe('useUpdateThreshold', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.UpdateThreshold], mutationSafeClientFn: expect.any(Function) @@ -93,7 +97,7 @@ describe('useUpdateThreshold', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(1) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), From 0d51c14668204a70afa2ba7197c712c3a93565f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Fri, 8 Nov 2024 13:46:13 +0100 Subject: [PATCH 08/12] update starter-kit version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7889d0c..3483b55 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "typescript": "^5.3.3" }, "dependencies": { - "@safe-global/sdk-starter-kit": "^1.0.1", + "@safe-global/sdk-starter-kit": "1.1.0", "viem": "^2.18.6", "wagmi": "^2.12.2" }, From bbfb0e8357b96c4f62a3d2366c166cee63942616 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:01:52 +0100 Subject: [PATCH 09/12] chore: set sdk-starter-kit version --- package.json | 2 +- yarn.lock | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 3483b55..08a36f6 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "typescript": "^5.3.3" }, "dependencies": { - "@safe-global/sdk-starter-kit": "1.1.0", + "@safe-global/sdk-starter-kit": "1.1.0-alpha.0", "viem": "^2.18.6", "wagmi": "^2.12.2" }, diff --git a/yarn.lock b/yarn.lock index 379d05c..e8bb641 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1065,36 +1065,36 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== -"@safe-global/api-kit@^2.5.1": - version "2.5.1" - resolved "https://registry.yarnpkg.com/@safe-global/api-kit/-/api-kit-2.5.1.tgz#621e814a2a1a057d594931b2b0184c8061e3b2cb" - integrity sha512-0M4oIpz1YIjLcNUDv6DG+56KsdveXNz4K9Z52zo5GneBrS12Q78PEY/O3WcF8mIEmY9X5W0YFmWwvmdv/cL8qA== +"@safe-global/api-kit@^2.5.5-alpha.0": + version "2.5.5-alpha.0" + resolved "https://registry.yarnpkg.com/@safe-global/api-kit/-/api-kit-2.5.5-alpha.0.tgz#08b7cd6e874f94451e0e04fee590ad462de6b9fd" + integrity sha512-KJIzvmBLPqVOHq3zmN9m7fDFTbEyAAOyrfVS+ZTGqzXHFanA4dHWFBU9qwDvQTMQljZMqonKYbKoS2wo8BlKaw== dependencies: - "@safe-global/protocol-kit" "^5.0.1" + "@safe-global/protocol-kit" "^5.0.5-alpha.0" "@safe-global/types-kit" "^1.0.0" node-fetch "^2.7.0" viem "^2.21.8" -"@safe-global/protocol-kit@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-5.0.1.tgz#886774f9a9f1712a52ee16950b4cb69f0188b88f" - integrity sha512-1nd+IIhNOSEMt9Mv7QEuPcEOOd4B+GMXPxADJCvSGkDmo1BwHi8EEn/HZfIPf/N92IswXd4cpA7oHnFaInS7tQ== +"@safe-global/protocol-kit@^5.0.5-alpha.0": + version "5.0.5-alpha.0" + resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-5.0.5-alpha.0.tgz#3848121dfaa2c7ea206900233a3d1cf1a9713a59" + integrity sha512-CYVyxjocb6Mm6Xt7M0ZNSRGELwSHZlFY24azEAd0AGK7S5XCLI3ircyzH9HbxPa8chRa90xrrv4urIO6GBzoiQ== dependencies: "@noble/hashes" "^1.3.3" - "@safe-global/safe-deployments" "^1.37.9" + "@safe-global/safe-deployments" "^1.37.14" "@safe-global/safe-modules-deployments" "^2.2.4" "@safe-global/types-kit" "^1.0.0" abitype "^1.0.2" semver "^7.6.3" viem "^2.21.8" -"@safe-global/relay-kit@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@safe-global/relay-kit/-/relay-kit-3.2.1.tgz#dccfee150090ab0312445d470c544fab245029f0" - integrity sha512-xrQuVCpoqq+GpL+VmIFx8JkKJUMyEZu0/ooUi3GraWPOP/NmWjn8CNp3A3XAI8dUlfVQwLie5BOE2eGqq9llxQ== +"@safe-global/relay-kit@^3.3.0-alpha.0": + version "3.3.0-alpha.0" + resolved "https://registry.yarnpkg.com/@safe-global/relay-kit/-/relay-kit-3.3.0-alpha.0.tgz#da23b2d9c7973f7db2c709158cfc82d4e51bfc0c" + integrity sha512-/woury8b8BHyugAHMhcviW4FrxXVY5U0ke1O1+btrRiq64q0VX86lMbuPnoFpDetlouxNvP0pSz2UyuGCPWeNg== dependencies: "@gelatonetwork/relay-sdk" "^5.5.0" - "@safe-global/protocol-kit" "^5.0.1" + "@safe-global/protocol-kit" "^5.0.5-alpha.0" "@safe-global/safe-modules-deployments" "^2.2.4" "@safe-global/types-kit" "^1.0.0" viem "^2.21.8" @@ -1115,10 +1115,10 @@ "@safe-global/safe-gateway-typescript-sdk" "^3.5.3" viem "^2.1.1" -"@safe-global/safe-deployments@^1.37.9": - version "1.37.10" - resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.10.tgz#2f61a25bd479332821ba2e91a575237d77406ec3" - integrity sha512-lcxX9CV+xdcLs4dF6Cx18zDww5JyqaX6RdcvU0o/34IgJ4Wjo3J/RNzJAoMhurCAfTGr+0vyJ9V13Qo50AR6JA== +"@safe-global/safe-deployments@^1.37.14": + version "1.37.14" + resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.14.tgz#31c1d1ff924d94ce639c136bef154de3adf5f75e" + integrity sha512-uHpYizq52j1arwWRxHbEbrZsECD5tG87NwLo/xDViRVw/GIrkRC6HerkzfZwiHVjVrC8gN8o3ApLsknYbxrF4w== dependencies: semver "^7.6.2" @@ -1132,14 +1132,14 @@ resolved "https://registry.yarnpkg.com/@safe-global/safe-modules-deployments/-/safe-modules-deployments-2.2.4.tgz#6e3b22af3a4eeba8e0a8f0952e575d25c5be216e" integrity sha512-m396ZrBPhZVYkapTTIuizyOOtoZsCKbicl0ztgDFfDbi7KbS6AtDP6cV89AYosQxUQS+v0q4ksQd30/j3L1BtQ== -"@safe-global/sdk-starter-kit@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@safe-global/sdk-starter-kit/-/sdk-starter-kit-1.0.1.tgz#aca1017b65bdd400c864538d59c24b2b302463d5" - integrity sha512-6OihdVs8JkxX+reZjVcv1XyOPOcHeT/aBYr3duJmuoxrnYmSfjK8An6XVxNRzJWYUdBOT4IHKLuCumnAmf1uYw== +"@safe-global/sdk-starter-kit@1.1.0-alpha.0": + version "1.1.0-alpha.0" + resolved "https://registry.yarnpkg.com/@safe-global/sdk-starter-kit/-/sdk-starter-kit-1.1.0-alpha.0.tgz#4f6da2fe5688553cc761e7a19036614a25ef5024" + integrity sha512-m3FtP1pBGS/cXV1eZRIg3eeqjQQSDMS+A4/OSr8vvIi4OgT0v67CTCMMo7J1XEnql1ptzWiTCbWgdj+V1l9vZA== dependencies: - "@safe-global/api-kit" "^2.5.1" - "@safe-global/protocol-kit" "^5.0.1" - "@safe-global/relay-kit" "^3.2.1" + "@safe-global/api-kit" "^2.5.5-alpha.0" + "@safe-global/protocol-kit" "^5.0.5-alpha.0" + "@safe-global/relay-kit" "^3.3.0-alpha.0" "@safe-global/types-kit" "^1.0.0" viem "^2.21.8" From e8727b7185b55c95bb5b1a6fdce52c5a7959c4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Fri, 8 Nov 2024 17:21:47 +0100 Subject: [PATCH 10/12] Remove unnecessary line break --- src/hooks/useSendTransaction.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/useSendTransaction.ts b/src/hooks/useSendTransaction.ts index e1a4ea6..3c18f57 100644 --- a/src/hooks/useSendTransaction.ts +++ b/src/hooks/useSendTransaction.ts @@ -51,6 +51,7 @@ export function useSendTransaction( if (result.transactions?.ethereumTxHash) { await waitForTransactionReceipt(result.transactions.ethereumTxHash) + invalidateQueries([QueryKey.PendingTransactions, QueryKey.SafeInfo]) await waitForTransactionIndexed(result.transactions) From a91f7ff44a748479dd469b61159902b5ff9918a1 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:24:36 +0100 Subject: [PATCH 11/12] chore: Set alpha release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 08a36f6..2b98fde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@safe-global/safe-react-hooks", - "version": "0.1.0", + "version": "0.2.0-alpha.0", "description": "A collection of React Hooks that facilitates the interaction of React apps with Safe Smart Accounts", "keywords": [ "Ethereum", From 95caf6d9ec3dac8adf10aa6e8623416fea562a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yago=20P=C3=A9rez=20V=C3=A1zquez?= Date: Mon, 11 Nov 2024 13:39:48 +0100 Subject: [PATCH 12/12] Remove useDynamicSafeAction because it is inefficient --- src/hooks/useDynamicSafeAction.ts | 60 ------------------- src/hooks/useUpdateOwners/useAddOwner.test.ts | 6 +- src/hooks/useUpdateOwners/useAddOwner.ts | 15 ++++- .../useUpdateOwners/useRemoveOwner.test.ts | 6 +- src/hooks/useUpdateOwners/useRemoveOwner.ts | 15 ++++- .../useUpdateOwners/useSwapOwner.test.ts | 6 +- src/hooks/useUpdateOwners/useSwapOwner.ts | 15 ++++- src/hooks/useUpdateThreshold.test.ts | 6 +- src/hooks/useUpdateThreshold.ts | 15 ++++- 9 files changed, 60 insertions(+), 84 deletions(-) delete mode 100644 src/hooks/useDynamicSafeAction.ts diff --git a/src/hooks/useDynamicSafeAction.ts b/src/hooks/useDynamicSafeAction.ts deleted file mode 100644 index ea78ec0..0000000 --- a/src/hooks/useDynamicSafeAction.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { UseMutateAsyncFunction, UseMutateFunction } from '@tanstack/react-query' -import { SafeClientResult } from '@safe-global/sdk-starter-kit' -import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' -import { - useSendSafeOperation, - UseSendSafeOperationReturnType -} from '@/hooks/useSendSafeOperation.js' -import { useSendTransaction, UseSendTransactionReturnType } from '@/hooks/useSendTransaction.js' -import { - useConfirmSafeOperation, - UseConfirmSafeOperationReturnType -} from '@/hooks/useConfirmSafeOperation.js' -import { - useConfirmTransaction, - UseConfirmTransactionReturnType -} from '@/hooks/useConfirmTransaction.js' -import { useConfig } from './useConfig.js' - -export type UseDynamicSafeActionParams = ConfigParam - -export type UseDynamicSafeActionReturnType = { - send: UseMutateFunction - sendAsync: UseMutateAsyncFunction - confirm: UseMutateFunction - confirmAsync: UseMutateAsyncFunction -} - -/** - * Hook to dynamically choose between Safe Operations and Transactions. - * @param params Parameters to customize the hook behavior. - * @param params.config SafeConfig to use instead of the one provided by `SafeProvider`. - * @returns Object containing the mutation state and the send and confirm functions. - */ -export function useDynamicSafeAction( - params: UseDynamicSafeActionParams = {} -): UseDynamicSafeActionReturnType { - const [config] = useConfig({ config: params.config }) - - const isSafeOperation = !!config?.safeOperationOptions - - // Use the appropriate hooks based on the presence of safeOperations in the config - const { sendSafeOperation, sendSafeOperationAsync }: UseSendSafeOperationReturnType = - useSendSafeOperation(params) - - const { sendTransaction, sendTransactionAsync }: UseSendTransactionReturnType = - useSendTransaction(params) - - const { confirmSafeOperation, confirmSafeOperationAsync }: UseConfirmSafeOperationReturnType = - useConfirmSafeOperation(params) - - const { confirmTransaction, confirmTransactionAsync }: UseConfirmTransactionReturnType = - useConfirmTransaction(params) - - return { - send: isSafeOperation ? sendSafeOperation : sendTransaction, - sendAsync: isSafeOperation ? sendSafeOperationAsync : sendTransactionAsync, - confirm: isSafeOperation ? confirmSafeOperation : confirmTransaction, - confirmAsync: isSafeOperation ? confirmSafeOperationAsync : confirmTransactionAsync - } -} diff --git a/src/hooks/useUpdateOwners/useAddOwner.test.ts b/src/hooks/useUpdateOwners/useAddOwner.test.ts index 1c0097f..be6f835 100644 --- a/src/hooks/useUpdateOwners/useAddOwner.test.ts +++ b/src/hooks/useUpdateOwners/useAddOwner.test.ts @@ -75,7 +75,7 @@ describe('useAddOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.AddOwner] @@ -83,7 +83,7 @@ describe('useAddOwner', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.AddOwner], mutationSafeClientFn: expect.any(Function) @@ -101,7 +101,7 @@ describe('useAddOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useAddOwner.ts b/src/hooks/useUpdateOwners/useAddOwner.ts index 612fc94..de5649a 100644 --- a/src/hooks/useUpdateOwners/useAddOwner.ts +++ b/src/hooks/useUpdateOwners/useAddOwner.ts @@ -1,8 +1,10 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' +import { useSendSafeOperation } from '@/hooks/useSendSafeOperation.js' +import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useConfig } from '@/hooks/useConfig.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' -import { useDynamicSafeAction } from '../useDynamicSafeAction.js' import { MutationKey } from '@/constants.js' @@ -24,7 +26,9 @@ export type UseAddOwnerReturnType = Omit< * @returns Object containing the mutation state and the function to add an owner. */ export function useAddOwner(params: UseAddOwnerParams = {}): UseAddOwnerReturnType { - const { sendAsync } = useDynamicSafeAction({ config: params.config }) + const [config] = useConfig({ config: params.config }) + const { sendSafeOperationAsync } = useSendSafeOperation(params) + const { sendTransactionAsync } = useSendTransaction(params) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -34,7 +38,12 @@ export function useAddOwner(params: UseAddOwnerParams = {}): UseAddOwnerReturnTy mutationKey: [MutationKey.AddOwner], mutationSafeClientFn: async (safeClient, params) => { const addOwnerTx = await safeClient.createAddOwnerTransaction(params) - return sendAsync({ transactions: [addOwnerTx] }) + + const isSafeOperation = !!config.safeOperationOptions + + return isSafeOperation + ? sendSafeOperationAsync({ transactions: [addOwnerTx] }) + : sendTransactionAsync({ transactions: [addOwnerTx] }) } }) diff --git a/src/hooks/useUpdateOwners/useRemoveOwner.test.ts b/src/hooks/useUpdateOwners/useRemoveOwner.test.ts index 7b24b78..a297590 100644 --- a/src/hooks/useUpdateOwners/useRemoveOwner.test.ts +++ b/src/hooks/useUpdateOwners/useRemoveOwner.test.ts @@ -76,7 +76,7 @@ describe('useRemoveOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.RemoveOwner] @@ -84,7 +84,7 @@ describe('useRemoveOwner', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.RemoveOwner], mutationSafeClientFn: expect.any(Function) @@ -102,7 +102,7 @@ describe('useRemoveOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useRemoveOwner.ts b/src/hooks/useUpdateOwners/useRemoveOwner.ts index d542b17..6009332 100644 --- a/src/hooks/useUpdateOwners/useRemoveOwner.ts +++ b/src/hooks/useUpdateOwners/useRemoveOwner.ts @@ -1,7 +1,9 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' -import { useDynamicSafeAction } from '../useDynamicSafeAction.js' +import { useSendSafeOperation } from '@/hooks/useSendSafeOperation.js' +import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useConfig } from '@/hooks/useConfig.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey } from '@/constants.js' @@ -23,7 +25,9 @@ export type UseRemoveOwnerReturnType = Omit< * @returns Object containing the mutation state and the function to remove an owner. */ export function useRemoveOwner(params: UseRemoveOwnerParams = {}): UseRemoveOwnerReturnType { - const { sendAsync } = useDynamicSafeAction({ config: params.config }) + const [config] = useConfig({ config: params.config }) + const { sendSafeOperationAsync } = useSendSafeOperation(params) + const { sendTransactionAsync } = useSendTransaction(params) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -33,7 +37,12 @@ export function useRemoveOwner(params: UseRemoveOwnerParams = {}): UseRemoveOwne mutationKey: [MutationKey.RemoveOwner], mutationSafeClientFn: async (safeClient, params) => { const removeOwnerTx = await safeClient.createRemoveOwnerTransaction(params) - return sendAsync({ transactions: [removeOwnerTx] }) + + const isSafeOperation = !!config.safeOperationOptions + + return isSafeOperation + ? sendSafeOperationAsync({ transactions: [removeOwnerTx] }) + : sendTransactionAsync({ transactions: [removeOwnerTx] }) } }) diff --git a/src/hooks/useUpdateOwners/useSwapOwner.test.ts b/src/hooks/useUpdateOwners/useSwapOwner.test.ts index 7d800ff..78c826b 100644 --- a/src/hooks/useUpdateOwners/useSwapOwner.test.ts +++ b/src/hooks/useUpdateOwners/useSwapOwner.test.ts @@ -73,7 +73,7 @@ describe('useSwapOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.SwapOwner] @@ -81,7 +81,7 @@ describe('useSwapOwner', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.SwapOwner], mutationSafeClientFn: expect.any(Function) @@ -99,7 +99,7 @@ describe('useSwapOwner', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useSwapOwner.ts b/src/hooks/useUpdateOwners/useSwapOwner.ts index 5c82f7d..68fe05f 100644 --- a/src/hooks/useUpdateOwners/useSwapOwner.ts +++ b/src/hooks/useUpdateOwners/useSwapOwner.ts @@ -1,8 +1,10 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner, SafeClient } from '@/types/index.js' +import { useSendSafeOperation } from '@/hooks/useSendSafeOperation.js' +import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useConfig } from '@/hooks/useConfig.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' -import { useDynamicSafeAction } from '../useDynamicSafeAction.js' import { MutationKey } from '@/constants.js' export type SwapOwnerVariables = Parameters[0] @@ -23,7 +25,9 @@ export type UseSwapOwnerReturnType = Omit< * @returns Object containing the mutation state and the function to swap an owner. */ export function useSwapOwner(params: UseSwapOwnerParams = {}): UseSwapOwnerReturnType { - const { sendAsync } = useDynamicSafeAction({ config: params.config }) + const [config] = useConfig({ config: params.config }) + const { sendSafeOperationAsync } = useSendSafeOperation(params) + const { sendTransactionAsync } = useSendTransaction(params) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -33,7 +37,12 @@ export function useSwapOwner(params: UseSwapOwnerParams = {}): UseSwapOwnerRetur mutationKey: [MutationKey.SwapOwner], mutationSafeClientFn: async (safeClient, params) => { const swapOwnerTx = await safeClient.createSwapOwnerTransaction(params) - return sendAsync({ transactions: [swapOwnerTx] }) + + const isSafeOperation = !!config.safeOperationOptions + + return isSafeOperation + ? sendSafeOperationAsync({ transactions: [swapOwnerTx] }) + : sendTransactionAsync({ transactions: [swapOwnerTx] }) } }) diff --git a/src/hooks/useUpdateThreshold.test.ts b/src/hooks/useUpdateThreshold.test.ts index a3a0f99..467f89f 100644 --- a/src/hooks/useUpdateThreshold.test.ts +++ b/src/hooks/useUpdateThreshold.test.ts @@ -71,7 +71,7 @@ describe('useUpdateThreshold', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config: undefined }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationSafeClientFn: expect.any(Function), mutationKey: [MutationKey.UpdateThreshold] @@ -79,7 +79,7 @@ describe('useUpdateThreshold', () => { expect(result.current).toEqual(mutationIdleResult) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ mutationKey: [MutationKey.UpdateThreshold], mutationSafeClientFn: expect.any(Function) @@ -97,7 +97,7 @@ describe('useUpdateThreshold', () => { expect(useSendTransactionSpy).toHaveBeenCalledTimes(1) expect(useSendTransactionSpy).toHaveBeenCalledWith({ config }) - expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(4) + expect(useSignerClientMutationSpy).toHaveBeenCalledTimes(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateThreshold.ts b/src/hooks/useUpdateThreshold.ts index 054a323..4ae2ccb 100644 --- a/src/hooks/useUpdateThreshold.ts +++ b/src/hooks/useUpdateThreshold.ts @@ -1,7 +1,9 @@ import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' import { SafeClientResult } from '@safe-global/sdk-starter-kit' import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' -import { useDynamicSafeAction } from './useDynamicSafeAction.js' +import { useSendSafeOperation } from '@/hooks/useSendSafeOperation.js' +import { useSendTransaction } from '@/hooks/useSendTransaction.js' +import { useConfig } from '@/hooks/useConfig.js' import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' import { MutationKey } from '@/constants.js' @@ -31,7 +33,9 @@ export type UseUpdateThresholdReturnType = Omit< export function useUpdateThreshold( params: UseUpdateThresholdParams = {} ): UseUpdateThresholdReturnType { - const { sendAsync } = useDynamicSafeAction({ config: params.config }) + const [config] = useConfig({ config: params.config }) + const { sendSafeOperationAsync } = useSendSafeOperation(params) + const { sendTransactionAsync } = useSendTransaction(params) const { mutate, mutateAsync, ...result } = useSignerClientMutation< SafeClientResult, @@ -42,7 +46,12 @@ export function useUpdateThreshold( mutationSafeClientFn: async (signerClient, updateThresholdParams) => { const updateThresholdTx = await signerClient.createChangeThresholdTransaction(updateThresholdParams) - return sendAsync({ transactions: [updateThresholdTx] }) + + const isSafeOperation = !!config.safeOperationOptions + + return isSafeOperation + ? sendSafeOperationAsync({ transactions: [updateThresholdTx] }) + : sendTransactionAsync({ transactions: [updateThresholdTx] }) } })