@nevermined-io/core-kit 0.4.5 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/Instantiable.abstract.js +15 -13
  2. package/dist/Instantiable.abstract.js.map +1 -0
  3. package/dist/artifacts/generated.d.ts +174 -40
  4. package/dist/artifacts/generated.d.ts.map +1 -1
  5. package/dist/artifacts/generated.js +22805 -7111
  6. package/dist/artifacts/generated.js.map +1 -0
  7. package/dist/contracts/AccessManager.js +12 -3
  8. package/dist/contracts/AccessManager.js.map +1 -0
  9. package/dist/contracts/AssetRegistry.d.ts +1 -0
  10. package/dist/contracts/AssetRegistry.d.ts.map +1 -1
  11. package/dist/contracts/AssetRegistry.js +134 -69
  12. package/dist/contracts/AssetRegistry.js.map +1 -0
  13. package/dist/contracts/ContractBase.d.ts.map +1 -1
  14. package/dist/contracts/ContractBase.js +173 -140
  15. package/dist/contracts/ContractBase.js.map +1 -0
  16. package/dist/contracts/ContractsApi.js +6 -54
  17. package/dist/contracts/ContractsApi.js.map +1 -0
  18. package/dist/contracts/CryptoTemplateBase.js +23 -11
  19. package/dist/contracts/CryptoTemplateBase.js.map +1 -0
  20. package/dist/contracts/FiatPaymentTemplate.js +9 -1
  21. package/dist/contracts/FiatPaymentTemplate.js.map +1 -0
  22. package/dist/contracts/FiatSettlementCondition.js +8 -1
  23. package/dist/contracts/FiatSettlementCondition.js.map +1 -0
  24. package/dist/contracts/FixedPaymentTemplate.js +42 -10
  25. package/dist/contracts/FixedPaymentTemplate.js.map +1 -0
  26. package/dist/contracts/NFT1155Base.js +48 -12
  27. package/dist/contracts/NFT1155Base.js.map +1 -0
  28. package/dist/contracts/NFT1155Credits.js +2 -0
  29. package/dist/contracts/NFT1155Credits.js.map +1 -0
  30. package/dist/contracts/NFT1155ExpirableCredits.js +26 -6
  31. package/dist/contracts/NFT1155ExpirableCredits.js.map +1 -0
  32. package/dist/contracts/NVMConfig.js +2 -0
  33. package/dist/contracts/NVMConfig.js.map +1 -0
  34. package/dist/contracts/PayAsYouGoTemplate.js +36 -10
  35. package/dist/contracts/PayAsYouGoTemplate.js.map +1 -0
  36. package/dist/contracts/ProtocolStandardFees.js +7 -1
  37. package/dist/contracts/ProtocolStandardFees.js.map +1 -0
  38. package/dist/contracts/Roles.js +2 -0
  39. package/dist/contracts/Roles.js.map +1 -0
  40. package/dist/contracts/index.js +2 -0
  41. package/dist/contracts/index.js.map +1 -0
  42. package/dist/errors/NeverminedErrors.js +27 -26
  43. package/dist/errors/NeverminedErrors.js.map +1 -0
  44. package/dist/errors/index.js +2 -0
  45. package/dist/errors/index.js.map +1 -0
  46. package/dist/index.js +2 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/models/AgentX402AccessToken.js +78 -46
  49. package/dist/models/AgentX402AccessToken.js.map +1 -0
  50. package/dist/models/Logger.js +12 -12
  51. package/dist/models/Logger.js.map +1 -0
  52. package/dist/models/NeverminedOptions.d.ts +3 -3
  53. package/dist/models/NeverminedOptions.d.ts.map +1 -1
  54. package/dist/models/NeverminedOptions.js +3 -28
  55. package/dist/models/NeverminedOptions.js.map +1 -0
  56. package/dist/models/NvmApiKey.js +96 -147
  57. package/dist/models/NvmApiKey.js.map +1 -0
  58. package/dist/models/Transactions.js +3 -1
  59. package/dist/models/Transactions.js.map +1 -0
  60. package/dist/models/index.js +2 -0
  61. package/dist/models/index.js.map +1 -0
  62. package/dist/nevermined/Nevermined.js +20 -42
  63. package/dist/nevermined/Nevermined.js.map +1 -0
  64. package/dist/nevermined/api/PaymentsApi.js +38 -43
  65. package/dist/nevermined/api/PaymentsApi.js.map +1 -0
  66. package/dist/nevermined/api/ServicesApi.js +7 -15
  67. package/dist/nevermined/api/ServicesApi.js.map +1 -0
  68. package/dist/nevermined/api/UtilsApi.js +7 -19
  69. package/dist/nevermined/api/UtilsApi.js.map +1 -0
  70. package/dist/nevermined/index.js +2 -0
  71. package/dist/nevermined/index.js.map +1 -0
  72. package/dist/nevermined/utils/AgentUtils.js +25 -23
  73. package/dist/nevermined/utils/AgentUtils.js.map +1 -0
  74. package/dist/nevermined/utils/AnvilHelpers.js +34 -19
  75. package/dist/nevermined/utils/AnvilHelpers.js.map +1 -0
  76. package/dist/nevermined/utils/BlockchainViemUtils.d.ts +4 -4
  77. package/dist/nevermined/utils/BlockchainViemUtils.js +102 -108
  78. package/dist/nevermined/utils/BlockchainViemUtils.js.map +1 -0
  79. package/dist/nevermined/utils/JwtUtils.js +33 -28
  80. package/dist/nevermined/utils/JwtUtils.js.map +1 -0
  81. package/dist/nevermined/utils/SignatureUtils.js +23 -27
  82. package/dist/nevermined/utils/SignatureUtils.js.map +1 -0
  83. package/dist/nevermined/utils/WebServiceConnector.js +18 -20
  84. package/dist/nevermined/utils/WebServiceConnector.js.map +1 -0
  85. package/dist/nevermined/utils/ZeroDevPolicies.js +115 -75
  86. package/dist/nevermined/utils/ZeroDevPolicies.js.map +1 -0
  87. package/dist/nevermined/utils/index.js +2 -0
  88. package/dist/nevermined/utils/index.js.map +1 -0
  89. package/dist/services/Api.js +11 -5
  90. package/dist/services/Api.js.map +1 -0
  91. package/dist/services/Profiles.js +15 -20
  92. package/dist/services/Profiles.js.map +1 -0
  93. package/dist/services/index.js +2 -0
  94. package/dist/services/index.js.map +1 -0
  95. package/dist/utils/ConversionTypeHelpers.js +13 -6
  96. package/dist/utils/ConversionTypeHelpers.js.map +1 -0
  97. package/dist/utils/DeploymentInfo.js +12 -7
  98. package/dist/utils/DeploymentInfo.js.map +1 -0
  99. package/dist/utils/Network.js +27 -19
  100. package/dist/utils/Network.js.map +1 -0
  101. package/dist/utils/helpers.js +42 -31
  102. package/dist/utils/helpers.js.map +1 -0
  103. package/dist/utils/index.js +2 -0
  104. package/dist/utils/index.js.map +1 -0
  105. package/package.json +17 -1
@@ -1,9 +1,10 @@
1
1
  import { createKernelAccountClient, createZeroDevPaymasterClient } from '@zerodev/sdk';
2
- import { estimateUserOperationFees, getBundlerRpcUrl, getPaymasterRpcUrl, isRelayerMode, } from '../nevermined/utils/BlockchainViemUtils.js';
3
- import { BaseError, ContractFunctionRevertedError, encodeFunctionData, getContract, http, parseAbi, parseEventLogs, } from 'viem';
2
+ import { estimateUserOperationFees, getBundlerRpcUrl, getPaymasterRpcUrl, isRelayerMode } from '../nevermined/utils/BlockchainViemUtils.js';
3
+ import { BaseError, ContractFunctionRevertedError, encodeFunctionData, getContract, http, parseAbi, parseEventLogs } from 'viem';
4
4
  import { ContractsError, ContractSimulationError } from '../errors/index.js';
5
5
  import { Instantiable } from '../Instantiable.abstract.js';
6
6
  import { getInputsOfFunctionFormatted, getTransactionReceipt } from '../nevermined/index.js';
7
+ import { getRandomBigInt } from '../utils/helpers.js';
7
8
  import { getChain } from '../utils/Network.js';
8
9
  /**
9
10
  * When a testnet RPC (Base Sepolia) fails internally, some providers return
@@ -17,23 +18,26 @@ import { getChain } from '../utils/Network.js';
17
18
  * chance to intercept a bogus estimate. We run the estimation ourselves
18
19
  * here, sanity-check the result, and always pass an explicit gas value
19
20
  * into `writeContract` so it doesn't re-query the misbehaving RPC.
20
- */
21
- const GAS_SANITY_THRESHOLD = 25000000n;
22
- const GAS_FALLBACK_CAP = 5000000n;
21
+ */ const GAS_SANITY_THRESHOLD = 25_000_000n;
22
+ const GAS_FALLBACK_CAP = 5_000_000n;
23
+ // EntryPoint v0.7: ZeroDev's `toKernelPluginManager` rejects `customNonceKey > maxUint16`.
24
+ // 16 bits = 65 536 channels — collision probability for the SDK's expected concurrency
25
+ // (k=2–5 parallel sends from one SCA) is negligible (< 0.02 %). High-fan-out callers
26
+ // (k > 50) should consider a per-process monotonic counter instead. See issue #1579.
27
+ const ZERODEV_NONCE_KEY_BITS = 16;
28
+ // Client-side cap on `waitForUserOperationReceipt`. The userOp is already in the bundler
29
+ // mempool when this fires — a client-side timeout does NOT cancel it. Callers that catch
30
+ // the resulting `ContractsError` MUST poll `bundlerClient.getUserOperationReceipt(hash)`
31
+ // before retrying; otherwise a retry can produce a duplicate on-chain op.
32
+ const USEROP_RECEIPT_TIMEOUT_MS = 90_000;
23
33
  function capForBogusEstimate(estimatedGas, logger) {
24
- if (estimatedGas < GAS_SANITY_THRESHOLD)
25
- return estimatedGas;
26
- logger.warn(`Estimated gas (${estimatedGas}) exceeds sanity threshold ` +
27
- `(${GAS_SANITY_THRESHOLD}); overriding with ${GAS_FALLBACK_CAP} to bypass misbehaving RPC estimate.`);
34
+ if (estimatedGas < GAS_SANITY_THRESHOLD) return estimatedGas;
35
+ logger.warn(`Estimated gas (${estimatedGas}) exceeds sanity threshold ` + `(${GAS_SANITY_THRESHOLD}); overriding with ${GAS_FALLBACK_CAP} to bypass misbehaving RPC estimate.`);
28
36
  return GAS_FALLBACK_CAP;
29
37
  }
30
38
  export class ContractBase extends Instantiable {
31
- contractName;
32
- contract;
33
- address;
34
- _zeroDevPaymaster = null;
35
- constructor(contractName, address) {
36
- super();
39
+ constructor(contractName, address){
40
+ super(), this._zeroDevPaymaster = null;
37
41
  this.contractName = contractName;
38
42
  this.address = address;
39
43
  }
@@ -43,21 +47,27 @@ export class ContractBase extends Instantiable {
43
47
  this.contract = getContract({
44
48
  address: contractConfig.address,
45
49
  abi: contractConfig.abi,
46
- client: { public: this.publicClient, wallet: this.walletClient },
50
+ client: {
51
+ public: this.publicClient,
52
+ wallet: this.walletClient
53
+ }
47
54
  });
48
55
  }
49
56
  async call(functionName, args, from) {
50
57
  try {
51
- return (await this.client.public.readContract({
58
+ return await this.client.public.readContract({
52
59
  address: this.address,
53
60
  abi: this.contract.abi,
54
- functionName: parseAbi([functionName]),
61
+ functionName: parseAbi([
62
+ functionName
63
+ ]),
55
64
  args,
56
- ...(from && { account: from }),
57
- }));
58
- //return await this.contract[functionSignature](...args, { from })
59
- }
60
- catch (err) {
65
+ ...from && {
66
+ account: from
67
+ }
68
+ });
69
+ //return await this.contract[functionSignature](...args, { from })
70
+ } catch (err) {
61
71
  throw new ContractsError(`Calling method "${functionName}" on contract "${this.contractName}" failed. Args: ${args} - ${err}`);
62
72
  }
63
73
  }
@@ -66,16 +76,14 @@ export class ContractBase extends Instantiable {
66
76
  if ('transactionHash' in txHash) {
67
77
  // txHash is TransactionReceipt
68
78
  return txHash;
69
- }
70
- else if ('userOpHash' in txHash) {
79
+ } else if ('userOpHash' in txHash) {
71
80
  // txHash is UserOperationReceipt, fetch the actual receipt using the utility function with retry logic
72
81
  const hash = txHash.receipt.transactionHash;
73
82
  return await getTransactionReceipt({
74
83
  txHash: hash,
75
- publicClient: this.client.public,
84
+ publicClient: this.client.public
76
85
  });
77
- }
78
- else {
86
+ } else {
79
87
  throw new Error('Unknown transaction type');
80
88
  }
81
89
  }
@@ -84,23 +92,20 @@ export class ContractBase extends Instantiable {
84
92
  abi: this.contract.abi,
85
93
  logs: txReceipt.logs,
86
94
  eventName,
87
- strict: false,
95
+ strict: false
88
96
  });
89
97
  }
90
98
  async multicall(calls, from, params = {}) {
91
99
  if (from.type === 'local') {
92
100
  this.logger.debug(`Blockchain Multicall using Local account`);
93
101
  return await this.localAccountMulticall(calls, from, params, params.progress);
94
- }
95
- else if (from.type === 'json-rpc') {
102
+ } else if (from.type === 'json-rpc') {
96
103
  this.logger.debug(`Blockchain Multicall using JSON-RPC account`);
97
104
  return await this.localAccountMulticall(calls, from, params, params.progress);
98
- }
99
- else if (from.type === 'smart') {
105
+ } else if (from.type === 'smart') {
100
106
  this.logger.debug(`Blockchain Multicall using ZeroDev account`);
101
107
  return await this.internalMulticallSmartAccount(calls, from, params, params.progress);
102
- }
103
- else {
108
+ } else {
104
109
  throw new ContractsError(`Account not supported`);
105
110
  }
106
111
  }
@@ -108,16 +113,13 @@ export class ContractBase extends Instantiable {
108
113
  if (from.type === 'local') {
109
114
  this.logger.debug(`Simulating calls using Local account`);
110
115
  return await this.localAccountSimulateMulticall(calls, from, params);
111
- }
112
- else if (from.type === 'json-rpc') {
116
+ } else if (from.type === 'json-rpc') {
113
117
  this.logger.debug(`Simulating calls using JSON-RPC account`);
114
118
  return await this.localAccountSimulateMulticall(calls, from, params);
115
- }
116
- else if (from.type === 'smart') {
119
+ } else if (from.type === 'smart') {
117
120
  this.logger.debug(`Simulating calls using Smart Account account`);
118
121
  return await this.internalSimulateMulticallSmartAccount(calls, from, params);
119
- }
120
- else {
122
+ } else {
121
123
  throw new ContractsError(`Account not supported`);
122
124
  }
123
125
  }
@@ -125,16 +127,13 @@ export class ContractBase extends Instantiable {
125
127
  if (from.type === 'local') {
126
128
  this.logger.debug(`Simulating calls using Local account`);
127
129
  return await this.localAccountSimulate(functionName, from, args, params);
128
- }
129
- else if (from.type === 'json-rpc') {
130
+ } else if (from.type === 'json-rpc') {
130
131
  this.logger.debug(`Simulating calls using JSON-RPC account`);
131
132
  return await this.localAccountSimulate(functionName, from, args, params);
132
- }
133
- else if (from.type === 'smart') {
133
+ } else if (from.type === 'smart') {
134
134
  this.logger.debug(`Simulating calls using Smart Account account`);
135
135
  return await this.internalSimulateSmartAccount(functionName, from, args, params);
136
- }
137
- else {
136
+ } else {
138
137
  throw new ContractsError(`Account not supported`);
139
138
  }
140
139
  }
@@ -142,16 +141,13 @@ export class ContractBase extends Instantiable {
142
141
  if (from.type === 'local') {
143
142
  this.logger.debug(`Blockchain Send using Local account with functionName: ${functionName} and following args: ${args}`);
144
143
  return await this.localAccountSend(functionName, from, args, params, params.progress);
145
- }
146
- else if (from.type === 'json-rpc') {
144
+ } else if (from.type === 'json-rpc') {
147
145
  this.logger.debug(`Blockchain Send using JSON-RPC account to ${functionName}`);
148
146
  return await this.localAccountSend(functionName, from, args, params, params.progress);
149
- }
150
- else if (from.type === 'smart') {
147
+ } else if (from.type === 'smart') {
151
148
  this.logger.debug(`Blockchain Send using ZeroDev account`);
152
149
  return await this.internalSendSmartAccount(functionName, from, args, params, params.progress);
153
- }
154
- else {
150
+ } else {
155
151
  throw new ContractsError(`Account not supported`);
156
152
  }
157
153
  }
@@ -162,7 +158,7 @@ export class ContractBase extends Instantiable {
162
158
  args: [],
163
159
  method: '',
164
160
  from: from,
165
- contractAddress: this.address,
161
+ contractAddress: this.address
166
162
  });
167
163
  }
168
164
  const kernelClient = createKernelAccountClient({
@@ -172,26 +168,34 @@ export class ContractBase extends Instantiable {
172
168
  client: this.client.public,
173
169
  ...this.getPaymasterConfig(),
174
170
  userOperation: {
175
- estimateFeesPerGas: async ({ bundlerClient }) => {
171
+ estimateFeesPerGas: async ({ bundlerClient })=>{
176
172
  return estimateUserOperationFees(bundlerClient, this.client.public);
177
- },
178
- },
173
+ }
174
+ }
179
175
  });
180
176
  const encodedCalls = [];
181
- calls.map((call) => {
177
+ calls.map((call)=>{
182
178
  encodedCalls.push({
183
179
  to: call.contractAddress || this.address,
184
180
  value: txparams.value || 0n,
185
181
  data: encodeFunctionData({
186
182
  abi: call.abi,
187
183
  functionName: call.functionName,
188
- args: call.args,
189
- }),
184
+ args: call.args
185
+ })
190
186
  });
191
187
  });
188
+ let userOpHash;
192
189
  try {
193
- const userOpHash = await kernelClient.sendUserOperation({
190
+ // Random nonce key per send so concurrent userOps from the same SCA
191
+ // hit distinct EntryPoint nonce channels instead of colliding on the
192
+ // default `customNonceKey=0n`. See issue #1579.
193
+ const nonce = await from.getNonce({
194
+ key: getRandomBigInt(ZERODEV_NONCE_KEY_BITS)
195
+ });
196
+ userOpHash = await kernelClient.sendUserOperation({
194
197
  callData: await kernelClient.account.encodeCalls(encodedCalls),
198
+ nonce
195
199
  });
196
200
  if (progress) {
197
201
  progress({
@@ -199,31 +203,33 @@ export class ContractBase extends Instantiable {
199
203
  args: [],
200
204
  method: '',
201
205
  from: from,
202
- contractAddress: this.address,
206
+ contractAddress: this.address
203
207
  });
204
208
  }
205
209
  // Wait for the transaction to be mined
206
210
  this.logger.debug(`Waiting for transaction to be mined... ${userOpHash}`);
207
- const txReceipt = await kernelClient.waitForUserOperationReceipt({ hash: userOpHash });
211
+ const txReceipt = await kernelClient.waitForUserOperationReceipt({
212
+ hash: userOpHash,
213
+ timeout: USEROP_RECEIPT_TIMEOUT_MS
214
+ });
208
215
  this.logger.debug(`Transaction mined - UserOperationHash: ${userOpHash}`);
209
216
  this.logger.debug(`Transaction receipt - TransactionHash: ${txReceipt.receipt.transactionHash}`);
210
217
  this.assertUserOpSucceeded(txReceipt, 'multicall', userOpHash);
211
218
  return txReceipt.receipt;
212
- }
213
- catch (err) {
219
+ } catch (err) {
214
220
  if (err instanceof BaseError) {
215
- const revertError = err.walk((err) => err instanceof ContractFunctionRevertedError);
221
+ const revertError = err.walk((err)=>err instanceof ContractFunctionRevertedError);
216
222
  this.logger.error(`revertError: ${String(revertError)}`);
217
223
  }
218
- throw new ContractsError(`Multicall failed: ${err}`);
224
+ // Surface userOpHash so callers can poll for eventual inclusion before
225
+ // retrying — a client-side receipt-wait timeout does NOT cancel the userOp.
226
+ const hashSuffix = userOpHash ? ` userOpHash=${userOpHash}` : '';
227
+ throw new ContractsError(`Multicall failed:${hashSuffix} ${err}`);
219
228
  }
220
229
  }
221
230
  assertUserOpSucceeded(txReceipt, method, userOpHash) {
222
- if (txReceipt.success)
223
- return;
224
- throw new ContractsError(`UserOp inner call reverted for "${method}" on "${this.contractName}". ` +
225
- `userOpHash=${userOpHash} txHash=${txReceipt.receipt.transactionHash} ` +
226
- `reason=${txReceipt.reason ?? 'unknown'}`);
231
+ if (txReceipt.success) return;
232
+ throw new ContractsError(`UserOp inner call reverted for "${method}" on "${this.contractName}". ` + `userOpHash=${userOpHash} txHash=${txReceipt.receipt.transactionHash} ` + `reason=${txReceipt.reason ?? 'unknown'}`);
227
233
  }
228
234
  async internalSendSmartAccount(name, from, args, txparams, progress) {
229
235
  const functionInputs = getInputsOfFunctionFormatted(this.contract.abi, name, args);
@@ -237,7 +243,7 @@ export class ContractBase extends Instantiable {
237
243
  value,
238
244
  contractName: this.contractName,
239
245
  contractAddress: this.address,
240
- gasLimit,
246
+ gasLimit
241
247
  });
242
248
  }
243
249
  try {
@@ -247,12 +253,13 @@ export class ContractBase extends Instantiable {
247
253
  functionName: name,
248
254
  args,
249
255
  account: from,
250
- ...(txparams.value && { value: txparams.value }),
256
+ ...txparams.value && {
257
+ value: txparams.value
258
+ }
251
259
  });
252
- }
253
- catch (err) {
260
+ } catch (err) {
254
261
  if (err instanceof BaseError) {
255
- const revertError = err.walk((err) => err instanceof ContractFunctionRevertedError);
262
+ const revertError = err.walk((err)=>err instanceof ContractFunctionRevertedError);
256
263
  this.logger.error(`revertError: ${String(revertError)}`);
257
264
  }
258
265
  throw new ContractsError(`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args} - ${err}`);
@@ -264,27 +271,37 @@ export class ContractBase extends Instantiable {
264
271
  client: this.client.public,
265
272
  ...this.getPaymasterConfig(),
266
273
  userOperation: {
267
- estimateFeesPerGas: async ({ bundlerClient }) => {
274
+ estimateFeesPerGas: async ({ bundlerClient })=>{
268
275
  return estimateUserOperationFees(bundlerClient, this.client.public);
269
- },
270
- },
276
+ }
277
+ }
278
+ });
279
+ const data = encodeFunctionData({
280
+ abi: this.contract.abi,
281
+ functionName: name,
282
+ args
271
283
  });
272
- const data = encodeFunctionData({ abi: this.contract.abi, functionName: name, args });
273
284
  let userOpHash;
274
285
  try {
286
+ // Random nonce key per send so concurrent userOps from the same SCA
287
+ // hit distinct EntryPoint nonce channels instead of colliding on the
288
+ // default `customNonceKey=0n`. See issue #1579.
289
+ const nonce = await from.getNonce({
290
+ key: getRandomBigInt(ZERODEV_NONCE_KEY_BITS)
291
+ });
275
292
  userOpHash = await kernelClient.sendUserOperation({
276
293
  callData: await kernelClient.account.encodeCalls([
277
294
  {
278
295
  to: this.address,
279
296
  value: txparams.value || 0n,
280
- data,
281
- },
297
+ data
298
+ }
282
299
  ]),
300
+ nonce
283
301
  });
284
- }
285
- catch (err) {
302
+ } catch (err) {
286
303
  if (err instanceof BaseError) {
287
- const revertError = err.walk((err) => err instanceof ContractFunctionRevertedError);
304
+ const revertError = err.walk((err)=>err instanceof ContractFunctionRevertedError);
288
305
  this.logger.error(`revertError: ${String(revertError)}`);
289
306
  }
290
307
  throw new ContractsError(`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args} - ${err}`);
@@ -299,10 +316,22 @@ export class ContractBase extends Instantiable {
299
316
  value,
300
317
  contractName: this.contractName,
301
318
  contractAddress: this.address,
302
- gasLimit,
319
+ gasLimit
320
+ });
321
+ }
322
+ let txReceipt;
323
+ try {
324
+ txReceipt = await kernelClient.waitForUserOperationReceipt({
325
+ hash: userOpHash,
326
+ timeout: USEROP_RECEIPT_TIMEOUT_MS
303
327
  });
328
+ } catch (err) {
329
+ // The userOp is already in the bundler mempool — a client-side timeout
330
+ // does NOT cancel it. Surface userOpHash so callers can poll for eventual
331
+ // inclusion before retrying, otherwise a retry can produce a duplicate
332
+ // on-chain op. Wrap symmetric to `internalMulticallSmartAccount`.
333
+ throw new ContractsError(`Calling method "${name}" on contract "${this.contractName}" timed out ` + `waiting for UserOp receipt. userOpHash=${userOpHash} — confirm on-chain ` + `inclusion before retrying. Underlying: ${err}`);
304
334
  }
305
- const txReceipt = await kernelClient.waitForUserOperationReceipt({ hash: userOpHash });
306
335
  this.assertUserOpSucceeded(txReceipt, name, userOpHash);
307
336
  if (progress) {
308
337
  progress({
@@ -314,7 +343,7 @@ export class ContractBase extends Instantiable {
314
343
  value,
315
344
  contractName: this.contractName,
316
345
  contractAddress: this.address,
317
- gasLimit,
346
+ gasLimit
318
347
  });
319
348
  }
320
349
  return txReceipt;
@@ -327,11 +356,12 @@ export class ContractBase extends Instantiable {
327
356
  functionName: name,
328
357
  args,
329
358
  account: from.address,
330
- ...(txparams.value && { value: txparams.value }),
359
+ ...txparams.value && {
360
+ value: txparams.value
361
+ }
331
362
  });
332
363
  return true;
333
- }
334
- catch (err) {
364
+ } catch (err) {
335
365
  throw new ContractSimulationError(`Error Simulating contract call "${name}" on contract "${this.contractName}" failed. Args: ${args} - ${err}`);
336
366
  }
337
367
  }
@@ -343,10 +373,11 @@ export class ContractBase extends Instantiable {
343
373
  functionName: name,
344
374
  args,
345
375
  account: from,
346
- ...(txparams.value && { value: txparams.value }),
376
+ ...txparams.value && {
377
+ value: txparams.value
378
+ }
347
379
  });
348
- }
349
- catch (err) {
380
+ } catch (err) {
350
381
  throw new ContractSimulationError(`Error Simulating contract call "${name}" on contract "${this.contractName}" failed. Args: ${args} - ${err}`);
351
382
  }
352
383
  return true;
@@ -384,7 +415,7 @@ export class ContractBase extends Instantiable {
384
415
  value,
385
416
  contractName,
386
417
  contractAddress,
387
- gasLimit,
418
+ gasLimit
388
419
  });
389
420
  }
390
421
  let txHash;
@@ -395,7 +426,9 @@ export class ContractBase extends Instantiable {
395
426
  functionName: name,
396
427
  args,
397
428
  account: from,
398
- ...(txparams.value && { value: txparams.value }),
429
+ ...txparams.value && {
430
+ value: txparams.value
431
+ }
399
432
  });
400
433
  // Resolve gas ourselves so `writeContract` never falls back to its own
401
434
  // `eth_estimateGas`. An explicit caller `gasLimit` always wins; otherwise
@@ -410,25 +443,24 @@ export class ContractBase extends Instantiable {
410
443
  functionName: name,
411
444
  args,
412
445
  account: from,
413
- ...(txparams.value && { value: txparams.value }),
446
+ ...txparams.value && {
447
+ value: txparams.value
448
+ }
414
449
  });
415
450
  resolvedGas = capForBogusEstimate(estimate, this.logger);
416
- }
417
- catch (estErr) {
418
- this.logger.warn(`estimateContractGas for "${name}" on "${contractName}" failed (${estErr}); ` +
419
- `falling back to ${GAS_FALLBACK_CAP} to avoid a bogus RPC re-estimate in writeContract.`);
451
+ } catch (estErr) {
452
+ this.logger.warn(`estimateContractGas for "${name}" on "${contractName}" failed (${estErr}); ` + `falling back to ${GAS_FALLBACK_CAP} to avoid a bogus RPC re-estimate in writeContract.`);
420
453
  resolvedGas = GAS_FALLBACK_CAP;
421
454
  }
422
455
  }
423
456
  txHash = await this.client.wallet.writeContract({
424
457
  ...request,
425
458
  account: from,
426
- gas: resolvedGas,
459
+ gas: resolvedGas
427
460
  });
428
- }
429
- catch (err) {
461
+ } catch (err) {
430
462
  if (err instanceof BaseError) {
431
- const revertError = err.walk((err) => err instanceof ContractFunctionRevertedError);
463
+ const revertError = err.walk((err)=>err instanceof ContractFunctionRevertedError);
432
464
  this.logger.error(`revertError: ${String(revertError)}`);
433
465
  }
434
466
  throw new ContractsError(`Calling method "${name}" on contract "${contractName}" failed. Args: ${args} - ${err}`);
@@ -443,10 +475,13 @@ export class ContractBase extends Instantiable {
443
475
  value,
444
476
  contractName,
445
477
  contractAddress,
446
- gasLimit,
478
+ gasLimit
447
479
  });
448
480
  }
449
- const txReceipt = getTransactionReceipt({ txHash, publicClient: this.client.public });
481
+ const txReceipt = getTransactionReceipt({
482
+ txHash,
483
+ publicClient: this.client.public
484
+ });
450
485
  if (progress) {
451
486
  progress({
452
487
  stage: 'receipt',
@@ -457,33 +492,30 @@ export class ContractBase extends Instantiable {
457
492
  value,
458
493
  contractName,
459
494
  contractAddress,
460
- gasLimit,
495
+ gasLimit
461
496
  });
462
497
  }
463
498
  return txReceipt;
464
499
  }
465
500
  async localAccountMulticall(calls, from, txparams, progress) {
466
501
  const receipts = [];
467
- for (const call of calls) {
502
+ for (const call of calls){
468
503
  receipts.push(await this.localAccountSend(call.functionName, from, call.args, txparams, progress, call.abi, call.contractAddress, call.contractName));
469
504
  }
470
- if (receipts.length > 0)
471
- return receipts.pop();
472
- else
473
- throw new ContractsError(`No receipts found for multicall`);
505
+ if (receipts.length > 0) return receipts.pop();
506
+ else throw new ContractsError(`No receipts found for multicall`);
474
507
  }
475
508
  async localAccountSimulateMulticall(calls, from, txparams) {
476
509
  try {
477
510
  const { results } = await this.client.public.simulateCalls({
478
511
  calls,
479
- account: from,
512
+ account: from
480
513
  });
481
514
  this.logger.debug(`Simulated multicall - ${results}`);
482
515
  return true;
483
- }
484
- catch (err) {
516
+ } catch (err) {
485
517
  if (err instanceof BaseError) {
486
- const revertError = err.walk((err) => err instanceof ContractFunctionRevertedError);
518
+ const revertError = err.walk((err)=>err instanceof ContractFunctionRevertedError);
487
519
  this.logger.error(`revertError: ${String(revertError)}`);
488
520
  }
489
521
  throw new ContractsError(`Error simulating multicall - ${err}`);
@@ -498,21 +530,21 @@ export class ContractBase extends Instantiable {
498
530
  client: this.client.public,
499
531
  ...this.getPaymasterConfig(),
500
532
  userOperation: {
501
- estimateFeesPerGas: async ({ bundlerClient }) => {
533
+ estimateFeesPerGas: async ({ bundlerClient })=>{
502
534
  return estimateUserOperationFees(bundlerClient, this.client.public);
503
- },
504
- },
535
+ }
536
+ }
505
537
  });
506
538
  const encodedCalls = [];
507
- for (const call of calls) {
539
+ for (const call of calls){
508
540
  encodedCalls.push({
509
541
  to: call.to,
510
542
  value: call.value || 0n,
511
543
  data: encodeFunctionData({
512
544
  abi: call.abi,
513
545
  functionName: call.functionName,
514
- args: call.args,
515
- }),
546
+ args: call.args
547
+ })
516
548
  });
517
549
  }
518
550
  // DONT DELETE THE COMMENTED LINES - ARE NECESSARY FOR F***ING ZERODEV DEBUGGING
@@ -529,14 +561,13 @@ export class ContractBase extends Instantiable {
529
561
  // this.logger.info(`Call ${index}: to=${call.to}, value=${call.value}, data=${call.data.slice(0, 10)}...`)
530
562
  // })
531
563
  await kernelClient.prepareUserOperation({
532
- callData: await kernelClient.account.encodeCalls(encodedCalls),
564
+ callData: await kernelClient.account.encodeCalls(encodedCalls)
533
565
  });
534
566
  return true;
535
- }
536
- catch (err) {
567
+ } catch (err) {
537
568
  this.logger.error(`Error details: ${JSON.stringify(err, null, 2)}`);
538
569
  if (err instanceof BaseError) {
539
- const revertError = err.walk((e) => e instanceof ContractFunctionRevertedError);
570
+ const revertError = err.walk((e)=>e instanceof ContractFunctionRevertedError);
540
571
  if (revertError) {
541
572
  this.logger.error(`Revert error: ${String(revertError)}`);
542
573
  }
@@ -548,26 +579,26 @@ export class ContractBase extends Instantiable {
548
579
  if (!this._zeroDevPaymaster) {
549
580
  this._zeroDevPaymaster = createZeroDevPaymasterClient({
550
581
  chain: getChain(this.config.chainId),
551
- transport: http(this.getPaymasterRPC()),
582
+ transport: http(this.getPaymasterRPC())
552
583
  });
553
584
  }
554
585
  return this._zeroDevPaymaster;
555
586
  }
556
587
  /**
557
- * Builds the `paymaster` partial for `createKernelAccountClient`. In relayer
558
- * mode (e.g. local `ultra-relay` for tests) returns an empty object so the
559
- * kernel client submits UserOps without paymaster fields and the bundler
560
- * pays gas via its executor key. In production returns the ZeroDev paymaster
561
- * sponsorship callback.
562
- */
563
- getPaymasterConfig() {
564
- if (isRelayerMode())
565
- return {};
588
+ * Builds the `paymaster` partial for `createKernelAccountClient`. In relayer
589
+ * mode (e.g. local `ultra-relay` for tests) returns an empty object so the
590
+ * kernel client submits UserOps without paymaster fields and the bundler
591
+ * pays gas via its executor key. In production returns the ZeroDev paymaster
592
+ * sponsorship callback.
593
+ */ getPaymasterConfig() {
594
+ if (isRelayerMode()) return {};
566
595
  const zerodevPaymaster = this.getOrCreatePaymaster();
567
596
  return {
568
597
  paymaster: {
569
- getPaymasterData: (userOperation) => zerodevPaymaster.sponsorUserOperation({ userOperation }),
570
- },
598
+ getPaymasterData: (userOperation)=>zerodevPaymaster.sponsorUserOperation({
599
+ userOperation
600
+ })
601
+ }
571
602
  };
572
603
  }
573
604
  getBundlerRPC() {
@@ -592,3 +623,5 @@ export class ContractBase extends Instantiable {
592
623
  return getPaymasterRpcUrl(projectId, this.config.chainId);
593
624
  }
594
625
  }
626
+
627
+ //# sourceMappingURL=ContractBase.js.map