viem 2.14.1 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/_cjs/accounts/hdKeyToAccount.js +2 -2
  3. package/_cjs/accounts/hdKeyToAccount.js.map +1 -1
  4. package/_cjs/accounts/index.js +4 -1
  5. package/_cjs/accounts/index.js.map +1 -1
  6. package/_cjs/accounts/mnemonicToAccount.js.map +1 -1
  7. package/_cjs/accounts/privateKeyToAccount.js +3 -1
  8. package/_cjs/accounts/privateKeyToAccount.js.map +1 -1
  9. package/_cjs/accounts/toAccount.js +1 -0
  10. package/_cjs/accounts/toAccount.js.map +1 -1
  11. package/_cjs/actions/public/getBlock.js +2 -2
  12. package/_cjs/actions/public/getBlock.js.map +1 -1
  13. package/_cjs/actions/public/getBlockTransactionCount.js +2 -2
  14. package/_cjs/actions/public/getBlockTransactionCount.js.map +1 -1
  15. package/_cjs/actions/public/getChainId.js +1 -1
  16. package/_cjs/actions/public/getChainId.js.map +1 -1
  17. package/_cjs/actions/public/getCode.js +1 -1
  18. package/_cjs/actions/public/getCode.js.map +1 -1
  19. package/_cjs/actions/public/getFeeHistory.js +1 -1
  20. package/_cjs/actions/public/getFeeHistory.js.map +1 -1
  21. package/_cjs/actions/public/getTransaction.js +3 -3
  22. package/_cjs/actions/public/getTransaction.js.map +1 -1
  23. package/_cjs/actions/public/getTransactionConfirmations.js +1 -1
  24. package/_cjs/actions/public/getTransactionCount.js +1 -1
  25. package/_cjs/actions/public/getTransactionCount.js.map +1 -1
  26. package/_cjs/actions/public/getTransactionReceipt.js +1 -1
  27. package/_cjs/actions/public/getTransactionReceipt.js.map +1 -1
  28. package/_cjs/actions/wallet/addChain.js +1 -1
  29. package/_cjs/actions/wallet/addChain.js.map +1 -1
  30. package/_cjs/actions/wallet/getAddresses.js +1 -1
  31. package/_cjs/actions/wallet/getAddresses.js.map +1 -1
  32. package/_cjs/actions/wallet/getPermissions.js +1 -1
  33. package/_cjs/actions/wallet/getPermissions.js.map +1 -1
  34. package/_cjs/actions/wallet/prepareTransactionRequest.js +30 -13
  35. package/_cjs/actions/wallet/prepareTransactionRequest.js.map +1 -1
  36. package/_cjs/actions/wallet/requestAddresses.js +1 -1
  37. package/_cjs/actions/wallet/requestAddresses.js.map +1 -1
  38. package/_cjs/chains/definitions/berachainTestnetbArtio.js +24 -0
  39. package/_cjs/chains/definitions/berachainTestnetbArtio.js.map +1 -0
  40. package/_cjs/chains/definitions/confluxESpace.js +2 -2
  41. package/_cjs/chains/definitions/confluxESpaceTestnet.js +2 -2
  42. package/_cjs/chains/definitions/mode.js +15 -0
  43. package/_cjs/chains/definitions/mode.js.map +1 -1
  44. package/_cjs/chains/index.js +8 -6
  45. package/_cjs/chains/index.js.map +1 -1
  46. package/_cjs/clients/transports/createTransport.js +12 -2
  47. package/_cjs/clients/transports/createTransport.js.map +1 -1
  48. package/_cjs/errors/version.js +1 -1
  49. package/_cjs/experimental/erc7715/actions/issuePermissions.js +1 -1
  50. package/_cjs/experimental/erc7715/actions/issuePermissions.js.map +1 -1
  51. package/_cjs/index.js +4 -1
  52. package/_cjs/index.js.map +1 -1
  53. package/_cjs/nonce/index.js +8 -0
  54. package/_cjs/nonce/index.js.map +1 -0
  55. package/_cjs/utils/buildRequest.js +10 -3
  56. package/_cjs/utils/buildRequest.js.map +1 -1
  57. package/_cjs/utils/index.js +4 -1
  58. package/_cjs/utils/index.js.map +1 -1
  59. package/_cjs/utils/nonceManager.js +73 -0
  60. package/_cjs/utils/nonceManager.js.map +1 -0
  61. package/_cjs/utils/promise/withDedupe.js +16 -0
  62. package/_cjs/utils/promise/withDedupe.js.map +1 -0
  63. package/_esm/accounts/hdKeyToAccount.js +2 -2
  64. package/_esm/accounts/hdKeyToAccount.js.map +1 -1
  65. package/_esm/accounts/index.js +1 -0
  66. package/_esm/accounts/index.js.map +1 -1
  67. package/_esm/accounts/mnemonicToAccount.js.map +1 -1
  68. package/_esm/accounts/privateKeyToAccount.js +3 -1
  69. package/_esm/accounts/privateKeyToAccount.js.map +1 -1
  70. package/_esm/accounts/toAccount.js +1 -0
  71. package/_esm/accounts/toAccount.js.map +1 -1
  72. package/_esm/actions/public/getBlock.js +2 -2
  73. package/_esm/actions/public/getBlock.js.map +1 -1
  74. package/_esm/actions/public/getBlockTransactionCount.js +2 -2
  75. package/_esm/actions/public/getBlockTransactionCount.js.map +1 -1
  76. package/_esm/actions/public/getChainId.js +1 -1
  77. package/_esm/actions/public/getChainId.js.map +1 -1
  78. package/_esm/actions/public/getCode.js +1 -1
  79. package/_esm/actions/public/getCode.js.map +1 -1
  80. package/_esm/actions/public/getFeeHistory.js +1 -1
  81. package/_esm/actions/public/getFeeHistory.js.map +1 -1
  82. package/_esm/actions/public/getTransaction.js +3 -3
  83. package/_esm/actions/public/getTransaction.js.map +1 -1
  84. package/_esm/actions/public/getTransactionConfirmations.js +1 -1
  85. package/_esm/actions/public/getTransactionCount.js +1 -1
  86. package/_esm/actions/public/getTransactionCount.js.map +1 -1
  87. package/_esm/actions/public/getTransactionReceipt.js +1 -1
  88. package/_esm/actions/public/getTransactionReceipt.js.map +1 -1
  89. package/_esm/actions/wallet/addChain.js +1 -1
  90. package/_esm/actions/wallet/addChain.js.map +1 -1
  91. package/_esm/actions/wallet/getAddresses.js +1 -1
  92. package/_esm/actions/wallet/getAddresses.js.map +1 -1
  93. package/_esm/actions/wallet/getPermissions.js +1 -1
  94. package/_esm/actions/wallet/getPermissions.js.map +1 -1
  95. package/_esm/actions/wallet/prepareTransactionRequest.js +31 -14
  96. package/_esm/actions/wallet/prepareTransactionRequest.js.map +1 -1
  97. package/_esm/actions/wallet/requestAddresses.js +1 -1
  98. package/_esm/actions/wallet/requestAddresses.js.map +1 -1
  99. package/_esm/chains/definitions/berachainTestnetbArtio.js +21 -0
  100. package/_esm/chains/definitions/berachainTestnetbArtio.js.map +1 -0
  101. package/_esm/chains/definitions/confluxESpace.js +2 -2
  102. package/_esm/chains/definitions/confluxESpaceTestnet.js +2 -2
  103. package/_esm/chains/definitions/mode.js +15 -0
  104. package/_esm/chains/definitions/mode.js.map +1 -1
  105. package/_esm/chains/index.js +1 -0
  106. package/_esm/chains/index.js.map +1 -1
  107. package/_esm/clients/transports/createTransport.js +12 -2
  108. package/_esm/clients/transports/createTransport.js.map +1 -1
  109. package/_esm/errors/version.js +1 -1
  110. package/_esm/experimental/erc7715/actions/issuePermissions.js +1 -1
  111. package/_esm/experimental/erc7715/actions/issuePermissions.js.map +1 -1
  112. package/_esm/index.js +1 -0
  113. package/_esm/index.js.map +1 -1
  114. package/_esm/nonce/index.js +3 -0
  115. package/_esm/nonce/index.js.map +1 -0
  116. package/_esm/utils/buildRequest.js +10 -3
  117. package/_esm/utils/buildRequest.js.map +1 -1
  118. package/_esm/utils/index.js +1 -0
  119. package/_esm/utils/index.js.map +1 -1
  120. package/_esm/utils/nonceManager.js +84 -0
  121. package/_esm/utils/nonceManager.js.map +1 -0
  122. package/_esm/utils/promise/withDedupe.js +14 -0
  123. package/_esm/utils/promise/withDedupe.js.map +1 -0
  124. package/_types/accounts/hdKeyToAccount.d.ts +3 -2
  125. package/_types/accounts/hdKeyToAccount.d.ts.map +1 -1
  126. package/_types/accounts/index.d.ts +4 -3
  127. package/_types/accounts/index.d.ts.map +1 -1
  128. package/_types/accounts/mnemonicToAccount.d.ts +2 -1
  129. package/_types/accounts/mnemonicToAccount.d.ts.map +1 -1
  130. package/_types/accounts/privateKeyToAccount.d.ts +5 -1
  131. package/_types/accounts/privateKeyToAccount.d.ts.map +1 -1
  132. package/_types/accounts/toAccount.d.ts.map +1 -1
  133. package/_types/accounts/types.d.ts +2 -0
  134. package/_types/accounts/types.d.ts.map +1 -1
  135. package/_types/actions/public/getBlock.d.ts.map +1 -1
  136. package/_types/actions/public/getBlockTransactionCount.d.ts.map +1 -1
  137. package/_types/actions/public/getChainId.d.ts.map +1 -1
  138. package/_types/actions/public/getCode.d.ts.map +1 -1
  139. package/_types/actions/public/getFeeHistory.d.ts.map +1 -1
  140. package/_types/actions/public/getTransaction.d.ts.map +1 -1
  141. package/_types/actions/public/getTransactionCount.d.ts.map +1 -1
  142. package/_types/actions/public/getTransactionReceipt.d.ts.map +1 -1
  143. package/_types/actions/wallet/getAddresses.d.ts.map +1 -1
  144. package/_types/actions/wallet/getPermissions.d.ts.map +1 -1
  145. package/_types/actions/wallet/prepareTransactionRequest.d.ts.map +1 -1
  146. package/_types/chains/definitions/berachainTestnetbArtio.d.ts +35 -0
  147. package/_types/chains/definitions/berachainTestnetbArtio.d.ts.map +1 -0
  148. package/_types/chains/definitions/confluxESpace.d.ts +2 -2
  149. package/_types/chains/definitions/confluxESpaceTestnet.d.ts +2 -2
  150. package/_types/chains/definitions/mode.d.ts +15 -0
  151. package/_types/chains/definitions/mode.d.ts.map +1 -1
  152. package/_types/chains/index.d.ts +1 -0
  153. package/_types/chains/index.d.ts.map +1 -1
  154. package/_types/clients/transports/createTransport.d.ts.map +1 -1
  155. package/_types/errors/version.d.ts +1 -1
  156. package/_types/experimental/erc7715/actions/issuePermissions.d.ts.map +1 -1
  157. package/_types/index.d.ts +1 -0
  158. package/_types/index.d.ts.map +1 -1
  159. package/_types/nonce/index.d.ts +2 -0
  160. package/_types/nonce/index.d.ts.map +1 -0
  161. package/_types/types/eip1193.d.ts +3 -0
  162. package/_types/types/eip1193.d.ts.map +1 -1
  163. package/_types/utils/buildRequest.d.ts.map +1 -1
  164. package/_types/utils/index.d.ts +1 -0
  165. package/_types/utils/index.d.ts.map +1 -1
  166. package/_types/utils/nonceManager.d.ts +51 -0
  167. package/_types/utils/nonceManager.d.ts.map +1 -0
  168. package/_types/utils/promise/withDedupe.d.ts +11 -0
  169. package/_types/utils/promise/withDedupe.d.ts.map +1 -0
  170. package/accounts/hdKeyToAccount.ts +11 -2
  171. package/accounts/index.ts +10 -0
  172. package/accounts/mnemonicToAccount.ts +3 -0
  173. package/accounts/privateKeyToAccount.ts +11 -1
  174. package/accounts/toAccount.ts +1 -0
  175. package/accounts/types.ts +2 -0
  176. package/actions/public/getBlock.ts +14 -8
  177. package/actions/public/getBlockTransactionCount.ts +14 -8
  178. package/actions/public/getChainId.ts +6 -3
  179. package/actions/public/getCode.ts +7 -4
  180. package/actions/public/getFeeHistory.ts +11 -8
  181. package/actions/public/getTransaction.ts +21 -12
  182. package/actions/public/getTransactionConfirmations.ts +1 -1
  183. package/actions/public/getTransactionCount.ts +7 -4
  184. package/actions/public/getTransactionReceipt.ts +7 -4
  185. package/actions/wallet/addChain.ts +1 -1
  186. package/actions/wallet/getAddresses.ts +4 -1
  187. package/actions/wallet/getPermissions.ts +4 -1
  188. package/actions/wallet/prepareTransactionRequest.ts +31 -16
  189. package/actions/wallet/requestAddresses.ts +1 -1
  190. package/chains/definitions/berachainTestnetbArtio.ts +21 -0
  191. package/chains/definitions/confluxESpace.ts +2 -2
  192. package/chains/definitions/confluxESpaceTestnet.ts +2 -2
  193. package/chains/definitions/mode.ts +15 -0
  194. package/chains/index.ts +1 -0
  195. package/clients/transports/createTransport.ts +12 -2
  196. package/errors/version.ts +1 -1
  197. package/experimental/erc7715/actions/issuePermissions.ts +7 -4
  198. package/index.ts +7 -0
  199. package/nonce/index.ts +9 -0
  200. package/nonce/package.json +6 -0
  201. package/package.json +6 -1
  202. package/types/eip1193.ts +4 -0
  203. package/utils/buildRequest.ts +104 -88
  204. package/utils/index.ts +7 -0
  205. package/utils/nonceManager.ts +132 -0
  206. package/utils/promise/withDedupe.ts +21 -0
@@ -55,9 +55,13 @@ import type {
55
55
  EIP1193RequestFn,
56
56
  EIP1193RequestOptions,
57
57
  } from '../types/eip1193.js'
58
+ import { stringToHex } from './encoding/toHex.js'
59
+ import { keccak256 } from './hash/keccak256.js'
58
60
  import type { CreateBatchSchedulerErrorType } from './promise/createBatchScheduler.js'
61
+ import { withDedupe } from './promise/withDedupe.js'
59
62
  import { type WithRetryErrorType, withRetry } from './promise/withRetry.js'
60
63
  import type { GetSocketRpcClientErrorType } from './rpc/socket.js'
64
+ import { stringify } from './stringify.js'
61
65
 
62
66
  export type RequestErrorType =
63
67
  | ChainDisconnectedErrorType
@@ -94,98 +98,110 @@ export function buildRequest<request extends (args: any) => Promise<any>>(
94
98
  options: EIP1193RequestOptions = {},
95
99
  ): EIP1193RequestFn {
96
100
  return async (args, overrideOptions = {}) => {
97
- const { retryDelay = 150, retryCount = 3 } = {
101
+ const {
102
+ dedupe = false,
103
+ retryDelay = 150,
104
+ retryCount = 3,
105
+ uid,
106
+ } = {
98
107
  ...options,
99
108
  ...overrideOptions,
100
109
  }
101
- return withRetry(
102
- async () => {
103
- try {
104
- return await request(args)
105
- } catch (err_) {
106
- const err = err_ as unknown as RpcError<
107
- RpcErrorCode | ProviderRpcErrorCode
108
- >
109
- switch (err.code) {
110
- // -32700
111
- case ParseRpcError.code:
112
- throw new ParseRpcError(err)
113
- // -32600
114
- case InvalidRequestRpcError.code:
115
- throw new InvalidRequestRpcError(err)
116
- // -32601
117
- case MethodNotFoundRpcError.code:
118
- throw new MethodNotFoundRpcError(err)
119
- // -32602
120
- case InvalidParamsRpcError.code:
121
- throw new InvalidParamsRpcError(err)
122
- // -32603
123
- case InternalRpcError.code:
124
- throw new InternalRpcError(err)
125
- // -32000
126
- case InvalidInputRpcError.code:
127
- throw new InvalidInputRpcError(err)
128
- // -32001
129
- case ResourceNotFoundRpcError.code:
130
- throw new ResourceNotFoundRpcError(err)
131
- // -32002
132
- case ResourceUnavailableRpcError.code:
133
- throw new ResourceUnavailableRpcError(err)
134
- // -32003
135
- case TransactionRejectedRpcError.code:
136
- throw new TransactionRejectedRpcError(err)
137
- // -32004
138
- case MethodNotSupportedRpcError.code:
139
- throw new MethodNotSupportedRpcError(err)
140
- // -32005
141
- case LimitExceededRpcError.code:
142
- throw new LimitExceededRpcError(err)
143
- // -32006
144
- case JsonRpcVersionUnsupportedError.code:
145
- throw new JsonRpcVersionUnsupportedError(err)
146
- // 4001
147
- case UserRejectedRequestError.code:
148
- throw new UserRejectedRequestError(err)
149
- // 4100
150
- case UnauthorizedProviderError.code:
151
- throw new UnauthorizedProviderError(err)
152
- // 4200
153
- case UnsupportedProviderMethodError.code:
154
- throw new UnsupportedProviderMethodError(err)
155
- // 4900
156
- case ProviderDisconnectedError.code:
157
- throw new ProviderDisconnectedError(err)
158
- // 4901
159
- case ChainDisconnectedError.code:
160
- throw new ChainDisconnectedError(err)
161
- // 4902
162
- case SwitchChainError.code:
163
- throw new SwitchChainError(err)
164
- // CAIP-25: User Rejected Error
165
- // https://docs.walletconnect.com/2.0/specs/clients/sign/error-codes#rejected-caip-25
166
- case 5000:
167
- throw new UserRejectedRequestError(err)
168
- default:
169
- if (err_ instanceof BaseError) throw err_
170
- throw new UnknownRpcError(err as Error)
171
- }
172
- }
173
- },
174
- {
175
- delay: ({ count, error }) => {
176
- // If we find a Retry-After header, let's retry after the given time.
177
- if (error && error instanceof HttpRequestError) {
178
- const retryAfter = error?.headers?.get('Retry-After')
179
- if (retryAfter?.match(/\d/))
180
- return Number.parseInt(retryAfter) * 1000
181
- }
110
+ const requestId = dedupe
111
+ ? keccak256(stringToHex(`${uid}.${stringify(args)}`))
112
+ : undefined
113
+ return withDedupe(
114
+ () =>
115
+ withRetry(
116
+ async () => {
117
+ try {
118
+ return await request(args)
119
+ } catch (err_) {
120
+ const err = err_ as unknown as RpcError<
121
+ RpcErrorCode | ProviderRpcErrorCode
122
+ >
123
+ switch (err.code) {
124
+ // -32700
125
+ case ParseRpcError.code:
126
+ throw new ParseRpcError(err)
127
+ // -32600
128
+ case InvalidRequestRpcError.code:
129
+ throw new InvalidRequestRpcError(err)
130
+ // -32601
131
+ case MethodNotFoundRpcError.code:
132
+ throw new MethodNotFoundRpcError(err)
133
+ // -32602
134
+ case InvalidParamsRpcError.code:
135
+ throw new InvalidParamsRpcError(err)
136
+ // -32603
137
+ case InternalRpcError.code:
138
+ throw new InternalRpcError(err)
139
+ // -32000
140
+ case InvalidInputRpcError.code:
141
+ throw new InvalidInputRpcError(err)
142
+ // -32001
143
+ case ResourceNotFoundRpcError.code:
144
+ throw new ResourceNotFoundRpcError(err)
145
+ // -32002
146
+ case ResourceUnavailableRpcError.code:
147
+ throw new ResourceUnavailableRpcError(err)
148
+ // -32003
149
+ case TransactionRejectedRpcError.code:
150
+ throw new TransactionRejectedRpcError(err)
151
+ // -32004
152
+ case MethodNotSupportedRpcError.code:
153
+ throw new MethodNotSupportedRpcError(err)
154
+ // -32005
155
+ case LimitExceededRpcError.code:
156
+ throw new LimitExceededRpcError(err)
157
+ // -32006
158
+ case JsonRpcVersionUnsupportedError.code:
159
+ throw new JsonRpcVersionUnsupportedError(err)
160
+ // 4001
161
+ case UserRejectedRequestError.code:
162
+ throw new UserRejectedRequestError(err)
163
+ // 4100
164
+ case UnauthorizedProviderError.code:
165
+ throw new UnauthorizedProviderError(err)
166
+ // 4200
167
+ case UnsupportedProviderMethodError.code:
168
+ throw new UnsupportedProviderMethodError(err)
169
+ // 4900
170
+ case ProviderDisconnectedError.code:
171
+ throw new ProviderDisconnectedError(err)
172
+ // 4901
173
+ case ChainDisconnectedError.code:
174
+ throw new ChainDisconnectedError(err)
175
+ // 4902
176
+ case SwitchChainError.code:
177
+ throw new SwitchChainError(err)
178
+ // CAIP-25: User Rejected Error
179
+ // https://docs.walletconnect.com/2.0/specs/clients/sign/error-codes#rejected-caip-25
180
+ case 5000:
181
+ throw new UserRejectedRequestError(err)
182
+ default:
183
+ if (err_ instanceof BaseError) throw err_
184
+ throw new UnknownRpcError(err as Error)
185
+ }
186
+ }
187
+ },
188
+ {
189
+ delay: ({ count, error }) => {
190
+ // If we find a Retry-After header, let's retry after the given time.
191
+ if (error && error instanceof HttpRequestError) {
192
+ const retryAfter = error?.headers?.get('Retry-After')
193
+ if (retryAfter?.match(/\d/))
194
+ return Number.parseInt(retryAfter) * 1000
195
+ }
182
196
 
183
- // Otherwise, let's retry with an exponential backoff.
184
- return ~~(1 << count) * retryDelay
185
- },
186
- retryCount,
187
- shouldRetry: ({ error }) => shouldRetry(error),
188
- },
197
+ // Otherwise, let's retry with an exponential backoff.
198
+ return ~~(1 << count) * retryDelay
199
+ },
200
+ retryCount,
201
+ shouldRetry: ({ error }) => shouldRetry(error),
202
+ },
203
+ ),
204
+ { enabled: dedupe, id: requestId },
189
205
  )
190
206
  }
191
207
  }
package/utils/index.ts CHANGED
@@ -491,3 +491,10 @@ export { type FormatUnitsErrorType, formatUnits } from './unit/formatUnits.js'
491
491
  export { type ParseUnitsErrorType, parseUnits } from './unit/parseUnits.js'
492
492
  export { type ParseEtherErrorType, parseEther } from './unit/parseEther.js'
493
493
  export { type ParseGweiErrorType, parseGwei } from './unit/parseGwei.js'
494
+ export {
495
+ type CreateNonceManagerParameters,
496
+ type NonceManager,
497
+ type NonceManagerSource,
498
+ createNonceManager,
499
+ nonceManager,
500
+ } from './nonceManager.js'
@@ -0,0 +1,132 @@
1
+ import type { Address } from 'abitype'
2
+
3
+ import { getTransactionCount } from '../actions/public/getTransactionCount.js'
4
+ import type { Client } from '../clients/createClient.js'
5
+ import type { MaybePromise } from '../types/utils.js'
6
+ import { LruMap } from './lru.js'
7
+
8
+ export type CreateNonceManagerParameters = {
9
+ source: NonceManagerSource
10
+ }
11
+
12
+ type FunctionParameters = {
13
+ address: Address
14
+ chainId: number
15
+ }
16
+
17
+ export type NonceManager = {
18
+ /** Get and increment a nonce. */
19
+ consume: (
20
+ parameters: FunctionParameters & { client: Client },
21
+ ) => Promise<number>
22
+ /** Increment a nonce. */
23
+ increment: (chainId: FunctionParameters) => void
24
+ /** Get a nonce. */
25
+ get: (chainId: FunctionParameters & { client: Client }) => Promise<number>
26
+ /** Reset a nonce. */
27
+ reset: (chainId: FunctionParameters) => void
28
+ }
29
+
30
+ /**
31
+ * Creates a nonce manager for auto-incrementing transaction nonces.
32
+ *
33
+ * - Docs: https://viem.sh/docs/accounts/createNonceManager
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const nonceManager = createNonceManager({
38
+ * source: jsonRpc(),
39
+ * })
40
+ * ```
41
+ */
42
+ export function createNonceManager(
43
+ parameters: CreateNonceManagerParameters,
44
+ ): NonceManager {
45
+ const { source } = parameters
46
+
47
+ const deltaMap = new Map()
48
+ const nonceMap = new LruMap<number>(8192)
49
+ const promiseMap = new Map<string, Promise<number>>()
50
+
51
+ const getKey = ({ address, chainId }: FunctionParameters) =>
52
+ `${address}.${chainId}`
53
+
54
+ return {
55
+ async consume({ address, chainId, client }) {
56
+ const key = getKey({ address, chainId })
57
+ const promise = this.get({ address, chainId, client })
58
+
59
+ this.increment({ address, chainId })
60
+ const nonce = await promise
61
+
62
+ await source.set({ address, chainId }, nonce)
63
+ nonceMap.set(key, nonce)
64
+
65
+ return nonce
66
+ },
67
+ async increment({ address, chainId }) {
68
+ const key = getKey({ address, chainId })
69
+ const delta = deltaMap.get(key) ?? 0
70
+ deltaMap.set(key, delta + 1)
71
+ },
72
+ async get({ address, chainId, client }) {
73
+ const key = getKey({ address, chainId })
74
+
75
+ let promise = promiseMap.get(key)
76
+ if (!promise) {
77
+ promise = (async () => {
78
+ try {
79
+ const nonce = await source.get({ address, chainId, client })
80
+ const previousNonce = nonceMap.get(key) ?? 0
81
+ if (nonce <= previousNonce) return previousNonce + 1
82
+ nonceMap.delete(key)
83
+ return nonce
84
+ } finally {
85
+ this.reset({ address, chainId })
86
+ }
87
+ })()
88
+ promiseMap.set(key, promise)
89
+ }
90
+
91
+ const delta = deltaMap.get(key) ?? 0
92
+ return delta + (await promise)
93
+ },
94
+ reset({ address, chainId }) {
95
+ const key = getKey({ address, chainId })
96
+ deltaMap.delete(key)
97
+ promiseMap.delete(key)
98
+ },
99
+ }
100
+ }
101
+
102
+ ////////////////////////////////////////////////////////////////////////////////////////////
103
+ // Sources
104
+
105
+ export type NonceManagerSource = {
106
+ /** Get a nonce. */
107
+ get(parameters: FunctionParameters & { client: Client }): MaybePromise<number>
108
+ /** Set a nonce. */
109
+ set(parameters: FunctionParameters, nonce: number): MaybePromise<void>
110
+ }
111
+
112
+ /** JSON-RPC source for a nonce manager. */
113
+ export function jsonRpc(): NonceManagerSource {
114
+ return {
115
+ async get(parameters) {
116
+ const { address, client } = parameters
117
+ return getTransactionCount(client, {
118
+ address,
119
+ blockTag: 'pending',
120
+ })
121
+ },
122
+ set() {},
123
+ }
124
+ }
125
+
126
+ ////////////////////////////////////////////////////////////////////////////////////////////
127
+ // Default
128
+
129
+ /** Default Nonce Manager with a JSON-RPC source. */
130
+ export const nonceManager = /*#__PURE__*/ createNonceManager({
131
+ source: jsonRpc(),
132
+ })
@@ -0,0 +1,21 @@
1
+ import { LruMap } from '../lru.js'
2
+
3
+ /** @internal */
4
+ export const promiseCache = /*#__PURE__*/ new LruMap<Promise<any>>(8192)
5
+
6
+ type WithDedupeOptions = {
7
+ enabled?: boolean | undefined
8
+ id?: string | undefined
9
+ }
10
+
11
+ /** Deduplicates in-flight promises. */
12
+ export function withDedupe<data>(
13
+ fn: () => Promise<data>,
14
+ { enabled = true, id }: WithDedupeOptions,
15
+ ): Promise<data> {
16
+ if (!enabled || !id) return fn()
17
+ if (promiseCache.get(id)) return promiseCache.get(id)!
18
+ const promise = fn().finally(() => promiseCache.delete(id))
19
+ promiseCache.set(id, promise)
20
+ return promise
21
+ }