Skip to content

Commit

Permalink
wip: checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Jun 18, 2024
1 parent 60bd07d commit 1c7c1d2
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 32 deletions.
14 changes: 14 additions & 0 deletions site/pages/experimental/solady/signMessage.md
Original file line number Diff line number Diff line change
@@ -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

5 changes: 5 additions & 0 deletions src/experimental/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,8 @@ export {
type SignTypedDataReturnType,
signTypedData,
} from './solady/actions/signTypedData.js'
export {
type SoladyActions,
type SoladyActionsParameters,
soladyActions,
} from './solady/decorators/solady.js'
12 changes: 8 additions & 4 deletions src/experimental/solady/actions/signMessage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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!, {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
26 changes: 16 additions & 10 deletions src/experimental/solady/actions/signMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,31 @@ 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<account> &
Pick<GetEip712DomainParameters, 'factory' | 'factoryData'> & {
accountOverride extends Account | undefined = Account | undefined,
verifier extends Address | undefined = Address | undefined,
> = Pick<GetEip712DomainParameters, 'factory' | 'factoryData'> &
GetAccountParameter<account, accountOverride> & {
message: SignableMessage
} & OneOf<
| {
accountDomain: RequiredBy<
TypedDataDomain,
'chainId' | 'name' | 'verifyingContract' | 'version'
>
verifier?: undefined
}
| {
| (GetVerifierParameter<verifier> & {
accountDomain?:
| RequiredBy<
TypedDataDomain,
'chainId' | 'name' | 'verifyingContract' | 'version'
>
| undefined
verifier: Address
}
})
>

export type SignMessageReturnType = Hex
Expand Down Expand Up @@ -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
Expand All @@ -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<Transport, chain, account>,
parameters: SignMessageParameters<account>,
parameters: SignMessageParameters<account, accountOverride>,
): Promise<SignMessageReturnType> {
const {
account: account_ = client.account,
Expand Down
17 changes: 9 additions & 8 deletions src/experimental/solady/actions/signTypedData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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,
})
Expand Down Expand Up @@ -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,
})
Expand All @@ -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,
})
Expand All @@ -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,
})
Expand All @@ -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,
})
Expand All @@ -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,
})
Expand All @@ -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,
})
Expand Down
29 changes: 19 additions & 10 deletions src/experimental/solady/actions/signTypedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown> = 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<typedData, primaryType, primaryTypes> &
GetAccountParameter<account> &
Pick<GetEip712DomainParameters, 'factory' | 'factoryData'> &
GetAccountParameter<account, accountOverride> &
OneOf<
| {
accountDomain: RequiredBy<
Expand All @@ -43,8 +46,9 @@ export type SignTypedDataParameters<
>
fields: Hex
extensions: readonly bigint[]
verifier?: undefined
}
| {
| (GetVerifierParameter<verifier> & {
accountDomain?:
| RequiredBy<
TypedDataDomain,
Expand All @@ -53,8 +57,7 @@ export type SignTypedDataParameters<
| undefined
fields?: Hex | undefined
extensions?: readonly bigint[] | undefined
verifier: Address
}
})
>

export type SignTypedDataReturnType = Hex
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -113,6 +115,7 @@ export type SignTypedDataErrorType = ErrorType
* },
* contents: 'Hello, Bob!',
* },
* verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
*
* @example
Expand All @@ -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',
Expand Down Expand Up @@ -158,16 +160,23 @@ export type SignTypedDataErrorType = ErrorType
* },
* contents: 'Hello, Bob!',
* },
* verifier: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* })
*/
export async function signTypedData<
const typedData extends TypedData | Record<string, unknown>,
primaryType extends keyof typedData | 'EIP712Domain',
chain extends Chain | undefined,
account extends Account | undefined,
accountOverride extends Account | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: SignTypedDataParameters<typedData, primaryType, account>,
parameters: SignTypedDataParameters<
typedData,
primaryType,
account,
accountOverride
>,
): Promise<SignTypedDataReturnType> {
const {
account: account_ = client.account,
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit 1c7c1d2

Please sign in to comment.