@@ -84,6 +84,11 @@ export class ChainSessionManager {
8484 public loginMethod : LoginMethod | null = null
8585 public userEmail : string | null = null
8686 private guard ?: GuardConfig
87+ private lastSignedCallCache ?: {
88+ fingerprint : string
89+ signedCall : { to : Address . Address ; data : Hex . Hex }
90+ createdAtMs : number
91+ }
8792
8893 /**
8994 * @param chainId The ID of the chain this manager is responsible for.
@@ -851,6 +856,11 @@ export class ChainSessionManager {
851856 } ) )
852857 try {
853858 const signedCall = await this . _buildAndSignCalls ( callsToSend )
859+ this . lastSignedCallCache = {
860+ fingerprint : this . _fingerprintCalls ( callsToSend ) ,
861+ signedCall,
862+ createdAtMs : Date . now ( ) ,
863+ }
854864 const feeOptions = await this . relayer . feeOptions ( signedCall . to , this . chainId , callsToSend )
855865 return feeOptions . options
856866 } catch ( err ) {
@@ -907,7 +917,7 @@ export class ChainSessionManager {
907917 callsToSend . unshift ( transferCall )
908918 }
909919 }
910- const signedCalls = await this . _buildAndSignCalls ( callsToSend )
920+ const signedCalls = this . _getCachedSignedCall ( callsToSend ) ?? ( await this . _buildAndSignCalls ( callsToSend ) )
911921 const hash = await this . relayer . relay ( signedCalls . to , signedCalls . data , this . chainId )
912922 const status = await this . _waitForTransactionReceipt ( hash . opHash , this . chainId )
913923 if ( status . status === 'confirmed' ) {
@@ -1101,4 +1111,42 @@ export class ChainSessionManager {
11011111 await this . sequenceStorage . clearExplicitSessions ( )
11021112 await this . sequenceStorage . clearSessionlessConnection ( )
11031113 }
1114+
1115+ private _getCachedSignedCall ( calls : Payload . Call [ ] ) : { to : Address . Address ; data : Hex . Hex } | null {
1116+ if ( ! this . lastSignedCallCache ) {
1117+ return null
1118+ }
1119+ const ttlMs = 30_000
1120+ if ( Date . now ( ) - this . lastSignedCallCache . createdAtMs > ttlMs ) {
1121+ this . lastSignedCallCache = undefined
1122+ return null
1123+ }
1124+ const fingerprint = this . _fingerprintCalls ( calls )
1125+ if ( ! fingerprint ) {
1126+ return null
1127+ }
1128+ if ( fingerprint !== this . lastSignedCallCache . fingerprint ) {
1129+ return null
1130+ }
1131+ return this . lastSignedCallCache . signedCall
1132+ }
1133+
1134+ private _fingerprintCalls ( calls : Payload . Call [ ] ) : string | null {
1135+ try {
1136+ return JSON . stringify (
1137+ calls . map ( ( call ) => ( {
1138+ to : call . to ,
1139+ value : call . value ?. toString ( ) ?? '0' ,
1140+ data : call . data ?? '0x' ,
1141+ gasLimit : call . gasLimit ?. toString ( ) ?? '0' ,
1142+ delegateCall : call . delegateCall ?? false ,
1143+ onlyFallback : call . onlyFallback ?? false ,
1144+ behaviorOnError : call . behaviorOnError ?? 'revert' ,
1145+ } ) ) ,
1146+ )
1147+ } catch ( error ) {
1148+ console . warn ( 'ChainSessionManager._fingerprintCalls failed:' , error )
1149+ return null
1150+ }
1151+ }
11041152}
0 commit comments