Skip to content

Commit

Permalink
feat: specify owner index on coinbase smart wallet (#2896)
Browse files Browse the repository at this point in the history
* feat: specify owner index on coinbase smart wallet

* chore: up

* chore: up

* Update wise-clouds-complain.md

* Update toCoinbaseSmartAccount.md

---------

Co-authored-by: jxom <j@wevm.dev>
Co-authored-by: jxom <jakemoxey@gmail.com>
  • Loading branch information
3 people authored Nov 1, 2024
1 parent a41f29d commit c0367c8
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/wise-clouds-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added `ownerIndex` parameter to `toCoinbaseSmartWallet`.
12 changes: 10 additions & 2 deletions pnpm-lock.yaml

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

Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ const account = await toCoinbaseSmartAccount({
})
```

### ownerIndex (optional)

- **Type:** `number`

Index of the owner to use for signing messages & User Operations.

```ts
const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...'), privateKeyToAccount('0x...')],
ownerIndex: 1, // [!code focus]
})
```

### nonce (optional)

- **Type:** `bigint`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const client = anvilMainnet.getClient({ account: true })
const bundlerClient = bundlerMainnet.getBundlerClient({ client })

const owner = privateKeyToAccount(accounts[0].privateKey)
const owner_webauthn = toWebAuthnAccount({
credential: { id: 'abc', publicKey: '0xdeadbeef' },
})

describe('return value: encodeCalls', () => {
test('single', async () => {
Expand Down Expand Up @@ -244,20 +247,57 @@ describe('return value: getStubSignature', () => {
})

test('default: webauthn', async () => {
const owner = toWebAuthnAccount({
credential: { id: 'abc', publicKey: '0xdeadbeef' },
})

const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
owners: [owner_webauthn],
})

const signature = await account.getStubSignature()
expect(signature).toMatchInlineSnapshot(
`"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000001949fc7c88032b9fcb5f6efc7a7b8c63668eae9871b765e23123bb473ff57aa831a7c0d9276168ebcc29f2875a0239cffdf2a9cd1c2007c5c77c071db9264df1d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273496a396e6164474850596759334b7156384f7a4a666c726275504b474f716d59576f4d57516869467773222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d00000000000000000000000000000000000000000000"`,
)
})

test('custom: ownerIndex', async () => {
{
const account = await toCoinbaseSmartAccount({
client,
owners: [owner, owner_webauthn, owner],
ownerIndex: 1,
})

const signature = await account.getStubSignature()
expect(signature).toMatchInlineSnapshot(
`"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000001949fc7c88032b9fcb5f6efc7a7b8c63668eae9871b765e23123bb473ff57aa831a7c0d9276168ebcc29f2875a0239cffdf2a9cd1c2007c5c77c071db9264df1d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273496a396e6164474850596759334b7156384f7a4a666c726275504b474f716d59576f4d57516869467773222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d00000000000000000000000000000000000000000000"`,
)
}

{
const account = await toCoinbaseSmartAccount({
client,
owners: [owner, owner_webauthn, owner],
ownerIndex: 2,
})

const signature = await account.getStubSignature()
expect(signature).toMatchInlineSnapshot(
`"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000041fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c00000000000000000000000000000000000000000000000000000000000000"`,
)
}

{
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
ownerIndex: 1,
})

const signature = await account.getStubSignature()
expect(signature).toMatchInlineSnapshot(
`"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000041fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c00000000000000000000000000000000000000000000000000000000000000"`,
)
}
})
})

describe('return value: getNonce', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import type {
export type ToCoinbaseSmartAccountParameters = {
address?: Address | undefined
client: Client
ownerIndex?: number | undefined
owners: readonly OneOf<LocalAccount | WebAuthnAccount>[]
nonce?: bigint | undefined
}
Expand Down Expand Up @@ -74,7 +75,7 @@ export type CoinbaseSmartAccountImplementation = Assign<
export async function toCoinbaseSmartAccount(
parameters: ToCoinbaseSmartAccountParameters,
): Promise<ToCoinbaseSmartAccountReturnType> {
const { client, owners, nonce = 0n } = parameters
const { client, ownerIndex = 0, owners, nonce = 0n } = parameters

let address = parameters.address

Expand All @@ -92,7 +93,7 @@ export async function toCoinbaseSmartAccount(
owner.type === 'webAuthn' ? owner.publicKey : pad(owner.address),
)

const owner = owners[0]
const owner = owners[ownerIndex] ?? owners[0]

return toSmartAccount({
client,
Expand Down Expand Up @@ -161,6 +162,7 @@ export async function toCoinbaseSmartAccount(
if (owner.type === 'webAuthn')
return '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000001949fc7c88032b9fcb5f6efc7a7b8c63668eae9871b765e23123bb473ff57aa831a7c0d9276168ebcc29f2875a0239cffdf2a9cd1c2007c5c77c071db9264df1d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273496a396e6164474850596759334b7156384f7a4a666c726275504b474f716d59576f4d57516869467773222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d00000000000000000000000000000000000000000000'
return wrapSignature({
ownerIndex,
signature:
'0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c',
})
Expand All @@ -178,6 +180,7 @@ export async function toCoinbaseSmartAccount(
const signature = await sign({ hash, owner })

return wrapSignature({
ownerIndex,
signature,
})
},
Expand All @@ -195,6 +198,7 @@ export async function toCoinbaseSmartAccount(
const signature = await sign({ hash, owner })

return wrapSignature({
ownerIndex,
signature,
})
},
Expand All @@ -218,6 +222,7 @@ export async function toCoinbaseSmartAccount(
const signature = await sign({ hash, owner })

return wrapSignature({
ownerIndex,
signature,
})
},
Expand All @@ -239,6 +244,7 @@ export async function toCoinbaseSmartAccount(
const signature = await sign({ hash, owner })

return wrapSignature({
ownerIndex,
signature,
})
},
Expand Down

0 comments on commit c0367c8

Please sign in to comment.