From 1667ad18896e826c463d4910dfd8f452f12aa3b3 Mon Sep 17 00:00:00 2001 From: jxom Date: Fri, 16 Aug 2024 07:05:06 +1000 Subject: [PATCH 1/2] feat: make `getNonce` optional on `SmartAccountImplementation` --- .changeset/hip-starfishes-speak.md | 5 ++++ .../implementations/toCoinbaseSmartAccount.ts | 15 +---------- .../implementations/toSoladySmartAccount.ts | 18 +++---------- .../accounts/toSmartAccount.test.ts | 25 +++++++++++++++++++ .../accounts/toSmartAccount.ts | 17 +++++++++++-- src/account-abstraction/accounts/types.ts | 18 ++++++++++--- 6 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 .changeset/hip-starfishes-speak.md diff --git a/.changeset/hip-starfishes-speak.md b/.changeset/hip-starfishes-speak.md new file mode 100644 index 0000000000..fa7d3c689b --- /dev/null +++ b/.changeset/hip-starfishes-speak.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +Made `getNonce` optional on `SmartAccountImplementation`. diff --git a/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts b/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts index 66cabcbdce..7995fb62b6 100644 --- a/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts +++ b/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts @@ -1,4 +1,4 @@ -import { type Address, type TypedData, parseAbi } from 'abitype' +import type { Address, TypedData } from 'abitype' import { type WebAuthnData, parseSignature as parseP256Signature, @@ -132,19 +132,6 @@ export async function toCoinbaseSmartAccount( return { factory: factory.address, factoryData } }, - async getNonce({ key = 0n } = {}) { - const address = await this.getAddress() - const nonce = await readContract(client, { - abi: parseAbi([ - 'function getNonce(address, uint192) pure returns (uint256)', - ]), - address: entryPoint.address, - functionName: 'getNonce', - args: [address, key], - }) - return nonce - }, - async getStubSignature() { if (owner.type === 'webAuthn') return '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000001949fc7c88032b9fcb5f6efc7a7b8c63668eae9871b765e23123bb473ff57aa831a7c0d9276168ebcc29f2875a0239cffdf2a9cd1c2007c5c77c071db9264df1d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273496a396e6164474850596759334b7156384f7a4a666c726275504b474f716d59576f4d57516869467773222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d00000000000000000000000000000000000000000000' diff --git a/src/account-abstraction/accounts/implementations/toSoladySmartAccount.ts b/src/account-abstraction/accounts/implementations/toSoladySmartAccount.ts index 9c9308d22b..204eadfc3a 100644 --- a/src/account-abstraction/accounts/implementations/toSoladySmartAccount.ts +++ b/src/account-abstraction/accounts/implementations/toSoladySmartAccount.ts @@ -1,4 +1,4 @@ -import { type Abi, type Address, type TypedData, parseAbi } from 'abitype' +import type { Abi, Address, TypedData } from 'abitype' import { parseAccount } from '../../../accounts/utils/parseAccount.js' import { readContract } from '../../../actions/public/readContract.js' @@ -34,6 +34,7 @@ export type ToSoladySmartAccountParameters< } | undefined factoryAddress?: Address | undefined + getNonce?: SmartAccountImplementation['getNonce'] | undefined owner: Address | Account salt?: Hex | undefined } @@ -86,6 +87,7 @@ export async function toSoladySmartAccount< version: '0.7', }, factoryAddress = '0x5d82735936c6Cd5DE57cC3c1A799f6B2E6F933Df', + getNonce, salt = '0x0', } = parameters @@ -103,6 +105,7 @@ export async function toSoladySmartAccount< return toSmartAccount({ client, entryPoint, + getNonce, extend: { abi, factory }, @@ -144,19 +147,6 @@ export async function toSoladySmartAccount< return { factory: factory.address, factoryData } }, - async getNonce({ key = 0n } = {}) { - const address = await this.getAddress() - const nonce = await readContract(client, { - abi: parseAbi([ - 'function getNonce(address, uint192) pure returns (uint256)', - ]), - address: entryPoint.address, - functionName: 'getNonce', - args: [address, key], - }) - return nonce - }, - async getStubSignature() { return '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c' }, diff --git a/src/account-abstraction/accounts/toSmartAccount.test.ts b/src/account-abstraction/accounts/toSmartAccount.test.ts index e677d8a143..d709d3b891 100644 --- a/src/account-abstraction/accounts/toSmartAccount.test.ts +++ b/src/account-abstraction/accounts/toSmartAccount.test.ts @@ -966,3 +966,28 @@ test('return value: `getFactoryArgs`', async () => { } `) }) + +test('return value: `getNonce`', async () => { + const { factoryAddress } = await deploySoladyAccount_07() + + const account = await toSoladySmartAccount({ + client, + factoryAddress, + owner: accounts[1].address, + }) + expect(await account.getNonce()).toBeDefined() +}) + +test('return value: `getNonce` (implementation override)', async () => { + const { factoryAddress } = await deploySoladyAccount_07() + + const account = await toSoladySmartAccount({ + client, + factoryAddress, + owner: accounts[1].address, + async getNonce() { + return 69n + }, + }) + expect(await account.getNonce()).toBe(69n) +}) diff --git a/src/account-abstraction/accounts/toSmartAccount.ts b/src/account-abstraction/accounts/toSmartAccount.ts index fec430171f..eb6ec99f3b 100644 --- a/src/account-abstraction/accounts/toSmartAccount.ts +++ b/src/account-abstraction/accounts/toSmartAccount.ts @@ -1,4 +1,4 @@ -import type { Abi } from 'abitype' +import { parseAbi, type Abi } from 'abitype' import { getCode } from '../../actions/public/getCode.js' import type { Prettify } from '../../types/utils.js' @@ -7,6 +7,7 @@ import { createNonceManager } from '../../utils/nonceManager.js' import { serializeErc6492Signature } from '../../utils/signature/serializeErc6492Signature.js' import type { EntryPointVersion } from '../types/entryPointVersion.js' import type { SmartAccount, SmartAccountImplementation } from './types.js' +import { readContract } from '../../actions/public/readContract.js' export type ToSmartAccountParameters< entryPointAbi extends Abi | readonly unknown[] = Abi, @@ -64,7 +65,19 @@ export async function toSmartAccount< client: implementation.client, }), ) - return await implementation.getNonce({ ...parameters, key }) + + if (implementation.getNonce) + return await implementation.getNonce({ ...parameters, key }) + + const nonce = await readContract(implementation.client, { + abi: parseAbi([ + 'function getNonce(address, uint192) pure returns (uint256)', + ]), + address: implementation.entryPoint.address, + functionName: 'getNonce', + args: [address, key], + }) + return nonce }, async isDeployed() { if (deployed) return true diff --git a/src/account-abstraction/accounts/types.ts b/src/account-abstraction/accounts/types.ts index 5ed9e3342a..b7f603fbb9 100644 --- a/src/account-abstraction/accounts/types.ts +++ b/src/account-abstraction/accounts/types.ts @@ -88,9 +88,11 @@ export type SmartAccountImplementation< * // 1n * ``` */ - getNonce: ( - parameters?: { key?: bigint | undefined } | undefined, - ) => Promise + getNonce?: + | (( + parameters?: { key?: bigint | undefined } | undefined, + ) => Promise) + | undefined /** * Retrieves the User Operation "stub" signature for gas estimation. * @@ -184,6 +186,16 @@ export type SmartAccount< { /** Address of the Smart Account. */ address: Address + /** + * Retrieves the nonce of the Account. + * + * @example + * ```ts + * const nonce = await account.getNonce() + * // 1n + * ``` + */ + getNonce: NonNullable /** Whether or not the Smart Account has been deployed. */ isDeployed: () => Promise /** Type of account. */ From 1e179dc8d4190ae0c3ab50ba11eb1eb2b65dfe06 Mon Sep 17 00:00:00 2001 From: jxom Date: Fri, 16 Aug 2024 07:05:13 +1000 Subject: [PATCH 2/2] chore: format --- src/account-abstraction/accounts/toSmartAccount.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/account-abstraction/accounts/toSmartAccount.ts b/src/account-abstraction/accounts/toSmartAccount.ts index eb6ec99f3b..46b38e8116 100644 --- a/src/account-abstraction/accounts/toSmartAccount.ts +++ b/src/account-abstraction/accounts/toSmartAccount.ts @@ -1,13 +1,13 @@ -import { parseAbi, type Abi } from 'abitype' +import { type Abi, parseAbi } from 'abitype' import { getCode } from '../../actions/public/getCode.js' +import { readContract } from '../../actions/public/readContract.js' import type { Prettify } from '../../types/utils.js' import { getAction } from '../../utils/getAction.js' import { createNonceManager } from '../../utils/nonceManager.js' import { serializeErc6492Signature } from '../../utils/signature/serializeErc6492Signature.js' import type { EntryPointVersion } from '../types/entryPointVersion.js' import type { SmartAccount, SmartAccountImplementation } from './types.js' -import { readContract } from '../../actions/public/readContract.js' export type ToSmartAccountParameters< entryPointAbi extends Abi | readonly unknown[] = Abi,