diff --git a/site/pages/experimental/solady/signMessage.md b/site/pages/experimental/solady/signMessage.md new file mode 100644 index 00000000000..9e598bd153e --- /dev/null +++ b/site/pages/experimental/solady/signMessage.md @@ -0,0 +1,14 @@ +--- +description: Signs a personal sign message via Solady's ERC-1271 format. +--- + +# signMessage + +Signs a [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal sign message via Solady's [ERC1271 `PersonalSign` format](https://github.com/Vectorized/solady/blob/678c9163550810b08f0ffb09624c9f7532392303/src/accounts/ERC1271.sol#L154-L166). + +This Action is suitable to sign messages for Smart Accounts that implement (or conform to) Solady's [ERC1271.sol](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC1271.sol). + +With the calculated signature, you can use [`verifyMessage`](https://viem.sh/docs/utilities/verifyMessage) to verify the signature + +## Usage + diff --git a/src/experimental/index.ts b/src/experimental/index.ts index 30c5e2ea4cf..d3ce7dd5585 100644 --- a/src/experimental/index.ts +++ b/src/experimental/index.ts @@ -76,3 +76,8 @@ export { type SignTypedDataReturnType, signTypedData, } from './solady/actions/signTypedData.js' +export { + type SoladyActions, + type SoladyActionsParameters, + soladyActions, +} from './solady/decorators/solady.js' diff --git a/src/experimental/solady/actions/signMessage.test.ts b/src/experimental/solady/actions/signMessage.test.ts index 2fbeeb96bb6..764269e0a10 100644 --- a/src/experimental/solady/actions/signMessage.test.ts +++ b/src/experimental/solady/actions/signMessage.test.ts @@ -16,9 +16,6 @@ import { import { encodeFunctionData, pad } from '../../../utils/index.js' import { signMessage } from './signMessage.js' -const client = anvilMainnet.getClient() -const clientWithAccount = anvilMainnet.getClient({ account: true }) - let verifier: Address beforeAll(async () => { const { factoryAddress } = await deployMock4337Account() @@ -34,6 +31,8 @@ beforeAll(async () => { await mine(client, { blocks: 1 }) }) +const client = anvilMainnet.getClient() + test('default', async () => { const message = 'hello world' const signature = await signMessage(client!, { @@ -108,6 +107,10 @@ test('raw message (bytes)', async () => { }) test('inferred account', async () => { + const clientWithAccount = anvilMainnet.getClient({ + account: accounts[0].address, + }) + const message = 'hello world' const signature = await signMessage(clientWithAccount!, { message, @@ -139,7 +142,8 @@ test('counterfactual smart account', async () => { }) const message = 'hello world' - const signature = await signMessage(clientWithAccount!, { + const signature = await signMessage(client, { + account: accounts[0].address, message, factory: factoryAddress, factoryData, diff --git a/src/experimental/solady/actions/signMessage.ts b/src/experimental/solady/actions/signMessage.ts index 44614d67bf7..5db45118ff8 100644 --- a/src/experimental/solady/actions/signMessage.ts +++ b/src/experimental/solady/actions/signMessage.ts @@ -16,11 +16,14 @@ import type { Hex, SignableMessage } from '../../../types/misc.js' import type { OneOf, RequiredBy } from '../../../types/utils.js' import { getAction } from '../../../utils/getAction.js' import { toPrefixedMessage } from '../../../utils/signature/toPrefixedMessage.js' +import type { GetVerifierParameter } from '../types.js' export type SignMessageParameters< account extends Account | undefined = Account | undefined, -> = GetAccountParameter & - Pick & { + accountOverride extends Account | undefined = Account | undefined, + verifier extends Address | undefined = Address | undefined, +> = Pick & + GetAccountParameter & { message: SignableMessage } & OneOf< | { @@ -28,16 +31,16 @@ export type SignMessageParameters< TypedDataDomain, 'chainId' | 'name' | 'verifyingContract' | 'version' > + verifier?: undefined } - | { + | (GetVerifierParameter & { accountDomain?: | RequiredBy< TypedDataDomain, 'chainId' | 'name' | 'verifyingContract' | 'version' > | undefined - verifier: Address - } + }) > export type SignMessageReturnType = Hex @@ -67,10 +70,11 @@ export type SignMessageErrorType = ErrorType * chain: mainnet, * transport: custom(window.ethereum), * }) + * * const signature = await signMessage(client, { - * account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', * message: 'hello world', - * verifier: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', * }) * * @example @@ -81,21 +85,23 @@ export type SignMessageErrorType = ErrorType * import { signMessage } from 'viem/experimental/solady' * * const client = createWalletClient({ - * account: privateKeyToAccount('0x…'), + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', * chain: mainnet, * transport: custom(window.ethereum), * }) + * * const signature = await signMessage(client, { * message: 'hello world', - * verifier: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', * }) */ export async function signMessage< chain extends Chain | undefined, account extends Account | undefined, + accountOverride extends Account | undefined = undefined, >( client: Client, - parameters: SignMessageParameters, + parameters: SignMessageParameters, ): Promise { const { account: account_ = client.account, diff --git a/src/experimental/solady/actions/signTypedData.test.ts b/src/experimental/solady/actions/signTypedData.test.ts index cbf9ff5e610..395e191fff6 100644 --- a/src/experimental/solady/actions/signTypedData.test.ts +++ b/src/experimental/solady/actions/signTypedData.test.ts @@ -17,7 +17,6 @@ import { encodeFunctionData, pad } from '../../../utils/index.js' import { signTypedData } from './signTypedData.js' const client = anvilMainnet.getClient() -const clientWithAccount = anvilMainnet.getClient({ account: true }) let verifier: Address beforeAll(async () => { @@ -71,6 +70,8 @@ describe('default', () => { }) test('inferred account', async () => { + const clientWithAccount = anvilMainnet.getClient({ account: true }) + const signature = await signTypedData(clientWithAccount, { ...typedData.complex, primaryType: 'Mail', @@ -142,8 +143,8 @@ describe('args: domain empty', () => { test('json-rpc account', async () => { const signature = await signTypedData(client, { ...typedData.complex, - domain: undefined, account: accounts[0].address, + domain: undefined, primaryType: 'Mail', verifier, }) @@ -182,10 +183,10 @@ describe('args: domain chainId', () => { test('json-rpc account', async () => { const signature = await signTypedData(client, { ...typedData.complex, + account: accounts[0].address, domain: { chainId: 1, }, - account: accounts[0].address, primaryType: 'Mail', verifier, }) @@ -205,10 +206,10 @@ describe('args: domain chainId', () => { test('local account', async () => { const signature = await signTypedData(client, { ...typedData.complex, + account: privateKeyToAccount(accounts[0].privateKey), domain: { chainId: 1, }, - account: privateKeyToAccount(accounts[0].privateKey), primaryType: 'Mail', verifier, }) @@ -230,10 +231,10 @@ describe('args: domain name', () => { test('json-rpc account', async () => { const signature = await signTypedData(client, { ...typedData.complex, + account: accounts[0].address, domain: { name: 'lol', }, - account: accounts[0].address, primaryType: 'Mail', verifier, }) @@ -253,10 +254,10 @@ describe('args: domain name', () => { test('local account', async () => { const signature = await signTypedData(client, { ...typedData.complex, + account: privateKeyToAccount(accounts[0].privateKey), domain: { name: 'lol', }, - account: privateKeyToAccount(accounts[0].privateKey), primaryType: 'Mail', verifier, }) @@ -278,10 +279,10 @@ describe('args: domain verifyingContract', () => { test('json-rpc account', async () => { const signature = await signTypedData(client, { ...typedData.complex, + account: accounts[0].address, domain: { verifyingContract: '0x0000000000000000000000000000000000000000', }, - account: accounts[0].address, primaryType: 'Mail', verifier, }) @@ -301,10 +302,10 @@ describe('args: domain verifyingContract', () => { test('local account', async () => { const signature = await signTypedData(client, { ...typedData.complex, + account: privateKeyToAccount(accounts[0].privateKey), domain: { verifyingContract: '0x0000000000000000000000000000000000000000', }, - account: privateKeyToAccount(accounts[0].privateKey), primaryType: 'Mail', verifier, }) diff --git a/src/experimental/solady/actions/signTypedData.ts b/src/experimental/solady/actions/signTypedData.ts index 1d655f5adeb..945757faeeb 100644 --- a/src/experimental/solady/actions/signTypedData.ts +++ b/src/experimental/solady/actions/signTypedData.ts @@ -25,16 +25,19 @@ import { hashStruct, } from '../../../utils/signature/hashTypedData.js' import { getTypesForEIP712Domain } from '../../../utils/typedData.js' +import type { GetVerifierParameter } from '../types.js' export type SignTypedDataParameters< typedData extends TypedData | Record = TypedData, primaryType extends keyof typedData | 'EIP712Domain' = keyof typedData, account extends Account | undefined = undefined, + accountOverride extends Account | undefined = undefined, + verifier extends Address | undefined = Address | undefined, /// primaryTypes = typedData extends TypedData ? keyof typedData : string, > = TypedDataDefinition & - GetAccountParameter & Pick & + GetAccountParameter & OneOf< | { accountDomain: RequiredBy< @@ -43,8 +46,9 @@ export type SignTypedDataParameters< > fields: Hex extensions: readonly bigint[] + verifier?: undefined } - | { + | (GetVerifierParameter & { accountDomain?: | RequiredBy< TypedDataDomain, @@ -53,8 +57,7 @@ export type SignTypedDataParameters< | undefined fields?: Hex | undefined extensions?: readonly bigint[] | undefined - verifier: Address - } + }) > export type SignTypedDataReturnType = Hex @@ -82,8 +85,7 @@ export type SignTypedDataErrorType = ErrorType * transport: custom(window.ethereum), * }) * const signature = await signTypedData(client, { - * account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', - * verifier: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', * domain: { * name: 'Ether Mail', * version: '1', @@ -113,6 +115,7 @@ export type SignTypedDataErrorType = ErrorType * }, * contents: 'Hello, Bob!', * }, + * verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', * }) * * @example @@ -123,12 +126,11 @@ export type SignTypedDataErrorType = ErrorType * import { signTypedData } from 'viem/experimental/solady' * * const client = createWalletClient({ - * account: privateKeyToAccount('0x…'), + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb' * chain: mainnet, * transport: http(), * }) * const signature = await signTypedData(client, { - * verifier: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', * domain: { * name: 'Ether Mail', * version: '1', @@ -158,6 +160,7 @@ export type SignTypedDataErrorType = ErrorType * }, * contents: 'Hello, Bob!', * }, + * verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', * }) */ export async function signTypedData< @@ -165,9 +168,15 @@ export async function signTypedData< primaryType extends keyof typedData | 'EIP712Domain', chain extends Chain | undefined, account extends Account | undefined, + accountOverride extends Account | undefined = undefined, >( client: Client, - parameters: SignTypedDataParameters, + parameters: SignTypedDataParameters< + typedData, + primaryType, + account, + accountOverride + >, ): Promise { const { account: account_ = client.account, @@ -184,7 +193,7 @@ export async function signTypedData< throw new AccountNotFoundError({ docsPath: '/experimental/solady/signTypedData', }) - const account = parseAccount(account_) + const account = parseAccount(account_!) // Retrieve account EIP712 domain. const { diff --git a/src/experimental/solady/decorators/solady.test.ts b/src/experimental/solady/decorators/solady.test.ts new file mode 100644 index 00000000000..c5d82d12e90 --- /dev/null +++ b/src/experimental/solady/decorators/solady.test.ts @@ -0,0 +1,84 @@ +import type { Address } from 'abitype' +import { beforeAll, expect, test } from 'vitest' + +import { Mock4337AccountFactory } from '../../../../test/contracts/generated.js' +import { anvilMainnet } from '../../../../test/src/anvil.js' +import { accounts, typedData } from '../../../../test/src/constants.js' +import { deployMock4337Account } from '../../../../test/src/utils.js' +import { + mine, + simulateContract, + writeContract, +} from '../../../actions/index.js' +import { pad } from '../../../utils/index.js' +import { soladyActions } from './solady.js' + +const client = anvilMainnet.getClient().extend(soladyActions()) + +let verifier: Address +beforeAll(async () => { + const { factoryAddress } = await deployMock4337Account() + const { result, request } = await simulateContract(client, { + account: accounts[0].address, + abi: Mock4337AccountFactory.abi, + address: factoryAddress, + functionName: 'createAccount', + args: [accounts[0].address, pad('0x0')], + }) + verifier = result + await writeContract(client, request) + await mine(client, { blocks: 1 }) +}) + +test('default', () => { + expect(soladyActions()(client)).toMatchInlineSnapshot(` + { + "signMessage": [Function], + "signTypedData": [Function], + } + `) +}) + +test('signMessage', async () => { + const result = await client.signMessage({ + account: accounts[0].address, + message: 'Hello, world!', + verifier, + }) + expect(result).toMatchInlineSnapshot( + `"0x2fd7a8fe17e1e364f3527263a1e0963f2bf1c1e12c0889347f7633351cb7d8060a1a87099c3ed804bd31405705946dc9266744574b1153f2905948a6967d67a11b"`, + ) + + const clientWithAccount = anvilMainnet + .getClient({ account: true }) + .extend(soladyActions({ verifier })) + const result_2 = await clientWithAccount.signMessage({ + message: 'Hello, world!', + }) + expect(result_2).toMatchInlineSnapshot( + `"0x2fd7a8fe17e1e364f3527263a1e0963f2bf1c1e12c0889347f7633351cb7d8060a1a87099c3ed804bd31405705946dc9266744574b1153f2905948a6967d67a11b"`, + ) +}) + +test('signTypedData', async () => { + const result = await client.signTypedData({ + ...typedData.complex, + account: accounts[0].address, + primaryType: 'Mail', + verifier, + }) + expect(result).toMatchInlineSnapshot( + `"0x17f7e62a3921a11100b1f9631ed17c176767719fcc6e6178bf05e44fe0def85274e45a4f27940e9bc53f55d8c6934524d461f031059ba41bc0991e52093e53a71c1788ede5301fb0c4b95dda42eabe811ba83dc3cde96087b00c9b72a4d26a379ac2972c4c4323c6d7ee73e319350f290c6549b6eb516b5e5354128413342332154d61696c2875696e743235362074696d657374616d702c506572736f6e2066726f6d2c506572736f6e20746f2c737472696e6720636f6e74656e74732c62797465732068617368294e616d6528737472696e672066697273742c737472696e67206c61737429506572736f6e284e616d65206e616d652c616464726573732077616c6c65742c737472696e675b335d206661766f72697465436f6c6f72732c75696e7432353620666f6f2c75696e7438206167652c626f6f6c206973436f6f6c2900c1"`, + ) + + const clientWithAccount = anvilMainnet + .getClient({ account: true }) + .extend(soladyActions({ verifier })) + const result_2 = await clientWithAccount.signTypedData({ + ...typedData.complex, + primaryType: 'Mail', + }) + expect(result_2).toMatchInlineSnapshot( + `"0x17f7e62a3921a11100b1f9631ed17c176767719fcc6e6178bf05e44fe0def85274e45a4f27940e9bc53f55d8c6934524d461f031059ba41bc0991e52093e53a71c1788ede5301fb0c4b95dda42eabe811ba83dc3cde96087b00c9b72a4d26a379ac2972c4c4323c6d7ee73e319350f290c6549b6eb516b5e5354128413342332154d61696c2875696e743235362074696d657374616d702c506572736f6e2066726f6d2c506572736f6e20746f2c737472696e6720636f6e74656e74732c62797465732068617368294e616d6528737472696e672066697273742c737472696e67206c61737429506572736f6e284e616d65206e616d652c616464726573732077616c6c65742c737472696e675b335d206661766f72697465436f6c6f72732c75696e7432353620666f6f2c75696e7438206167652c626f6f6c206973436f6f6c2900c1"`, + ) +}) diff --git a/src/experimental/solady/decorators/solady.ts b/src/experimental/solady/decorators/solady.ts new file mode 100644 index 00000000000..a972ce41cd6 --- /dev/null +++ b/src/experimental/solady/decorators/solady.ts @@ -0,0 +1,232 @@ +import type { Address, TypedData } from 'abitype' +import type { Client } from '../../../clients/createClient.js' +import type { Transport } from '../../../clients/transports/createTransport.js' +import type { Account } from '../../../types/account.js' +import type { Chain } from '../../../types/chain.js' +import { + type SignMessageParameters, + type SignMessageReturnType, + signMessage, +} from '../actions/signMessage.js' +import { + type SignTypedDataParameters, + type SignTypedDataReturnType, + signTypedData, +} from '../actions/signTypedData.js' + +export type SoladyActions< + account extends Account | undefined = Account | undefined, + verifier extends Address | undefined = Address | undefined, +> = { + /** + * Signs a [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal sign message via Solady's [ERC1271 `PersonalSign` format](https://github.com/Vectorized/solady/blob/678c9163550810b08f0ffb09624c9f7532392303/src/accounts/ERC1271.sol#L154-L166). + * + * This Action is suitable to sign messages for Smart Accounts that implement (or conform to) Solady's [ERC1271.sol](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC1271.sol). + * + * - Docs: https://viem.sh/experimental/solady/signMessage + * + * With the calculated signature, you can: + * - use [`verifyMessage`](https://viem.sh/docs/utilities/verifyMessage) to verify the signature, + * + * @param client - Client to use + * @param parameters - {@link SignMessageParameters} + * @returns The signed message. {@link SignMessageReturnType} + * + * @example + * ```ts + * import { createWalletClient, custom } from 'viem' + * import { mainnet } from 'viem/chains' + * import { soladyActions } from 'viem/experimental/solady' + * + * const client = createWalletClient({ + * chain: mainnet, + * transport: custom(window.ethereum), + * }).extend(soladyActions()) + * + * const signature = await client.signMessage({ + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * message: 'hello world', + * verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', + * }) + * ``` + * + * @example Account & Signer Hoisting + * ```ts + * import { createWalletClient, custom } from 'viem' + * import { mainnet } from 'viem/chains' + * import { soladyActions } from 'viem/experimental/solady' + * + * const client = createWalletClient({ + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * chain: mainnet, + * transport: custom(window.ethereum), + * }).extend(soladyActions({ verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e' })) + * + * const signature = await client.signMessage({ + * message: 'hello world', + * }) + * ``` + */ + signMessage: ( + parameters: SignMessageParameters, + ) => Promise + /** + * Signs an [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data message via Solady's [ERC1271 `TypedDataSign` format](https://github.com/Vectorized/solady/blob/678c9163550810b08f0ffb09624c9f7532392303/src/accounts/ERC1271.sol#L130-L151). + * + * This Action is suitable to sign messages for Smart Accounts that implement (or conform to) Solady's [ERC1271.sol](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC1271.sol). + * + * - Docs: https://viem.sh/experimental/solady/signTypedData + * + * @param client - Client to use + * @param parameters - {@link SignTypedDataParameters} + * @returns The signed data. {@link SignTypedDataReturnType} + * + * @example + * ```ts + * import { createWalletClient, custom } from 'viem' + * import { mainnet } from 'viem/chains' + * import { soladyActions } from 'viem/experimental/solady' + * + * const client = createWalletClient({ + * chain: mainnet, + * transport: custom(window.ethereum), + * }).extend(soladyActions()) + * + * const signature = await client.signTypedData({ + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * domain: { + * name: 'Ether Mail', + * version: '1', + * chainId: 1, + * verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + * }, + * types: { + * Person: [ + * { name: 'name', type: 'string' }, + * { name: 'wallet', type: 'address' }, + * ], + * Mail: [ + * { name: 'from', type: 'Person' }, + * { name: 'to', type: 'Person' }, + * { name: 'contents', type: 'string' }, + * ], + * }, + * primaryType: 'Mail', + * message: { + * from: { + * name: 'Cow', + * wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + * }, + * to: { + * name: 'Bob', + * wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + * }, + * contents: 'Hello, Bob!', + * }, + * verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', + * }) + * ``` + * + * @example Account & Signer Hoisting + * ```ts + * import { createWalletClient, http } from 'viem' + * import { privateKeyToAccount } from 'viem/accounts' + * import { mainnet } from 'viem/chains' + * import { soladyActions } from 'viem/experimental/solady' + * + * const client = createWalletClient({ + * account: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', + * chain: mainnet, + * transport: http(), + * }).extend(soladyActions({ verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e' })) + * + * const signature = await client.signTypedData({ + * domain: { + * name: 'Ether Mail', + * version: '1', + * chainId: 1, + * verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', + * }, + * types: { + * Person: [ + * { name: 'name', type: 'string' }, + * { name: 'wallet', type: 'address' }, + * ], + * Mail: [ + * { name: 'from', type: 'Person' }, + * { name: 'to', type: 'Person' }, + * { name: 'contents', type: 'string' }, + * ], + * }, + * primaryType: 'Mail', + * message: { + * from: { + * name: 'Cow', + * wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + * }, + * to: { + * name: 'Bob', + * wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + * }, + * contents: 'Hello, Bob!', + * }, + * }) + * ``` + */ + signTypedData: < + const typedData extends TypedData | Record, + primaryType extends keyof typedData | 'EIP712Domain', + accountOverride extends Account | undefined = undefined, + >( + parameters: SignTypedDataParameters< + typedData, + primaryType, + account, + accountOverride + >, + ) => Promise +} + +export type SoladyActionsParameters< + verifier extends Account | Address | undefined = + | Account + | Address + | undefined, +> = { + verifier?: verifier | undefined +} + +/** + * A suite of Actions based on [Solady contracts](https://github.com/Vectorized/solady). + * + * @example + * import { createPublicClient, createWalletClient, http } from 'viem' + * import { mainnet } from 'viem/chains' + * import { soladyActions } from 'viem/experimental' + * + * const walletClient = createWalletClient({ + * chain: mainnet, + * transport: http(), + * }).extend(soladyActions()) + * + * const result = await walletClient.signMessage({...}) + */ +export function soladyActions( + parameters: SoladyActionsParameters = {}, +) { + const { verifier } = parameters + return < + transport extends Transport, + chain extends Chain | undefined = Chain | undefined, + account extends Account | undefined = Account | undefined, + >( + client: Client, + ): SoladyActions => { + return { + signMessage: (parameters) => + signMessage(client, { verifier, ...parameters }), + signTypedData: (parameters) => + signTypedData(client, { verifier, ...(parameters as any) }), + } + } +} diff --git a/src/experimental/solady/types.ts b/src/experimental/solady/types.ts new file mode 100644 index 00000000000..ffd80ed2871 --- /dev/null +++ b/src/experimental/solady/types.ts @@ -0,0 +1,7 @@ +import type { Address } from 'abitype' + +export type GetVerifierParameter< + verifier extends Address | undefined = Address, +> = verifier extends Address + ? { verifier?: Address | undefined } + : { verifier: Address }