From af88f2d656ea6fcc034421adb249c2a3422f5c92 Mon Sep 17 00:00:00 2001 From: Vitor Date: Mon, 14 Oct 2024 15:41:05 -0300 Subject: [PATCH 1/9] feat: useRequestPermissions hook --- .../src/actions/requestPermissions.test.ts | 31 +++++++ .../core/src/actions/requestPermissions.ts | 48 ++++++++++ packages/core/src/connectors/mock.ts | 23 +++++ packages/core/src/exports/actions.test.ts | 1 + packages/core/src/exports/actions.ts | 7 ++ packages/core/src/exports/index.test.ts | 1 + packages/core/src/exports/index.ts | 7 ++ packages/core/src/exports/query.test.ts | 1 + packages/core/src/exports/query.ts | 8 ++ .../core/src/query/requestPermissions.test.ts | 15 ++++ packages/core/src/query/requestPermissions.ts | 41 +++++++++ packages/react/src/exports/actions.test.ts | 1 + packages/react/src/exports/index.test.ts | 1 + packages/react/src/exports/index.ts | 6 ++ packages/react/src/exports/query.test.ts | 1 + .../src/hooks/useRequestPermissions.test-d.ts | 67 ++++++++++++++ .../src/hooks/useRequestPermissions.test.ts | 36 ++++++++ .../react/src/hooks/useRequestPermissions.ts | 65 ++++++++++++++ packages/vue/src/exports/actions.test.ts | 1 + packages/vue/src/exports/query.test.ts | 1 + site/.vitepress/sidebar.ts | 2 + site/core/api/actions/requestPermissions.md | 78 ++++++++++++++++ site/react/api/hooks/useRequestPermissions.md | 89 +++++++++++++++++++ 23 files changed, 531 insertions(+) create mode 100644 packages/core/src/actions/requestPermissions.test.ts create mode 100644 packages/core/src/actions/requestPermissions.ts create mode 100644 packages/core/src/query/requestPermissions.test.ts create mode 100644 packages/core/src/query/requestPermissions.ts create mode 100644 packages/react/src/hooks/useRequestPermissions.test-d.ts create mode 100644 packages/react/src/hooks/useRequestPermissions.test.ts create mode 100644 packages/react/src/hooks/useRequestPermissions.ts create mode 100644 site/core/api/actions/requestPermissions.md create mode 100644 site/react/api/hooks/useRequestPermissions.md diff --git a/packages/core/src/actions/requestPermissions.test.ts b/packages/core/src/actions/requestPermissions.test.ts new file mode 100644 index 0000000000..44521b08fe --- /dev/null +++ b/packages/core/src/actions/requestPermissions.test.ts @@ -0,0 +1,31 @@ +import { config } from '@wagmi/test' +import { expect, test } from 'vitest' + +import { connect } from './connect.js' +import { disconnect } from './disconnect.js' +import { requestPermissions } from './requestPermissions.js' + +const connector = config.connectors[0]! + +test('default', async () => { + await connect(config, { connector }) + await expect( + requestPermissions(config, { eth_accounts: {} }), + ).resolves.toMatchInlineSnapshot(` + [ + { + "caveats": [ + { + "type": "filterResponse", + "value": [ + "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", + ], + }, + ], + "invoker": "https://example.com", + "parentCapability": "eth_accounts", + }, + ] + `) + await disconnect(config, { connector }) +}) diff --git a/packages/core/src/actions/requestPermissions.ts b/packages/core/src/actions/requestPermissions.ts new file mode 100644 index 0000000000..fb2a446cfe --- /dev/null +++ b/packages/core/src/actions/requestPermissions.ts @@ -0,0 +1,48 @@ +import { + type RequestPermissionsErrorType as viem_RequestPermissionsErrorType, + type RequestPermissionsParameters as viem_RequestPermissionsParameters, + type RequestPermissionsReturnType as viem_RequestPermissionsReturnType, + requestPermissions as viem_requestPermissions, +} from 'viem/actions' + +import type { Config } from '../createConfig.js' +import type { BaseErrorType, ErrorType } from '../errors/base.js' +import type { ConnectorParameter } from '../types/properties.js' +import type { Compute } from '../types/utils.js' +import { getAction } from '../utils/getAction.js' +import { + type GetConnectorClientErrorType, + getConnectorClient, +} from './getConnectorClient.js' + +export type RequestPermissionsParameters = Compute< + viem_RequestPermissionsParameters & ConnectorParameter +> + +export type RequestPermissionsReturnType = viem_RequestPermissionsReturnType + +export type RequestPermissionsErrorType = + // getConnectorClient() + | GetConnectorClientErrorType + // base + | BaseErrorType + | ErrorType + // viem + | viem_RequestPermissionsErrorType + +/** https://wagmi.sh/core/api/actions/requestPermissions */ +export async function requestPermissions( + config: Config, + parameters: RequestPermissionsParameters, +): Promise { + const { connector, ...rest } = parameters + + const client = await getConnectorClient(config, { connector }) + + const action = getAction( + client, + viem_requestPermissions, + 'requestPermissions', + ) + return action(rest) +} diff --git a/packages/core/src/connectors/mock.ts b/packages/core/src/connectors/mock.ts index 8c6fa4d57b..641dd73917 100644 --- a/packages/core/src/connectors/mock.ts +++ b/packages/core/src/connectors/mock.ts @@ -32,6 +32,7 @@ export type MockParameters = { signMessageError?: boolean | Error | undefined signTypedDataError?: boolean | Error | undefined reconnect?: boolean | undefined + requestPermissionsError?: boolean | Error | undefined watchAssetError?: boolean | Error | undefined } | undefined @@ -250,6 +251,28 @@ export function mock(parameters: MockParameters) { if (method === 'wallet_showCallsStatus') return + if (method === 'wallet_requestPermissions') { + if (features.requestPermissionsError) { + if (typeof features.requestPermissionsError === 'boolean') + throw new UserRejectedRequestError( + new Error('Failed to request permissions.'), + ) + throw features.requestPermissionsError + } + return [ + { + invoker: 'https://example.com', + parentCapability: 'eth_accounts', + caveats: [ + { + type: 'filterResponse', + value: ['0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb'], + }, + ], + }, + ] + } + // other methods if (method === 'personal_sign') { if (features.signMessageError) { diff --git a/packages/core/src/exports/actions.test.ts b/packages/core/src/exports/actions.test.ts index 77f805d96c..79162348ef 100644 --- a/packages/core/src/exports/actions.test.ts +++ b/packages/core/src/exports/actions.test.ts @@ -53,6 +53,7 @@ test('exports', () => { "readContract", "readContracts", "reconnect", + "requestPermissions", "sendTransaction", "signMessage", "signTypedData", diff --git a/packages/core/src/exports/actions.ts b/packages/core/src/exports/actions.ts index d5d6b21760..4b32fd1ebe 100644 --- a/packages/core/src/exports/actions.ts +++ b/packages/core/src/exports/actions.ts @@ -286,6 +286,13 @@ export { reconnect, } from '../actions/reconnect.js' +export { + type RequestPermissionsErrorType, + type RequestPermissionsParameters, + type RequestPermissionsReturnType, + requestPermissions, +} from '../actions/requestPermissions.js' + export { type SendTransactionErrorType, type SendTransactionParameters, diff --git a/packages/core/src/exports/index.test.ts b/packages/core/src/exports/index.test.ts index 2d6953b9cc..0e15d2f92f 100644 --- a/packages/core/src/exports/index.test.ts +++ b/packages/core/src/exports/index.test.ts @@ -53,6 +53,7 @@ test('exports', () => { "readContract", "readContracts", "reconnect", + "requestPermissions", "sendTransaction", "signMessage", "signTypedData", diff --git a/packages/core/src/exports/index.ts b/packages/core/src/exports/index.ts index 69dae7cc17..092f933261 100644 --- a/packages/core/src/exports/index.ts +++ b/packages/core/src/exports/index.ts @@ -286,6 +286,13 @@ export { reconnect, } from '../actions/reconnect.js' +export { + type RequestPermissionsErrorType, + type RequestPermissionsParameters, + type RequestPermissionsReturnType, + requestPermissions, +} from '../actions/requestPermissions.js' + export { type SendTransactionErrorType, type SendTransactionParameters, diff --git a/packages/core/src/exports/query.test.ts b/packages/core/src/exports/query.test.ts index 777bfe9abe..571d75b081 100644 --- a/packages/core/src/exports/query.test.ts +++ b/packages/core/src/exports/query.test.ts @@ -67,6 +67,7 @@ test('exports', () => { "readContractsQueryKey", "readContractsQueryOptions", "reconnectMutationOptions", + "requestPermissionsMutationOptions", "sendTransactionMutationOptions", "signMessageMutationOptions", "signTypedDataMutationOptions", diff --git a/packages/core/src/exports/query.ts b/packages/core/src/exports/query.ts index 5746148bab..7776fb95f7 100644 --- a/packages/core/src/exports/query.ts +++ b/packages/core/src/exports/query.ts @@ -296,6 +296,14 @@ export { reconnectMutationOptions, } from '../query/reconnect.js' +export { + type RequestPermissionsData, + type RequestPermissionsVariables, + type RequestPermissionsMutate, + type RequestPermissionsMutateAsync, + requestPermissionsMutationOptions, +} from '../query/requestPermissions.js' + export { type SendTransactionData, type SendTransactionVariables, diff --git a/packages/core/src/query/requestPermissions.test.ts b/packages/core/src/query/requestPermissions.test.ts new file mode 100644 index 0000000000..142c57251d --- /dev/null +++ b/packages/core/src/query/requestPermissions.test.ts @@ -0,0 +1,15 @@ +import { config } from '@wagmi/test' +import { expect, test } from 'vitest' + +import { requestPermissionsMutationOptions } from './requestPermissions.js' + +test('default', () => { + expect(requestPermissionsMutationOptions(config)).toMatchInlineSnapshot(` + { + "mutationFn": [Function], + "mutationKey": [ + "requestPermissions", + ], + } + `) +}) diff --git a/packages/core/src/query/requestPermissions.ts b/packages/core/src/query/requestPermissions.ts new file mode 100644 index 0000000000..89adfa53fc --- /dev/null +++ b/packages/core/src/query/requestPermissions.ts @@ -0,0 +1,41 @@ +import type { MutationOptions } from '@tanstack/query-core' + +import { + type RequestPermissionsErrorType, + type RequestPermissionsParameters, + type RequestPermissionsReturnType, + requestPermissions, +} from '../actions/requestPermissions.js' +import type { Config } from '../createConfig.js' +import type { Mutate, MutateAsync } from './types.js' + +export function requestPermissionsMutationOptions(config: Config) { + return { + mutationFn(variables) { + return requestPermissions(config, variables) + }, + mutationKey: ['requestPermissions'], + } as const satisfies MutationOptions< + RequestPermissionsData, + RequestPermissionsErrorType, + RequestPermissionsVariables + > +} + +export type RequestPermissionsData = RequestPermissionsReturnType + +export type RequestPermissionsVariables = RequestPermissionsParameters + +export type RequestPermissionsMutate = Mutate< + RequestPermissionsData, + RequestPermissionsErrorType, + RequestPermissionsVariables, + context +> + +export type RequestPermissionsMutateAsync = MutateAsync< + RequestPermissionsData, + RequestPermissionsErrorType, + RequestPermissionsVariables, + context +> diff --git a/packages/react/src/exports/actions.test.ts b/packages/react/src/exports/actions.test.ts index 77f805d96c..79162348ef 100644 --- a/packages/react/src/exports/actions.test.ts +++ b/packages/react/src/exports/actions.test.ts @@ -53,6 +53,7 @@ test('exports', () => { "readContract", "readContracts", "reconnect", + "requestPermissions", "sendTransaction", "signMessage", "signTypedData", diff --git a/packages/react/src/exports/index.test.ts b/packages/react/src/exports/index.test.ts index cba2fa8d59..99a3af38e5 100644 --- a/packages/react/src/exports/index.test.ts +++ b/packages/react/src/exports/index.test.ts @@ -50,6 +50,7 @@ test('exports', () => { "useReadContracts", "useContractReads", "useReconnect", + "useRequestPermissions", "useSendTransaction", "useSignMessage", "useSignTypedData", diff --git a/packages/react/src/exports/index.ts b/packages/react/src/exports/index.ts index 7a08838ce4..1069136aac 100644 --- a/packages/react/src/exports/index.ts +++ b/packages/react/src/exports/index.ts @@ -245,6 +245,12 @@ export { useReconnect, } from '../hooks/useReconnect.js' +export { + type UseRequestPermissionsParameters, + type UseRequestPermissionsReturnType, + useRequestPermissions, +} from '../hooks/useRequestPermissions.js' + export { type UseSendTransactionParameters, type UseSendTransactionReturnType, diff --git a/packages/react/src/exports/query.test.ts b/packages/react/src/exports/query.test.ts index fe4130815d..d02001d527 100644 --- a/packages/react/src/exports/query.test.ts +++ b/packages/react/src/exports/query.test.ts @@ -67,6 +67,7 @@ test('exports', () => { "readContractsQueryKey", "readContractsQueryOptions", "reconnectMutationOptions", + "requestPermissionsMutationOptions", "sendTransactionMutationOptions", "signMessageMutationOptions", "signTypedDataMutationOptions", diff --git a/packages/react/src/hooks/useRequestPermissions.test-d.ts b/packages/react/src/hooks/useRequestPermissions.test-d.ts new file mode 100644 index 0000000000..638e6f7b27 --- /dev/null +++ b/packages/react/src/hooks/useRequestPermissions.test-d.ts @@ -0,0 +1,67 @@ +import type { RequestPermissionsErrorType } from '@wagmi/core' +import type { RequestPermissionsVariables } from '@wagmi/core/query' +import { expectTypeOf, test } from 'vitest' + +import { useRequestPermissions } from './useRequestPermissions.js' +import type { WalletPermission } from 'viem' + +const contextValue = { foo: 'bar' } as const + +test('context', () => { + const { context, data, error, requestPermissions, variables } = + useRequestPermissions({ + mutation: { + onMutate(variables) { + expectTypeOf(variables).toEqualTypeOf() + return contextValue + }, + onError(error, variables, context) { + expectTypeOf(variables).toEqualTypeOf() + expectTypeOf(error).toEqualTypeOf() + expectTypeOf(context).toEqualTypeOf() + }, + onSuccess(data, variables, context) { + expectTypeOf(variables).toEqualTypeOf() + expectTypeOf(data).toEqualTypeOf() + expectTypeOf(context).toEqualTypeOf() + }, + onSettled(data, error, variables, context) { + expectTypeOf(data).toEqualTypeOf() + expectTypeOf( + error, + ).toEqualTypeOf() + expectTypeOf(variables).toEqualTypeOf() + expectTypeOf(context).toEqualTypeOf() + }, + }, + }) + + expectTypeOf(data).toEqualTypeOf() + expectTypeOf(error).toEqualTypeOf() + expectTypeOf(variables).toEqualTypeOf< + RequestPermissionsVariables | undefined + >() + expectTypeOf(context).toEqualTypeOf() + + requestPermissions( + { eth_accounts: {} }, + { + onError(error, variables, context) { + expectTypeOf(variables).toEqualTypeOf() + expectTypeOf(error).toEqualTypeOf() + expectTypeOf(context).toEqualTypeOf() + }, + onSuccess(data, variables, context) { + expectTypeOf(variables).toEqualTypeOf() + expectTypeOf(data).toEqualTypeOf() + expectTypeOf(context).toEqualTypeOf() + }, + onSettled(data, error, variables, context) { + expectTypeOf(data).toEqualTypeOf() + expectTypeOf(error).toEqualTypeOf() + expectTypeOf(variables).toEqualTypeOf() + expectTypeOf(context).toEqualTypeOf() + }, + }, + ) +}) diff --git a/packages/react/src/hooks/useRequestPermissions.test.ts b/packages/react/src/hooks/useRequestPermissions.test.ts new file mode 100644 index 0000000000..c20a749aa1 --- /dev/null +++ b/packages/react/src/hooks/useRequestPermissions.test.ts @@ -0,0 +1,36 @@ +import { connect, disconnect } from '@wagmi/core' +import { config } from '@wagmi/test' +import { renderHook, waitFor } from '@wagmi/test/react' +import { expect, test } from 'vitest' + +import { useRequestPermissions } from './useRequestPermissions.js' + +const connector = config.connectors[0]! + +test('default', async () => { + await connect(config, { connector }) + + const { result } = renderHook(() => useRequestPermissions()) + + result.current.requestPermissions({ eth_accounts: {} }) + await waitFor(() => expect(result.current.isSuccess).toBeTruthy()) + + expect(result.current.data).toMatchInlineSnapshot(` + [ + { + "caveats": [ + { + "type": "filterResponse", + "value": [ + "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", + ], + }, + ], + "invoker": "https://example.com", + "parentCapability": "eth_accounts", + }, + ] + `) + + await disconnect(config, { connector }) +}) diff --git a/packages/react/src/hooks/useRequestPermissions.ts b/packages/react/src/hooks/useRequestPermissions.ts new file mode 100644 index 0000000000..155da7abc6 --- /dev/null +++ b/packages/react/src/hooks/useRequestPermissions.ts @@ -0,0 +1,65 @@ +'use client' + +import { useMutation } from '@tanstack/react-query' +import type { RequestPermissionsErrorType } from '@wagmi/core' +import type { Compute } from '@wagmi/core/internal' +import { + type RequestPermissionsData, + type RequestPermissionsMutate, + type RequestPermissionsMutateAsync, + type RequestPermissionsVariables, + requestPermissionsMutationOptions, +} from '@wagmi/core/query' + +import type { ConfigParameter } from '../types/properties.js' +import type { + UseMutationParameters, + UseMutationReturnType, +} from '../utils/query.js' +import { useConfig } from './useConfig.js' + +export type UseRequestPermissionsParameters = Compute< + ConfigParameter & { + mutation?: + | UseMutationParameters< + RequestPermissionsData, + RequestPermissionsErrorType, + RequestPermissionsVariables, + context + > + | undefined + } +> + +export type UseRequestPermissionsReturnType = Compute< + UseMutationReturnType< + RequestPermissionsData, + RequestPermissionsErrorType, + RequestPermissionsVariables, + context + > & { + requestPermissions: RequestPermissionsMutate + requestPermissionsAsync: RequestPermissionsMutateAsync + } +> + +/** https://wagmi.sh/react/api/hooks/useRequestPermissions */ +export function useRequestPermissions( + parameters: UseRequestPermissionsParameters = {}, +): UseRequestPermissionsReturnType { + const { mutation } = parameters + + const config = useConfig(parameters) + + const mutationOptions = requestPermissionsMutationOptions(config) + const { mutate, mutateAsync, ...result } = useMutation({ + ...mutation, + ...mutationOptions, + }) + + return { + ...result, + requestPermissions: mutate, + requestPermissionsAsync: mutateAsync, + } +} diff --git a/packages/vue/src/exports/actions.test.ts b/packages/vue/src/exports/actions.test.ts index 77f805d96c..79162348ef 100644 --- a/packages/vue/src/exports/actions.test.ts +++ b/packages/vue/src/exports/actions.test.ts @@ -53,6 +53,7 @@ test('exports', () => { "readContract", "readContracts", "reconnect", + "requestPermissions", "sendTransaction", "signMessage", "signTypedData", diff --git a/packages/vue/src/exports/query.test.ts b/packages/vue/src/exports/query.test.ts index d2b3386c33..d99e9296c3 100644 --- a/packages/vue/src/exports/query.test.ts +++ b/packages/vue/src/exports/query.test.ts @@ -67,6 +67,7 @@ test('exports', () => { "readContractsQueryKey", "readContractsQueryOptions", "reconnectMutationOptions", + "requestPermissionsMutationOptions", "sendTransactionMutationOptions", "signMessageMutationOptions", "signTypedDataMutationOptions", diff --git a/site/.vitepress/sidebar.ts b/site/.vitepress/sidebar.ts index e08ff57314..decbd1faea 100644 --- a/site/.vitepress/sidebar.ts +++ b/site/.vitepress/sidebar.ts @@ -239,6 +239,7 @@ export function getSidebar() { link: '/react/api/hooks/useReadContracts', }, { text: 'useReconnect', link: '/react/api/hooks/useReconnect' }, + { text: 'useRequestPermissions', link: '/react/api/hooks/useRequestPermissions' }, { text: 'useSendTransaction', link: '/react/api/hooks/useSendTransaction', @@ -868,6 +869,7 @@ export function getSidebar() { text: 'readContracts', link: '/core/api/actions/readContracts', }, + { text: 'requestPermissions', link: '/core/api/actions/requestPermissions' }, { text: 'sendTransaction', link: '/core/api/actions/sendTransaction', diff --git a/site/core/api/actions/requestPermissions.md b/site/core/api/actions/requestPermissions.md new file mode 100644 index 0000000000..425bba943d --- /dev/null +++ b/site/core/api/actions/requestPermissions.md @@ -0,0 +1,78 @@ + + +# requestPermissions + +Action for requesting permissions for a wallet. + +## Import + +```ts +import { requestPermissions } from '@wagmi/core' +``` + +## Usage + +::: code-group +```ts [index.ts] +import { requestPermissions } from '@wagmi/core' +import { config } from './config' + +const permissions = await requestPermissions(config, { + eth_accounts: {} +}) +``` +<<< @/snippets/core/config.ts[config.ts] +::: + +## Parameters + +```ts +import { type RequestPermissionsParameters } from '@wagmi/core' +``` + +### connector + +`Connector | undefined` + +[Connector](/core/api/connectors) to request permissions from. + +::: code-group +```ts [index.ts] +import { getAccount, requestPermissions } from '@wagmi/core' +import { config } from './config' + +const { connector } = getAccount(config) +const permissions = await requestPermissions(config, { + connector, // [!code focus] + eth_accounts: {} +}) +``` +<<< @/snippets/core/config.ts[config.ts] +::: + +## Return Type + +```ts +import { type RequestPermissionsReturnType } from '@wagmi/core' +``` + +[`WalletPermission[]`](https://viem.sh/docs/glossary/types#walletpermission) + +The wallet permissions. + +## Error + +```ts +import { type RequestPermissionsErrorType } from '@wagmi/core' +``` + + + +## Viem + +- [`requestPermissions`](https://viem.sh/docs/actions/wallet/requestPermissions.html) + diff --git a/site/react/api/hooks/useRequestPermissions.md b/site/react/api/hooks/useRequestPermissions.md new file mode 100644 index 0000000000..71927e5f9d --- /dev/null +++ b/site/react/api/hooks/useRequestPermissions.md @@ -0,0 +1,89 @@ +--- +title: useRequestPermissions +description: Hook for requesting permissions for a wallet. +--- + + + +# useRequestPermissions + +Hook for requesting permissions for a wallet. + +## Import + +```ts +import { useRequestPermissions } from 'wagmi' +``` + +## Usage + +::: code-group +```tsx [index.tsx] +import { useRequestPermissions } from 'wagmi' + +function App() { + const { requestPermissions } = useRequestPermissions() + + return ( + + ) +} +``` +<<< @/snippets/react/config.ts[config.ts] +::: + +## Parameters + +```ts +import { type UseRequestPermissionsParameters } from 'wagmi' +``` + +### config + +`Config | undefined` + +[`Config`](/react/api/createConfig#config) to use instead of retrieving from the from nearest [`WagmiProvider`](/react/api/WagmiProvider). + +::: code-group +```tsx [index.tsx] +import { useRequestPermissions } from 'wagmi' +import { config } from './config' // [!code focus] + +function App() { + const result = useRequestPermissions({ + config, // [!code focus] + }) +} +``` +<<< @/snippets/react/config.ts[config.ts] +::: + + + +## Return Type + +```ts +import { type UseRequestPermissionsReturnType } from 'wagmi' +``` + + + + + +## Action + +- [`requestPermissions`](/core/api/actions/requestPermissions) From 2e5d15116574727b4f0a71ff17895f50d818d939 Mon Sep 17 00:00:00 2001 From: Vitor Date: Mon, 14 Oct 2024 15:42:03 -0300 Subject: [PATCH 2/9] chore: changeset --- .changeset/four-pants-notice.md | 5 +++++ .changeset/seven-terms-guess.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/four-pants-notice.md create mode 100644 .changeset/seven-terms-guess.md diff --git a/.changeset/four-pants-notice.md b/.changeset/four-pants-notice.md new file mode 100644 index 0000000000..f3f51bf6a9 --- /dev/null +++ b/.changeset/four-pants-notice.md @@ -0,0 +1,5 @@ +--- +"wagmi": minor +--- + +Added `useRequestPermissions` hook. diff --git a/.changeset/seven-terms-guess.md b/.changeset/seven-terms-guess.md new file mode 100644 index 0000000000..44a4436c3c --- /dev/null +++ b/.changeset/seven-terms-guess.md @@ -0,0 +1,5 @@ +--- +"@wagmi/core": minor +--- + +Added `requestPermissions` action. From 05550b1142588ca2d044e33b814332277d32ac43 Mon Sep 17 00:00:00 2001 From: Vitor Date: Mon, 14 Oct 2024 15:42:21 -0300 Subject: [PATCH 3/9] chore: sidebar --- .../react/src/hooks/useRequestPermissions.test-d.ts | 2 +- site/.vitepress/sidebar.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/react/src/hooks/useRequestPermissions.test-d.ts b/packages/react/src/hooks/useRequestPermissions.test-d.ts index 638e6f7b27..51cb1eecdd 100644 --- a/packages/react/src/hooks/useRequestPermissions.test-d.ts +++ b/packages/react/src/hooks/useRequestPermissions.test-d.ts @@ -2,8 +2,8 @@ import type { RequestPermissionsErrorType } from '@wagmi/core' import type { RequestPermissionsVariables } from '@wagmi/core/query' import { expectTypeOf, test } from 'vitest' -import { useRequestPermissions } from './useRequestPermissions.js' import type { WalletPermission } from 'viem' +import { useRequestPermissions } from './useRequestPermissions.js' const contextValue = { foo: 'bar' } as const diff --git a/site/.vitepress/sidebar.ts b/site/.vitepress/sidebar.ts index decbd1faea..1c56e20fce 100644 --- a/site/.vitepress/sidebar.ts +++ b/site/.vitepress/sidebar.ts @@ -239,7 +239,10 @@ export function getSidebar() { link: '/react/api/hooks/useReadContracts', }, { text: 'useReconnect', link: '/react/api/hooks/useReconnect' }, - { text: 'useRequestPermissions', link: '/react/api/hooks/useRequestPermissions' }, + { + text: 'useRequestPermissions', + link: '/react/api/hooks/useRequestPermissions', + }, { text: 'useSendTransaction', link: '/react/api/hooks/useSendTransaction', @@ -869,7 +872,10 @@ export function getSidebar() { text: 'readContracts', link: '/core/api/actions/readContracts', }, - { text: 'requestPermissions', link: '/core/api/actions/requestPermissions' }, + { + text: 'requestPermissions', + link: '/core/api/actions/requestPermissions', + }, { text: 'sendTransaction', link: '/core/api/actions/sendTransaction', From 10192ce4a03f75f5469d5aa875a558f6ae7f3b30 Mon Sep 17 00:00:00 2001 From: Vitor Date: Fri, 23 Jan 2026 22:31:32 -0300 Subject: [PATCH 4/9] refactor: request permissions --- .../core/src/actions/requestPermissions.ts | 6 +- packages/core/src/exports/query.ts | 2 + packages/core/src/query/requestPermissions.ts | 74 +++++++++++++------ .../src/hooks/useRequestPermissions.test.ts | 10 +-- .../react/src/hooks/useRequestPermissions.ts | 61 +++++++-------- 5 files changed, 88 insertions(+), 65 deletions(-) diff --git a/packages/core/src/actions/requestPermissions.ts b/packages/core/src/actions/requestPermissions.ts index fb2a446cfe..8bc498a6e5 100644 --- a/packages/core/src/actions/requestPermissions.ts +++ b/packages/core/src/actions/requestPermissions.ts @@ -4,7 +4,6 @@ import { type RequestPermissionsReturnType as viem_RequestPermissionsReturnType, requestPermissions as viem_requestPermissions, } from 'viem/actions' - import type { Config } from '../createConfig.js' import type { BaseErrorType, ErrorType } from '../errors/base.js' import type { ConnectorParameter } from '../types/properties.js' @@ -31,12 +30,11 @@ export type RequestPermissionsErrorType = | viem_RequestPermissionsErrorType /** https://wagmi.sh/core/api/actions/requestPermissions */ -export async function requestPermissions( - config: Config, +export async function requestPermissions( + config: config, parameters: RequestPermissionsParameters, ): Promise { const { connector, ...rest } = parameters - const client = await getConnectorClient(config, { connector }) const action = getAction( diff --git a/packages/core/src/exports/query.ts b/packages/core/src/exports/query.ts index 02258fc730..22322dfb44 100644 --- a/packages/core/src/exports/query.ts +++ b/packages/core/src/exports/query.ts @@ -366,6 +366,8 @@ export { type RequestPermissionsData, type RequestPermissionsMutate, type RequestPermissionsMutateAsync, + type RequestPermissionsMutationOptions, + type RequestPermissionsOptions, type RequestPermissionsVariables, requestPermissionsMutationOptions, } from '../query/requestPermissions.js' diff --git a/packages/core/src/query/requestPermissions.ts b/packages/core/src/query/requestPermissions.ts index 89adfa53fc..3806fbf3d7 100644 --- a/packages/core/src/query/requestPermissions.ts +++ b/packages/core/src/query/requestPermissions.ts @@ -1,5 +1,4 @@ -import type { MutationOptions } from '@tanstack/query-core' - +import type { MutateOptions, MutationOptions } from '@tanstack/query-core' import { type RequestPermissionsErrorType, type RequestPermissionsParameters, @@ -7,35 +6,66 @@ import { requestPermissions, } from '../actions/requestPermissions.js' import type { Config } from '../createConfig.js' -import type { Mutate, MutateAsync } from './types.js' +import type { MutationParameter } from '../types/query.js' +import type { Compute } from '../types/utils.js' -export function requestPermissionsMutationOptions(config: Config) { +export type RequestPermissionsOptions = MutationParameter< + RequestPermissionsData, + RequestPermissionsErrorType, + RequestPermissionsVariables, + context +> + +export function requestPermissionsMutationOptions< + config extends Config, + context, +>( + config: config, + options: RequestPermissionsOptions = {}, +): RequestPermissionsMutationOptions { return { + ...(options.mutation as any), mutationFn(variables) { return requestPermissions(config, variables) }, mutationKey: ['requestPermissions'], - } as const satisfies MutationOptions< - RequestPermissionsData, - RequestPermissionsErrorType, - RequestPermissionsVariables - > + } } -export type RequestPermissionsData = RequestPermissionsReturnType - -export type RequestPermissionsVariables = RequestPermissionsParameters - -export type RequestPermissionsMutate = Mutate< +export type RequestPermissionsMutationOptions = MutationOptions< RequestPermissionsData, RequestPermissionsErrorType, - RequestPermissionsVariables, - context + RequestPermissionsVariables > -export type RequestPermissionsMutateAsync = MutateAsync< - RequestPermissionsData, - RequestPermissionsErrorType, - RequestPermissionsVariables, - context -> +export type RequestPermissionsData = Compute + +export type RequestPermissionsVariables = RequestPermissionsParameters + +export type RequestPermissionsMutate = ( + variables: RequestPermissionsVariables, + options?: + | Compute< + MutateOptions< + RequestPermissionsData, + RequestPermissionsErrorType, + Compute, + context + > + > + | undefined, +) => void + +export type RequestPermissionsMutateAsync = ( + variables: RequestPermissionsVariables, + options?: + | Compute< + MutateOptions< + RequestPermissionsData, + RequestPermissionsErrorType, + Compute, + context + > + > + | undefined, +) => Promise diff --git a/packages/react/src/hooks/useRequestPermissions.test.ts b/packages/react/src/hooks/useRequestPermissions.test.ts index c20a749aa1..003115ef01 100644 --- a/packages/react/src/hooks/useRequestPermissions.test.ts +++ b/packages/react/src/hooks/useRequestPermissions.test.ts @@ -1,7 +1,7 @@ import { connect, disconnect } from '@wagmi/core' import { config } from '@wagmi/test' -import { renderHook, waitFor } from '@wagmi/test/react' -import { expect, test } from 'vitest' +import { renderHook } from '@wagmi/test/react' +import { expect, test, vi } from 'vitest' import { useRequestPermissions } from './useRequestPermissions.js' @@ -10,10 +10,10 @@ const connector = config.connectors[0]! test('default', async () => { await connect(config, { connector }) - const { result } = renderHook(() => useRequestPermissions()) + const { result } = await renderHook(() => useRequestPermissions()) - result.current.requestPermissions({ eth_accounts: {} }) - await waitFor(() => expect(result.current.isSuccess).toBeTruthy()) + result.current.mutate({ eth_accounts: {} }) + await vi.waitUntil(() => result.current.isSuccess, { timeout: 5_000 }) expect(result.current.data).toMatchInlineSnapshot(` [ diff --git a/packages/react/src/hooks/useRequestPermissions.ts b/packages/react/src/hooks/useRequestPermissions.ts index 155da7abc6..9bc89cda39 100644 --- a/packages/react/src/hooks/useRequestPermissions.ts +++ b/packages/react/src/hooks/useRequestPermissions.ts @@ -1,65 +1,58 @@ 'use client' - import { useMutation } from '@tanstack/react-query' -import type { RequestPermissionsErrorType } from '@wagmi/core' +import type { + Config, + RequestPermissionsErrorType, + ResolvedRegister, +} from '@wagmi/core' import type { Compute } from '@wagmi/core/internal' import { type RequestPermissionsData, type RequestPermissionsMutate, type RequestPermissionsMutateAsync, + type RequestPermissionsOptions, type RequestPermissionsVariables, requestPermissionsMutationOptions, } from '@wagmi/core/query' - import type { ConfigParameter } from '../types/properties.js' -import type { - UseMutationParameters, - UseMutationReturnType, -} from '../utils/query.js' +import type { UseMutationReturnType } from '../utils/query.js' import { useConfig } from './useConfig.js' -export type UseRequestPermissionsParameters = Compute< - ConfigParameter & { - mutation?: - | UseMutationParameters< - RequestPermissionsData, - RequestPermissionsErrorType, - RequestPermissionsVariables, - context - > - | undefined - } -> +export type UseRequestPermissionsParameters< + config extends Config = Config, + context = unknown, +> = Compute & RequestPermissionsOptions> export type UseRequestPermissionsReturnType = Compute< UseMutationReturnType< RequestPermissionsData, RequestPermissionsErrorType, RequestPermissionsVariables, - context + context, + RequestPermissionsMutate, + RequestPermissionsMutateAsync > & { + /** @deprecated use `mutate` instead */ requestPermissions: RequestPermissionsMutate + /** @deprecated use `mutateAsync` instead */ requestPermissionsAsync: RequestPermissionsMutateAsync } > /** https://wagmi.sh/react/api/hooks/useRequestPermissions */ -export function useRequestPermissions( - parameters: UseRequestPermissionsParameters = {}, +export function useRequestPermissions< + config extends Config = ResolvedRegister['config'], + context = unknown, +>( + parameters: UseRequestPermissionsParameters = {}, ): UseRequestPermissionsReturnType { - const { mutation } = parameters - const config = useConfig(parameters) - - const mutationOptions = requestPermissionsMutationOptions(config) - const { mutate, mutateAsync, ...result } = useMutation({ - ...mutation, - ...mutationOptions, - }) - + const options = requestPermissionsMutationOptions(config, parameters) + const mutation = useMutation(options) + type Return = UseRequestPermissionsReturnType return { - ...result, - requestPermissions: mutate, - requestPermissionsAsync: mutateAsync, + ...(mutation as Return), + requestPermissions: mutation.mutate as Return['mutate'], + requestPermissionsAsync: mutation.mutateAsync as Return['mutateAsync'], } } From 214c3c04369dddefd6e3c8ae3a59e2eab485f90d Mon Sep 17 00:00:00 2001 From: Vitor Date: Sat, 24 Jan 2026 13:32:30 -0300 Subject: [PATCH 5/9] fix: solid export tests --- packages/solid/src/exports/actions.test.ts | 1 + packages/solid/src/exports/query.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/solid/src/exports/actions.test.ts b/packages/solid/src/exports/actions.test.ts index 48d1bf21b7..14bd590c19 100644 --- a/packages/solid/src/exports/actions.test.ts +++ b/packages/solid/src/exports/actions.test.ts @@ -49,6 +49,7 @@ test('exports', () => { "readContract", "readContracts", "reconnect", + "requestPermissions", "sendCalls", "sendTransaction", "showCallsStatus", diff --git a/packages/solid/src/exports/query.test.ts b/packages/solid/src/exports/query.test.ts index bff9e09292..e10c3b6857 100644 --- a/packages/solid/src/exports/query.test.ts +++ b/packages/solid/src/exports/query.test.ts @@ -74,6 +74,7 @@ test('exports', () => { "readContractsQueryKey", "readContractsQueryOptions", "reconnectMutationOptions", + "requestPermissionsMutationOptions", "sendCallsMutationOptions", "sendCallsSyncMutationOptions", "sendTransactionMutationOptions", From b66f931031b599619623985773906c85af270d2b Mon Sep 17 00:00:00 2001 From: tmm Date: Tue, 11 Aug 2026 11:04:58 -0400 Subject: [PATCH 6/9] fix: align request permissions with current conventions --- packages/core/src/connectors/mock.test.ts | 13 +++++++++++++ packages/react/src/hooks/useRequestPermissions.ts | 3 +-- site/core/api/actions/requestPermissions.md | 13 ++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/core/src/connectors/mock.test.ts b/packages/core/src/connectors/mock.test.ts index 90e9d6f8b9..45386156e3 100644 --- a/packages/core/src/connectors/mock.test.ts +++ b/packages/core/src/connectors/mock.test.ts @@ -72,6 +72,7 @@ test('behavior: connector.getProvider request errors', async () => { const connectorFn = mock({ accounts, features: { + requestPermissionsError: true, signMessageError: true, signTypedDataError: true, switchChainError: true, @@ -83,6 +84,18 @@ test('behavior: connector.getProvider request errors', async () => { ) as ReturnType const provider = await connector.getProvider() + await expect( + provider.request({ + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + }), + ).rejects.toThrowErrorMatchingInlineSnapshot(` + [UserRejectedRequestError: User rejected the request. + + Details: Failed to request permissions. + Version: viem@2.55.7] + `) + await expect( provider.request({ method: 'eth_signTypedData_v4', diff --git a/packages/react/src/hooks/useRequestPermissions.ts b/packages/react/src/hooks/useRequestPermissions.ts index 9bc89cda39..3afdf475c6 100644 --- a/packages/react/src/hooks/useRequestPermissions.ts +++ b/packages/react/src/hooks/useRequestPermissions.ts @@ -5,7 +5,7 @@ import type { RequestPermissionsErrorType, ResolvedRegister, } from '@wagmi/core' -import type { Compute } from '@wagmi/core/internal' +import type { Compute, ConfigParameter } from '@wagmi/core/internal' import { type RequestPermissionsData, type RequestPermissionsMutate, @@ -14,7 +14,6 @@ import { type RequestPermissionsVariables, requestPermissionsMutationOptions, } from '@wagmi/core/query' -import type { ConfigParameter } from '../types/properties.js' import type { UseMutationReturnType } from '../utils/query.js' import { useConfig } from './useConfig.js' diff --git a/site/core/api/actions/requestPermissions.md b/site/core/api/actions/requestPermissions.md index 425bba943d..f74f88d873 100644 --- a/site/core/api/actions/requestPermissions.md +++ b/site/core/api/actions/requestPermissions.md @@ -34,6 +34,18 @@ const permissions = await requestPermissions(config, { import { type RequestPermissionsParameters } from '@wagmi/core' ``` +### eth_accounts + +`Record` + +Account permissions to request from the wallet. + +```ts +const permissions = await requestPermissions(config, { + eth_accounts: {}, // [!code focus] +}) +``` + ### connector `Connector | undefined` @@ -75,4 +87,3 @@ import { type RequestPermissionsErrorType } from '@wagmi/core' ## Viem - [`requestPermissions`](https://viem.sh/docs/actions/wallet/requestPermissions.html) - From 23ea4e23281b6fdd5ce4a8c8f76cc2ab0d5d09b8 Mon Sep 17 00:00:00 2001 From: tmm Date: Tue, 11 Aug 2026 11:06:22 -0400 Subject: [PATCH 7/9] docs: polish request permissions examples --- site/core/api/actions/requestPermissions.md | 6 +++--- site/react/api/hooks/useRequestPermissions.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/core/api/actions/requestPermissions.md b/site/core/api/actions/requestPermissions.md index f74f88d873..b15e800b1f 100644 --- a/site/core/api/actions/requestPermissions.md +++ b/site/core/api/actions/requestPermissions.md @@ -21,8 +21,8 @@ import { requestPermissions } from '@wagmi/core' import { requestPermissions } from '@wagmi/core' import { config } from './config' -const permissions = await requestPermissions(config, { - eth_accounts: {} +const permissions = await requestPermissions(config, { + eth_accounts: {}, }) ``` <<< @/snippets/core/config.ts[config.ts] @@ -60,7 +60,7 @@ import { config } from './config' const { connector } = getAccount(config) const permissions = await requestPermissions(config, { connector, // [!code focus] - eth_accounts: {} + eth_accounts: {}, }) ``` <<< @/snippets/core/config.ts[config.ts] diff --git a/site/react/api/hooks/useRequestPermissions.md b/site/react/api/hooks/useRequestPermissions.md index 71927e5f9d..b37c39e34f 100644 --- a/site/react/api/hooks/useRequestPermissions.md +++ b/site/react/api/hooks/useRequestPermissions.md @@ -35,7 +35,7 @@ function App() { return (