@@ -27,6 +27,7 @@ import type { BundlerOptions } from "../../../smart/types.js";
2727import { getDefaultBundlerUrl } from "../../../smart/lib/constants.js" ;
2828import { getClientFetch } from "../../../../utils/fetch.js" ;
2929import { stringify } from "../../../../utils/json.js" ;
30+ import { withCache } from "../../../../utils/promise/withCache.js" ;
3031
3132interface DelegationContractResponse {
3233 id : string ;
@@ -36,10 +37,6 @@ interface DelegationContractResponse {
3637 } ;
3738}
3839
39- // Cache for delegation contract address to avoid repeated requests
40- let cachedDelegationContract : string | null = null ;
41- let cachePromise : Promise < string > | null = null ;
42-
4340/**
4441 * Fetches the delegation contract address from the bundler using the tw_getDelegationContract RPC method
4542 * @internal
@@ -49,68 +46,54 @@ async function getDelegationContractAddress(args: {
4946 chain : Chain ;
5047 bundlerUrl ?: string ;
5148} ) : Promise < string > {
52- // Return cached result if available
53- if ( cachedDelegationContract ) {
54- return cachedDelegationContract ;
55- }
56-
57- // If there's already a request in progress, wait for it
58- if ( cachePromise ) {
59- return cachePromise ;
60- }
61-
62- // Create the promise and cache it
63- cachePromise = ( async ( ) => {
64- const { client, chain, bundlerUrl } = args ;
65- const url = bundlerUrl ?? getDefaultBundlerUrl ( chain ) ;
66- const fetchWithHeaders = getClientFetch ( client ) ;
49+ const { client, chain, bundlerUrl } = args ;
50+ const url = bundlerUrl ?? getDefaultBundlerUrl ( chain ) ;
51+
52+ // Create a cache key based on the bundler URL to ensure we cache per chain/bundler
53+ const cacheKey = `delegation-contract:${ url } ` ;
54+
55+ return withCache (
56+ async ( ) => {
57+ const fetchWithHeaders = getClientFetch ( client ) ;
6758
68- const response = await fetchWithHeaders ( url , {
69- useAuthToken : true ,
70- body : stringify ( {
71- id : 1 ,
72- jsonrpc : "2.0" ,
73- method : "tw_getDelegationContract" ,
74- params : [ ] ,
75- } ) ,
76- headers : {
77- "Content-Type" : "application/json" ,
78- } ,
79- method : "POST" ,
80- } ) ;
81-
82- if ( ! response . ok ) {
83- throw new Error (
84- `Failed to fetch delegation contract: ${ response . status } ${ response . statusText } ` ,
85- ) ;
86- }
59+ const response = await fetchWithHeaders ( url , {
60+ useAuthToken : true ,
61+ body : stringify ( {
62+ id : 1 ,
63+ jsonrpc : "2.0" ,
64+ method : "tw_getDelegationContract" ,
65+ params : [ ] ,
66+ } ) ,
67+ headers : {
68+ "Content-Type" : "application/json" ,
69+ } ,
70+ method : "POST" ,
71+ } ) ;
8772
88- const result : DelegationContractResponse = await response . json ( ) ;
89-
90- if ( ( result as any ) . error ) {
91- throw new Error (
92- `Delegation contract RPC error: ${ JSON . stringify ( ( result as any ) . error ) } ` ,
93- ) ;
94- }
73+ if ( ! response . ok ) {
74+ throw new Error (
75+ `Failed to fetch delegation contract: ${ response . status } ${ response . statusText } ` ,
76+ ) ;
77+ }
9578
96- if ( ! result . result ?. delegationContract ) {
97- throw new Error (
98- "Invalid response: missing delegationContract in result" ,
99- ) ;
100- }
79+ const result : DelegationContractResponse = await response . json ( ) ;
80+
81+ if ( ( result as any ) . error ) {
82+ throw new Error (
83+ `Delegation contract RPC error: ${ JSON . stringify ( ( result as any ) . error ) } ` ,
84+ ) ;
85+ }
10186
102- // Cache the result
103- cachedDelegationContract = result . result . delegationContract ;
104- return cachedDelegationContract ;
105- } ) ( ) ;
87+ if ( ! result . result ?. delegationContract ) {
88+ throw new Error (
89+ "Invalid response: missing delegationContract in result" ,
90+ ) ;
91+ }
10692
107- try {
108- const result = await cachePromise ;
109- return result ;
110- } finally {
111- // Clear the promise cache after completion (success or failure)
112- cachePromise = null ;
113- }
93+ return result . result . delegationContract ;
94+ } ,
95+ { cacheKey }
96+ ) ;
11497}
11598
11699
0 commit comments