Skip to content
Merged
5 changes: 5 additions & 0 deletions .changeset/swift-lobsters-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": minor
---

**Experimental:** Added `addSubAccount` Action as per [ERC-7895](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md).
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
"src": {
"entry": [
"index.ts!",
"{account-abstraction,accounts,actions,celo,chains,ens,experimental,experimental/erc7739,experimental/erc7821,experimental/erc7846,linea,node,nonce,op-stack,siwe,utils,window,zksync}/index.ts!",
"{account-abstraction,accounts,actions,celo,chains,ens,experimental,experimental/erc7739,experimental/erc7821,experimental/erc7846,experimental/erc7895,linea,node,nonce,op-stack,siwe,utils,window,zksync}/index.ts!",
"chains/utils.ts!"
],
"ignore": ["node/trustedSetups_cjs.ts"]
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions site/pages/experimental/erc7846/connect.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
description: Requests to connect account(s).
description: Requests to connect Account(s).
---

# connect

Requests to connect account(s) with optional [capabilities](#capabilities).
Requests to connect Account(s) with optional [capabilities](#capabilities).

## Usage

Expand Down Expand Up @@ -69,7 +69,7 @@ const { accounts } = await walletClient.connect({

### `unstable_addSubAccount`

Adds a sub-account to the connected account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)
Adds a Sub Account to the connected Account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)

```ts twoslash
import { walletClient } from './config'
Expand Down Expand Up @@ -99,7 +99,7 @@ const { accounts } = await walletClient.connect({

### `unstable_getSubAccounts`

Returns all sub-accounts of the connected account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)
Returns all Sub Accounts of the connected Account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)

```ts twoslash
import { walletClient } from './config'
Expand Down Expand Up @@ -149,4 +149,4 @@ const { accounts } = await walletClient.connect({
## JSON-RPC Methods

- [`wallet_connect`](https://github.com/ethereum/ERCs/blob/abd1c9f4eda2d6ad06ade0e3af314637a27d1ee7/ERCS/erc-7846.md)
- Falls back to [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102)
- Falls back to [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102)
211 changes: 211 additions & 0 deletions site/pages/experimental/erc7895/addSubAccount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
description: Requests to add a Sub Account.
---

# addSubAccount

Requests to add a Sub Account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)

[What is a Sub Account?](https://blog.base.dev/subaccounts)

## Usage

:::code-group

```ts twoslash [example.ts]
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
keys: [{
key: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d',
type: 'address'
}],
type: 'create',
})
```

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

export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7895Actions())
```

:::

## Returns

The created Sub Account.

```ts
type ReturnType = {
address: Address
factory?: Address | undefined
factoryData?: Hex | undefined
}
```

## Parameters

### New Accounts

Allows the wallet to create a Sub Account with a set of known signing keys. [Learn more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md#createaccount)

#### `keys`

Set of signing keys that will belong to the Sub Account.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
keys: [{ // [!code focus]
key: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d486e5df68893003e01241522', // [!code focus]
type: 'p256' // [!code focus]
}], // [!code focus]
type: 'create',
})
```

#### `keys.key`

- **Type:** `Hex`

The public key of the signing key.

- This is a 32-byte hexadecimal string.
- For `type: "address"`, this is a 20-byte address.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
keys: [{
key: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d486e5df68893003e01241522', // [!code focus]
type: 'p256'
}],
type: 'create',
})
```

#### `keys.type`

- **Type:** `'address' | 'p256' | 'webcrypto-p256' | 'webauthn-p256'`

The type of signing key.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
keys: [{
key: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d486e5df68893003e01241522',
type: 'p256' // [!code focus]
}],
type: 'create',
})
```


### Deployed Accounts

An existing account that the user wants to link to their global account. [Learn more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md#deployedaccount)

#### `address`

Address of the deployed account.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000', // [!code focus]
type: 'deployed',
})
```

#### `chainId`

The chain ID of the deployed account.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
chainId: 1, // [!code focus]
type: 'deployed',
})
```

### Undeployed Accounts

An account that has been created, but is not yet deployed. The wallet will decide whether or not to deploy it. [Learn more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md#undeployedaccount)

#### `address`

Address of the undeployed account.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000', // [!code focus]
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
factoryData: '0xdeadbeef',
type: 'undeployed',
})
```

#### `chainId`

The chain ID the account will be deployed on.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
chainId: 1, // [!code focus]
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
factoryData: '0xdeadbeef',
type: 'undeployed',
})
```

#### `factory`

The address of the factory contract.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce', // [!code focus]
factoryData: '0xdeadbeef',
type: 'undeployed',
})
```

#### `factoryData`

The data to be passed to the factory contract.

```ts twoslash
import { walletClient } from './config'

const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
factoryData: '0xdeadbeef', // [!code focus]
type: 'undeployed',
})
```

19 changes: 19 additions & 0 deletions site/pages/experimental/erc7895/client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Extending Client with ERC-7895 Actions [Setting up your Viem Client]

To use the experimental functionality of [ERC-7895](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md), you can extend your existing (or new) Viem Client with experimental [ERC-7895](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md) Actions.

```ts
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7895Actions } from 'viem/experimental' // [!code focus]

const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7895Actions()) // [!code focus]

const subAccount = await client.addSubAccount({
keys: [{ key: '0x0000000000000000000000000000000000000000', type: 'address' }],
type: 'create',
})
```
18 changes: 18 additions & 0 deletions site/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,24 @@ export const sidebar = {
},
],
},
{
text: 'ERC-7895',
items: [
{
text: 'Client',
link: '/experimental/erc7895/client',
},
{
text: 'Actions',
items: [
{
text: 'addSubAccount',
link: '/experimental/erc7895/addSubAccount',
},
],
},
],
},
],
},
'/op-stack': {
Expand Down
36 changes: 36 additions & 0 deletions src/experimental/erc7895/actions/addSubAccount.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { expect, test } from 'vitest'
import { anvilMainnet } from '../../../../test/src/anvil.js'
import { addSubAccount } from './addSubAccount.js'

const client = anvilMainnet.getClient()

test('default', async () => {
{
const response = await addSubAccount(client, {
keys: [
{ key: '0x0000000000000000000000000000000000000000', type: 'address' },
],
type: 'create',
})

expect(response).toMatchInlineSnapshot(`
{
"address": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
}
`)
}

{
const response = await addSubAccount(client, {
address: '0x0000000000000000000000000000000000000000',
chainId: 1,
type: 'deployed',
})

expect(response).toMatchInlineSnapshot(`
{
"address": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
}
`)
}
})
Loading
Loading