diff --git a/package.json b/package.json index 7889d0c..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", @@ -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-alpha.0", "viem": "^2.18.6", "wagmi": "^2.12.2" }, 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/constants.ts b/src/constants.ts index 61eacfd..f02f218 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,7 +6,9 @@ export enum QueryKey { Threshold = 'threshold', IsDeployed = 'isDeployed', Owners = 'owners', - SafeInfo = 'safeInfo' + SafeInfo = 'safeInfo', + SafeOperations = 'safeOperations', + PendingSafeOperations = 'pendingSafeOperations' } export enum MutationKey { @@ -15,5 +17,7 @@ export enum MutationKey { UpdateThreshold = 'updateThreshold', SwapOwner = 'swapOwner', AddOwner = 'addOwner', - RemoveOwner = 'removeOwner' + RemoveOwner = 'removeOwner', + SendSafeOperation = 'sendSafeOperation', + ConfirmSafeOperation = 'confirmSafeOperation' } diff --git a/src/createClient.ts b/src/createClient.ts index 57069d2..e47dac0 100644 --- a/src/createClient.ts +++ b/src/createClient.ts @@ -1,5 +1,18 @@ -import type { SafeConfig, SafeConfigWithSigner } from '@/types/index.js' -import { createSafeClient } from '@safe-global/sdk-starter-kit' +import { createSafeClient, safeOperations } from '@safe-global/sdk-starter-kit' +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, @@ -12,16 +25,26 @@ 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)) + + return config.safeOperationOptions + ? await extendWithSafeOperations(publicClient, config.safeOperationOptions) + : 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 }) + + return config.safeOperationOptions + ? await extendWithSafeOperations(signerClient, config.safeOperationOptions) + : signerClient +} 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..c236f04 --- /dev/null +++ b/src/hooks/useConfirmSafeOperation.ts @@ -0,0 +1,65 @@ +import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' +import { ConfirmSafeOperationProps, SafeClientResult } from '@safe-global/sdk-starter-kit' +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 { mutate, mutateAsync, ...result } = useSignerClientMutation< + SafeClientResult, + ConfirmSafeOperationVariables + >({ + ...params, + mutationKey: [MutationKey.ConfirmSafeOperation], + mutationSafeClientFn: async (signerClient, { safeOperationHash }) => { + 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 + }) + + 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..c9d2f58 --- /dev/null +++ b/src/hooks/usePendingSafeOperations.ts @@ -0,0 +1,37 @@ +import { type UseQueryResult } from '@tanstack/react-query' +import { ListOptions } from '@safe-global/api-kit' +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' + +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 { + return usePublicClientQuery({ + ...params, + querySafeClientFn: async (safeClient) => { + 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, + offset: params.offset + }) + + return pendingSafeOperations + }, + queryKey: [QueryKey.PendingSafeOperations] + }) +} 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/useSafe.ts b/src/hooks/useSafe.ts index dac7f79..a43b8a5 100644 --- a/src/hooks/useSafe.ts +++ b/src/hooks/useSafe.ts @@ -8,7 +8,10 @@ import { useSafeInfo, useSignerAddress, useTransaction, - useTransactions + useTransactions, + usePendingSafeOperations, + useSafeOperation, + 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 + getPendingSafeOperations: typeof usePendingSafeOperations + getSafeOperation: typeof useSafeOperation + getSafeOperations: typeof useSafeOperations } /** @@ -49,6 +55,9 @@ export function useSafe(): UseSafeReturnType { getTransaction: useTransaction, getTransactions: useTransactions, getSafeInfo: useSafeInfo, - getSignerAddress: useSignerAddress + getSignerAddress: useSignerAddress, + getPendingSafeOperations: usePendingSafeOperations, + getSafeOperation: useSafeOperation, + getSafeOperations: useSafeOperations } } 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..62d936a --- /dev/null +++ b/src/hooks/useSendSafeOperation.ts @@ -0,0 +1,61 @@ +import { UseMutateAsyncFunction, UseMutateFunction, UseMutationResult } from '@tanstack/react-query' +import { SafeClientResult, SendSafeOperationProps } from '@safe-global/sdk-starter-kit' +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 { mutate, mutateAsync, ...result } = useSignerClientMutation< + SafeClientResult, + SendSafeOperationVariables + >({ + ...params, + mutationKey: [MutationKey.SendSafeOperation], + mutationSafeClientFn: async (signerClient, { transactions = [], ...paymasterSendOptions }) => { + 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 + }) + + if (result.safeOperations?.userOperationHash) { + invalidateQueries([QueryKey.SafeOperations, QueryKey.SafeInfo]) + } else if (result.safeOperations?.safeOperationHash) { + invalidateQueries([QueryKey.PendingSafeOperations]) + } + + return result + } + }) + + return { ...result, sendSafeOperation: mutate, sendSafeOperationAsync: mutateAsync } +} 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.test.ts b/src/hooks/useUpdateOwners/useAddOwner.test.ts index 8f1e357..be6f835 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(2) 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(2) 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(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useAddOwner.ts b/src/hooks/useUpdateOwners/useAddOwner.ts index 1c4ce8c..de5649a 100644 --- a/src/hooks/useUpdateOwners/useAddOwner.ts +++ b/src/hooks/useUpdateOwners/useAddOwner.ts @@ -1,8 +1,11 @@ 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 { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' +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 { MutationKey } from '@/constants.js' export type AddOwnerVariables = Parameters[0] @@ -23,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 { sendTransactionAsync } = useSendTransaction({ 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 +38,12 @@ export function useAddOwner(params: UseAddOwnerParams = {}): UseAddOwnerReturnTy mutationKey: [MutationKey.AddOwner], mutationSafeClientFn: async (safeClient, params) => { const addOwnerTx = await safeClient.createAddOwnerTransaction(params) - return sendTransactionAsync({ 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 48ef90f..a297590 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(2) 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(2) 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(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useRemoveOwner.ts b/src/hooks/useUpdateOwners/useRemoveOwner.ts index a5ae292..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 { 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 { 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 { sendTransactionAsync } = useSendTransaction({ 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 sendTransactionAsync({ 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 227241e..78c826b 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(2) 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(2) 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(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateOwners/useSwapOwner.ts b/src/hooks/useUpdateOwners/useSwapOwner.ts index 33d1521..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 { SafeClient, SafeClientResult } from '@safe-global/sdk-starter-kit' -import { ConfigParam, SafeConfigWithSigner } from '@/types/index.js' -import { useSignerClientMutation } from '@/hooks/useSignerClientMutation.js' +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 { 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 { sendTransactionAsync } = useSendTransaction({ 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 sendTransactionAsync({ 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 72bdf61..467f89f 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(2) 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(2) 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(2) expect(useSignerClientMutationSpy).toHaveBeenCalledWith({ config, mutationSafeClientFn: expect.any(Function), diff --git a/src/hooks/useUpdateThreshold.ts b/src/hooks/useUpdateThreshold.ts index 64a010e..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 { 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 { sendTransactionAsync } = useSendTransaction({ 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 sendTransactionAsync({ transactions: [updateThresholdTx] }) + + const isSafeOperation = !!config.safeOperationOptions + + return isSafeOperation + ? sendSafeOperationAsync({ transactions: [updateThresholdTx] }) + : sendTransactionAsync({ transactions: [updateThresholdTx] }) } }) 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..15f45e8 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,17 +1,48 @@ -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 +} 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 SafeOperationOptions = BundlerOptions & PaymasterOptions + 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?: SafeOperationOptions +} & SdkStarterKitConfig export type SafeConfig< Provider extends SdkStarterKitConfig['provider'] = SdkStarterKitConfig['provider'], @@ -21,6 +52,7 @@ export type SafeConfig< chain: Chain provider: Provider signer: Signer + safeOperationOptions?: SafeOperationOptions } & (Provider extends string ? { transport: HttpTransport } : { transport: CustomTransport }) export type SafeConfigWithSigner = SafeConfig & { signer: string } 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"