diff --git a/packages/svelte/src/lib/hooks/useSignMessage.svelte.test.ts b/packages/svelte/src/lib/hooks/useSignMessage.svelte.test.ts new file mode 100644 index 0000000000..a3ba95f6bb --- /dev/null +++ b/packages/svelte/src/lib/hooks/useSignMessage.svelte.test.ts @@ -0,0 +1,50 @@ +import { connect, disconnect, getAccount } from '@wagmi/core' +import { config, privateKey } from '@wagmi/test' +import { recoverMessageAddress } from 'viem' +import { expect, test, vi } from 'vitest' + +import { privateKeyToAccount } from 'viem/accounts' +import { testHook } from './test.svelte.js' +import { useSignMessage } from './useSignMessage.svelte' + +const connector = config.connectors[0]! + +test( + 'default', + testHook(async () => { + await connect(config, { connector }) + + const signMessage = $derived.by(useSignMessage()) + + signMessage.signMessage({ message: 'foo bar baz' }) + await expect.poll(() => signMessage.isSuccess).toBeTruthy() + + await expect( + recoverMessageAddress({ + message: 'foo bar baz', + signature: signMessage.data!, + }), + ).resolves.toEqual(getAccount(config).address) + + await disconnect(config, { connector }) + }), +) + +test( + 'behavior: local account', + testHook(async () => { + const signMessage = $derived.by(useSignMessage()) + + const account = privateKeyToAccount(privateKey) + signMessage.signMessage({ account, message: 'foo bar baz' }) + + await expect.poll(() => signMessage.isSuccess).toBeTruthy() + + await expect( + recoverMessageAddress({ + message: 'foo bar baz', + signature: signMessage.data!, + }), + ).resolves.toEqual(account.address) + }), +) diff --git a/packages/svelte/src/lib/hooks/useSignMessage.svelte.ts b/packages/svelte/src/lib/hooks/useSignMessage.svelte.ts new file mode 100644 index 0000000000..01bfa29a0e --- /dev/null +++ b/packages/svelte/src/lib/hooks/useSignMessage.svelte.ts @@ -0,0 +1,69 @@ +import { createMutation } from '@tanstack/svelte-query' +import type { SignMessageErrorType } from '@wagmi/core' +import type { Compute } from '@wagmi/core/internal' +import { + type SignMessageData, + type SignMessageMutate, + type SignMessageMutateAsync, + type SignMessageVariables, + signMessageMutationOptions, +} from '@wagmi/core/query' + +import type { + CreateMutationParameters, + CreateMutationReturnType, +} from '$lib/query.svelte.js' +import type { RuneParameters, RuneReturnType } from '$lib/types.js' +import type { ConfigParameter } from '../types.js' +import { useConfig } from './useConfig.svelte.js' + +export type UseSignMessageParameters = RuneParameters< + Compute< + ConfigParameter & { + mutation?: + | CreateMutationParameters< + SignMessageData, + SignMessageErrorType, + SignMessageVariables, + context + > + | undefined + } + > +> + +export type UseSignMessageReturnType = RuneReturnType< + Compute< + CreateMutationReturnType< + SignMessageData, + SignMessageErrorType, + SignMessageVariables, + context + > & { + signMessage: SignMessageMutate + signMessageAsync: SignMessageMutateAsync + } + > +> + +/** https://wagmi.sh/react/api/hooks/useSignMessage */ +export function useSignMessage( + parameters: UseSignMessageParameters = () => ({}), +): UseSignMessageReturnType { + const { mutation } = $derived.by(parameters) + + const config = $derived.by(useConfig(parameters)) + + const mutationOptions = $derived(signMessageMutationOptions(config)) + const query = createMutation(() => ({ + ...mutation, + ...mutationOptions, + })) + const { mutate, mutateAsync, ...result } = $derived(query) + + return () => ({ + ...result, + signMessage: mutate, + signMessageAsync: mutateAsync, + }) +}