Parallel Transactions with Smart Accounts
With smart accounts, the nonce can be two-dimensional:
nonceKey
(or nonce space) identifies a logical lane or stream.nonce
within that key auto-increments on every UserOperation.
This enables parallel execution across different nonce keys, and sequential ordering within each key.
Visual Illustration
┌────────────────────┐
nonceKey 1: │ UserOp A (nonce: 0)│
│ UserOp B (nonce: 1)│
│ UserOp C (nonce: 2)│ ← Sequential
└────────────────────┘
┌────────────────────┐
nonceKey 2: │ UserOp X (nonce: 0)│
│ UserOp Y (nonce: 1)│ ← Independent
└────────────────────┘
┌────────────────────┐
nonceKey 3: │ UserOp Z (nonce: 0)│ ← Parallel
└────────────────────┘
Using nonceKey
for Parallel and Sequential Execution
Each nonceKey
runs in its own lane — parallel to other keys.
Within the same nonceKey
, the nonce auto-increments to preserve sequential ordering.
1. Create Smart Account Client
const smartAccountClient = createSmartAccountClient({
account: await toStartaleSmartAccount({
signer: signer,
chain,
transport: http(),
index: BigInt(106910),
}),
transport: http(bundlerUrl),
client: publicClient,
paymaster: scsPaymasterClient,
paymasterContext: scsContext,
});
2. Generate nonces with different keys
Use arbitrary numbers, user-based hashes, or string-based IDs to define your nonceKey.
const myNonce1 = await smartAccountClient.account.getNonce({
key: 1n, // lane 1
});
const myNonce2 = await smartAccountClient.account.getNonce({
key: 2n, // lane 2
});
3. Send UserOps with Different Nonce Keys
const hash1 = smartAccountClient.sendUserOperation({
calls: [...],
nonce: myNonce1, // from key: 1
});
const hash2 = smartAccountClient.sendUserOperation({
calls: [...],
nonce: myNonce2, // from key: 2
});
Result
Result
- UserOp A →
nonce key: 1
,nonce: 0
- UserOp B →
nonce key: 2
,nonce: 0
These will execute in parallel, even if submitted at the same time.