Skip to content

Commit

Permalink
feat: siwe (#2280)
Browse files Browse the repository at this point in the history
* feat: siwe

* wip: check

* wip: parse

* refactor: comments and errors

* chore: format

* chore: add exports

* test: utils

* chore: format

* refactor: time-related data types

* refactor: rename utils

* feat(siwe): action

* chore: format

* docs: siwe

* chore: format

* docs: up

* chore: snaps

* test: boost coverage

---------

Co-authored-by: tmm <tmm@users.noreply.github.com>
  • Loading branch information
tmm and tmm committed May 21, 2024
1 parent 846bf3d commit 4dc6d32
Show file tree
Hide file tree
Showing 36 changed files with 2,153 additions and 16 deletions.
4 changes: 2 additions & 2 deletions site/pages/docs/actions/public/verifyMessage.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const [account] = await walletClient.getAddresses()

`boolean`

Wheather the signed message is valid for the given address.
Whether the signed message is valid for the given address.

## Parameters

Expand Down Expand Up @@ -169,4 +169,4 @@ const valid = await publicClient.verifyMessage({

## JSON-RPC Method

[`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) to a deployless [universal signature validator contract](https://eips.ethereum.org/EIPS/eip-6492).
[`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) to a deployless [universal signature validator contract](https://eips.ethereum.org/EIPS/eip-6492).
4 changes: 2 additions & 2 deletions site/pages/docs/actions/public/verifyTypedData.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const [account] = await walletClient.getAddresses()

`boolean`

Wheather the signed message is valid for the given address.
Whether the signed message is valid for the given address.

## Parameters

Expand Down Expand Up @@ -459,4 +459,4 @@ const valid = await publicClient.verifyTypedData({

## JSON-RPC Method

[`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) to a deployless [universal signature validator contract](https://eips.ethereum.org/EIPS/eip-6492).
[`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) to a deployless [universal signature validator contract](https://eips.ethereum.org/EIPS/eip-6492).
4 changes: 1 addition & 3 deletions site/pages/docs/ens/utilities/labelhash.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ labelhash(normalize('awkweb')) // [!code focus:2]
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS labels](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `labelhash`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::

###

## Returns

`string`
Expand All @@ -39,4 +37,4 @@ The hashed ENS label.

- **Type:** `string`

A ENS label.
A ENS label.
6 changes: 6 additions & 0 deletions site/pages/docs/glossary/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ When address is invalid.
### `UnsupportedProviderMethodError`
### `UserRejectedRequestError`

## SIWE

### CreateSiweMessageErrorType
### SiweInvalidMessageFieldErrorType
### VerifySiweMessageErrorType

## Transaction

### `FeeConflictError`
Expand Down
245 changes: 245 additions & 0 deletions site/pages/docs/siwe/actions/verifySiweMessage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
---
description: Verifies EIP-4361 formatted message was signed.
---

# verifySiweMessage

Verifies [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message was signed.

See [`createSiweMessage`](/docs/siwe/utilities/createSiweMessage) for info on how to create a EIP-4361 formatted message.

## Usage

:::code-group

```ts twoslash [example.ts]
import { account, walletClient, publicClient } from './client'
import { message } from './message'

const signature = await walletClient.signMessage({ account, message })
// [!code focus:99]
const valid = await publicClient.verifySiweMessage({
message,
signature,
})
// @log: true
```

```ts twoslash [client.ts] filename="client.ts"
import 'viem/window'
// ---cut---
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet } from 'viem/chains'

export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})

export const walletClient = createWalletClient({
transport: custom(window.ethereum!)
})

// @log: ↓ JSON-RPC Account
export const [account] = await walletClient.getAddresses()

// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
```

```ts twoslash [message.ts] filename="message.ts"
// ---cut---
import { createSiweMessage, generateSiweNonce } from 'viem/siwe'
import { mainnet } from 'viem/chains'
import { account } from './client'

export const message = createSiweMessage({
address: account.address,
chainId: mainnet.id,
domain: 'example.com',
nonce: generateSiweNonce(),
uri: 'https://example.com/path',
version: '1',
})
```

:::

## Returns

`boolean`

Whether the signed message is valid for the given address.

## Parameters

### message

- **Type:** `string`

[EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message to be verified.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
import { createSiweMessage, generateSiweNonce } from 'viem/siwe'
// ---cut---
const valid = await publicClient.verifySiweMessage({
message: createSiweMessage({ // [!code focus:1]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
chainId: 1, // [!code focus:1]
domain: 'example.com', // [!code focus:1]
nonce: generateSiweNonce(), // [!code focus:1]
uri: 'https://example.com/path', // [!code focus:1]
version: '1', // [!code focus:1]
}), // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### signature

- **Type:** `Hex`

The signature that was generated by signing the message with the address's signer.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c', // [!code focus:1]
})
```

### address (optional)

- **Type:** `Address`

Ethereum address to check against.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### blockNumber (optional)

- **Type:** `number`

Only used when verifying a message that was signed by a Smart Contract Account. The block number to check if the contract was already deployed.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
blockNumber: 42069n, // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### blockTag (optional)

- **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
- **Default:** `'latest'`

Only used when verifying a message that was signed by a Smart Contract Account. The block tag to check if the contract was already deployed.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
blockTag: 'safe', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### domain (optional)

- **Type:** `string`

[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority to check against.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
domain: 'viem.sh', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### nonce (optional)

- **Type:** `string`

Random string to check against.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
import { generateSiweNonce } from 'viem/siwe'
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
nonce: generateSiweNonce(), // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### scheme (optional)

- **Type:** `string`

[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme to check against.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
scheme: 'https', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

### time (optional)

- **Type:** `Date`
- **Default:** `new Date()`

Current time to check optional [`expirationTime`](http://localhost:5173/docs/siwe/utilities/createSiweMessage#expirationtime-optional) and [`notBefore`](/docs/siwe/utilities/createSiweMessage#notbefore-optional) message fields.

```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
time: new Date(), // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```

0 comments on commit 4dc6d32

Please sign in to comment.