@@ -68,6 +68,19 @@ async function getOnchainNonce(account: Address, nonceTrack = 0n): Promise<bigin
6868 return results . nonceValue
6969}
7070
71+ /**
72+ * Resets the nonce to the given value, unless the current local nonce is already lower.
73+ * We call this whenever a boop fails to be included onchain.
74+ */
75+ async function resetNonce ( account : Address , nonceTrack : bigint , nonceValue : bigint ) : Promise < void > {
76+ const mutex = nonceMutexes . getOrSet ( account , nonceTrack , ( ) => new Mutex ( ) )
77+ void mutex . locked ( ( ) => {
78+ const nonce = nonces . get ( account , nonceTrack )
79+ if ( ! nonce || nonce <= nonceValue ) return
80+ nonces . set ( account , nonceTrack , nonceValue )
81+ } )
82+ }
83+
7184/**
7285 * Returns cached nonce.
7386 * Fallback to fetching nonce from the EntryPoint contract.
@@ -95,11 +108,14 @@ export async function sendBoop(
95108 retry = 0 ,
96109) : Promise < Hash > {
97110 let boopHash : Hash | undefined = undefined
98- let needsNonceResync = false
111+ let needsNonceResync = false // resync = delete nonce, next attempt will fetch onchain
112+ let needsNonceReset = false // reset = reset to this boop's nonce (because it failed)
113+ let nonceValue = 0n
99114
100115 try {
101116 const boopClient = getBoopClient ( )
102117 let boop = await boopFromTransaction ( account , tx , app )
118+ nonceValue = boop . nonceValue
103119
104120 let simulation = sim
105121 if ( ! isSponsored ) {
@@ -133,7 +149,10 @@ export async function sendBoop(
133149 // If the nonce is too low and the wallet is assigning it, we'll need a resync.
134150 needsNonceResync = ! tx . nonce && output . status === Onchain . InvalidNonce
135151
136- if ( output . status !== Onchain . Success ) throw translateBoopError ( output )
152+ if ( output . status !== Onchain . Success ) {
153+ needsNonceReset = true
154+ throw translateBoopError ( output )
155+ }
137156 markBoopAsSuccess ( boopHash , output . receipt )
138157 boopCache . putReceipt ( boopHash , output . receipt )
139158 return output . receipt . boopHash
@@ -142,6 +161,8 @@ export async function sendBoop(
142161 if ( needsNonceResync ) {
143162 reqLogger . trace ( "boop nonce resync needed, deleting cached nonce" )
144163 deleteNonce ( account , nonceTrack )
164+ } else if ( needsNonceReset ) {
165+ resetNonce ( account , nonceTrack , nonceValue )
145166 }
146167
147168 // Try one more time if the last attempt failed due to a boop set by the wallet being too low.
0 commit comments