diff --git a/.changeset/famous-penguins-lay.md b/.changeset/famous-penguins-lay.md new file mode 100644 index 00000000000..80b2f48b625 --- /dev/null +++ b/.changeset/famous-penguins-lay.md @@ -0,0 +1,5 @@ +--- +"@thirdweb-dev/wallets": patch +--- + +Multidimensional nonces for smart wallets diff --git a/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-provider.ts b/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-provider.ts index bf1fb2c995d..ea4b793c769 100644 --- a/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-provider.ts +++ b/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-provider.ts @@ -149,7 +149,7 @@ export class ERC4337EthersProvider extends providers.BaseProvider { hash: userOpHash, confirmations: 0, from: userOp.sender, - nonce: BigNumber.from(userOp.nonce).toNumber(), + nonce: 0, // not the real nonce, but good enough for this purpose gasLimit: BigNumber.from(userOp.callGasLimit), // ?? value: BigNumber.from(0), data: utils.hexValue(userOp.callData), // should extract the actual called method from this "execFromEntryPoint()" call diff --git a/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-signer.ts b/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-signer.ts index a96df3f59f6..533ba573ed5 100644 --- a/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-signer.ts +++ b/packages/wallets/src/evm/connectors/smart-wallet/lib/erc4337-signer.ts @@ -5,6 +5,7 @@ import { ClientConfig } from "@account-abstraction/sdk"; import { BaseAccountAPI } from "./base-api"; import type { ERC4337EthersProvider } from "./erc4337-provider"; import { HttpRpcClient } from "./http-rpc-client"; +import { randomNonce } from "./utils"; export class ERC4337EthersSigner extends Signer { config: ClientConfig; @@ -40,12 +41,14 @@ export class ERC4337EthersSigner extends Signer { const tx = await ethers.utils.resolveProperties(transaction); await this.verifyAllNecessaryFields(tx); + const multidimensionalNonce = randomNonce(); const userOperation = await this.smartAccountAPI.createSignedUserOp( { target: tx.to || "", data: tx.data?.toString() || "0x", value: tx.value, gasLimit: tx.gasLimit, + nonce: multidimensionalNonce, }, batched, ); diff --git a/packages/wallets/src/evm/connectors/smart-wallet/lib/utils.ts b/packages/wallets/src/evm/connectors/smart-wallet/lib/utils.ts index e952e727aa5..4ad0171c913 100644 --- a/packages/wallets/src/evm/connectors/smart-wallet/lib/utils.ts +++ b/packages/wallets/src/evm/connectors/smart-wallet/lib/utils.ts @@ -76,3 +76,31 @@ export async function getUserOpHashV06( ); return utils.keccak256(enc); } + +const generateRandomUint192 = (): bigint => { + const rand1 = BigInt(Math.floor(Math.random() * 0x100000000)); + const rand2 = BigInt(Math.floor(Math.random() * 0x100000000)); + const rand3 = BigInt(Math.floor(Math.random() * 0x100000000)); + const rand4 = BigInt(Math.floor(Math.random() * 0x100000000)); + const rand5 = BigInt(Math.floor(Math.random() * 0x100000000)); + const rand6 = BigInt(Math.floor(Math.random() * 0x100000000)); + return ( + (rand1 << 160n) | + (rand2 << 128n) | + (rand3 << 96n) | + (rand4 << 64n) | + (rand5 << 32n) | + rand6 + ); +}; + +export const randomNonce = () => { + let hexString = generateRandomUint192().toString(16); + if (hexString.length % 2 !== 0) { + hexString = "0" + hexString; + } + hexString = "0x" + hexString; + return ethers.BigNumber.from( + ethers.utils.concat([hexString, "0x0000000000000000"]), + ); +};