@pushchain/core 6.0.25 → 6.0.27-alpha.0

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 (183) hide show
  1. package/AGW.md +194 -0
  2. package/CHANGELOG.md +74 -0
  3. package/README.md +2 -0
  4. package/package.json +7 -1
  5. package/src/lib/agentic/agentic.d.ts +23 -0
  6. package/src/lib/agentic/agentic.js +51 -0
  7. package/src/lib/agentic/agentic.types.d.ts +409 -0
  8. package/src/lib/agentic/agentic.types.js +3 -0
  9. package/src/lib/agentic/capabilities.d.ts +37 -0
  10. package/src/lib/agentic/capabilities.js +64 -0
  11. package/src/lib/agentic/chain.d.ts +3 -0
  12. package/src/lib/agentic/chain.js +15 -0
  13. package/src/lib/agentic/codec/abi-layout.d.ts +15 -0
  14. package/src/lib/agentic/codec/abi-layout.js +121 -0
  15. package/src/lib/agentic/codec/defaults.d.ts +51 -0
  16. package/src/lib/agentic/codec/defaults.js +53 -0
  17. package/src/lib/agentic/codec/ids.d.ts +35 -0
  18. package/src/lib/agentic/codec/ids.js +74 -0
  19. package/src/lib/agentic/codec/native.d.ts +75 -0
  20. package/src/lib/agentic/codec/native.js +328 -0
  21. package/src/lib/agentic/codec/rules.d.ts +45 -0
  22. package/src/lib/agentic/codec/rules.js +110 -0
  23. package/src/lib/agentic/codec/selectors.d.ts +19 -0
  24. package/src/lib/agentic/codec/selectors.js +60 -0
  25. package/src/lib/agentic/codec/session.d.ts +54 -0
  26. package/src/lib/agentic/codec/session.js +65 -0
  27. package/src/lib/agentic/codec/svm-accounts.d.ts +35 -0
  28. package/src/lib/agentic/codec/svm-accounts.js +68 -0
  29. package/src/lib/agentic/codec/svm-idl.d.ts +11 -0
  30. package/src/lib/agentic/codec/svm-idl.js +226 -0
  31. package/src/lib/agentic/codec/svm-terms.d.ts +157 -0
  32. package/src/lib/agentic/codec/svm-terms.js +242 -0
  33. package/src/lib/agentic/codec/universal-terms.d.ts +67 -0
  34. package/src/lib/agentic/codec/universal-terms.js +41 -0
  35. package/src/lib/agentic/codec/universal.d.ts +14 -0
  36. package/src/lib/agentic/codec/universal.js +157 -0
  37. package/src/lib/agentic/constants.d.ts +11 -0
  38. package/src/lib/agentic/constants.js +15 -0
  39. package/src/lib/agentic/context.d.ts +29 -0
  40. package/src/lib/agentic/context.js +56 -0
  41. package/src/lib/agentic/contracts/abi/v5/agent-validator.d.ts +105 -0
  42. package/src/lib/agentic/contracts/abi/v5/agent-validator.js +149 -0
  43. package/src/lib/agentic/contracts/abi/v5/agw-factory.d.ts +847 -0
  44. package/src/lib/agentic/contracts/abi/v5/agw-factory.js +1108 -0
  45. package/src/lib/agentic/contracts/abi/v5/agw.d.ts +1211 -0
  46. package/src/lib/agentic/contracts/abi/v5/agw.js +1588 -0
  47. package/src/lib/agentic/contracts/abi/v5/index.d.ts +6 -0
  48. package/src/lib/agentic/contracts/abi/v5/index.js +17 -0
  49. package/src/lib/agentic/contracts/abi/v5/smart-session.d.ts +1493 -0
  50. package/src/lib/agentic/contracts/abi/v5/smart-session.js +1965 -0
  51. package/src/lib/agentic/contracts/abi/v5/universal-rules-policy.d.ts +1640 -0
  52. package/src/lib/agentic/contracts/abi/v5/universal-rules-policy.js +2160 -0
  53. package/src/lib/agentic/contracts/donut-v5.d.ts +11 -0
  54. package/src/lib/agentic/contracts/donut-v5.js +15 -0
  55. package/src/lib/agentic/contracts/prc20-metadata.d.ts +26 -0
  56. package/src/lib/agentic/contracts/prc20-metadata.js +87 -0
  57. package/src/lib/agentic/contracts/reader.d.ts +35 -0
  58. package/src/lib/agentic/contracts/reader.js +16 -0
  59. package/src/lib/agentic/contracts/v5.d.ts +5323 -0
  60. package/src/lib/agentic/contracts/v5.js +316 -0
  61. package/src/lib/agentic/deployments.d.ts +61 -0
  62. package/src/lib/agentic/deployments.js +203 -0
  63. package/src/lib/agentic/errors.d.ts +71 -0
  64. package/src/lib/agentic/errors.js +92 -0
  65. package/src/lib/agentic/execution/guards.d.ts +9 -0
  66. package/src/lib/agentic/execution/guards.js +30 -0
  67. package/src/lib/agentic/execution/outbound.d.ts +55 -0
  68. package/src/lib/agentic/execution/outbound.js +187 -0
  69. package/src/lib/agentic/execution/send.d.ts +9 -0
  70. package/src/lib/agentic/execution/send.js +276 -0
  71. package/src/lib/agentic/execution/svm-instruction.d.ts +24 -0
  72. package/src/lib/agentic/execution/svm-instruction.js +40 -0
  73. package/src/lib/agentic/execution/svm-outbound.d.ts +18 -0
  74. package/src/lib/agentic/execution/svm-outbound.js +86 -0
  75. package/src/lib/agentic/execution/svm-payload.d.ts +18 -0
  76. package/src/lib/agentic/execution/svm-payload.js +136 -0
  77. package/src/lib/agentic/execution/svm-public.d.ts +5 -0
  78. package/src/lib/agentic/execution/svm-public.js +182 -0
  79. package/src/lib/agentic/execution/svm-quote.d.ts +11 -0
  80. package/src/lib/agentic/execution/svm-quote.js +24 -0
  81. package/src/lib/agentic/execution/svm-send.d.ts +44 -0
  82. package/src/lib/agentic/execution/svm-send.js +90 -0
  83. package/src/lib/agentic/index.d.ts +5 -0
  84. package/src/lib/agentic/index.js +10 -0
  85. package/src/lib/agentic/management/common.d.ts +29 -0
  86. package/src/lib/agentic/management/common.js +114 -0
  87. package/src/lib/agentic/management/create.d.ts +16 -0
  88. package/src/lib/agentic/management/create.js +271 -0
  89. package/src/lib/agentic/management/duplicates.d.ts +4 -0
  90. package/src/lib/agentic/management/duplicates.js +20 -0
  91. package/src/lib/agentic/management/label.d.ts +3 -0
  92. package/src/lib/agentic/management/label.js +17 -0
  93. package/src/lib/agentic/management/prepare.d.ts +7 -0
  94. package/src/lib/agentic/management/prepare.js +95 -0
  95. package/src/lib/agentic/management/rules-write.d.ts +42 -0
  96. package/src/lib/agentic/management/rules-write.js +279 -0
  97. package/src/lib/agentic/management/svm-context.d.ts +25 -0
  98. package/src/lib/agentic/management/svm-context.js +55 -0
  99. package/src/lib/agentic/management/svm-metadata.d.ts +10 -0
  100. package/src/lib/agentic/management/svm-metadata.js +56 -0
  101. package/src/lib/agentic/management/svm-public.d.ts +6 -0
  102. package/src/lib/agentic/management/svm-public.js +125 -0
  103. package/src/lib/agentic/management/svm.d.ts +27 -0
  104. package/src/lib/agentic/management/svm.js +150 -0
  105. package/src/lib/agentic/presets/catalog.d.ts +21 -0
  106. package/src/lib/agentic/presets/catalog.js +10 -0
  107. package/src/lib/agentic/presets/index.d.ts +5 -0
  108. package/src/lib/agentic/presets/index.js +190 -0
  109. package/src/lib/agentic/presets/types.d.ts +44 -0
  110. package/src/lib/agentic/presets/types.js +3 -0
  111. package/src/lib/agentic/public-rule.d.ts +9 -0
  112. package/src/lib/agentic/public-rule.js +342 -0
  113. package/src/lib/agentic/reads/checkpoints.d.ts +17 -0
  114. package/src/lib/agentic/reads/checkpoints.js +109 -0
  115. package/src/lib/agentic/reads/rules.d.ts +42 -0
  116. package/src/lib/agentic/reads/rules.js +286 -0
  117. package/src/lib/agentic/reads/snapshot.d.ts +28 -0
  118. package/src/lib/agentic/reads/snapshot.js +85 -0
  119. package/src/lib/agentic/reads/svm.d.ts +17 -0
  120. package/src/lib/agentic/reads/svm.js +52 -0
  121. package/src/lib/agentic/reads/wallets.d.ts +25 -0
  122. package/src/lib/agentic/reads/wallets.js +122 -0
  123. package/src/lib/agentic/response.d.ts +41 -0
  124. package/src/lib/agentic/response.js +358 -0
  125. package/src/lib/agentic/revert.d.ts +7 -0
  126. package/src/lib/agentic/revert.js +102 -0
  127. package/src/lib/agentic/runtime.d.ts +58 -0
  128. package/src/lib/agentic/runtime.js +95 -0
  129. package/src/lib/agentic/utils.d.ts +57 -0
  130. package/src/lib/agentic/utils.js +165 -0
  131. package/src/lib/agentic/wallet.d.ts +32 -0
  132. package/src/lib/agentic/wallet.js +130 -0
  133. package/src/lib/constants/chain.js +1 -1
  134. package/src/lib/constants/enums.d.ts +6 -3
  135. package/src/lib/constants/enums.js +6 -3
  136. package/src/lib/constants/index.d.ts +65 -7
  137. package/src/lib/constants/index.js +18 -3
  138. package/src/lib/constants/read-state.d.ts +15 -2
  139. package/src/lib/constants/read-state.js +19 -3
  140. package/src/lib/index.d.ts +9 -3
  141. package/src/lib/index.js +11 -2
  142. package/src/lib/orchestrator/internals/errors.d.ts +7 -0
  143. package/src/lib/orchestrator/internals/errors.js +13 -1
  144. package/src/lib/orchestrator/internals/execute-standard.d.ts +3 -1
  145. package/src/lib/orchestrator/internals/execute-standard.js +3 -3
  146. package/src/lib/orchestrator/internals/outbound-sync.js +52 -7
  147. package/src/lib/orchestrator/internals/push-chain-tx.d.ts +1 -1
  148. package/src/lib/orchestrator/internals/push-chain-tx.js +13 -1
  149. package/src/lib/orchestrator/orchestrator.d.ts +3 -0
  150. package/src/lib/orchestrator/orchestrator.js +13 -1
  151. package/src/lib/orchestrator/orchestrator.types.d.ts +8 -0
  152. package/src/lib/orchestrator/route-detector.js +3 -2
  153. package/src/lib/orchestrator/svm-idl/resolve.d.ts +2 -0
  154. package/src/lib/orchestrator/svm-idl/resolve.js +11 -1
  155. package/src/lib/progress-hook/progress-hook.js +84 -0
  156. package/src/lib/progress-hook/progress-hook.types.d.ts +14 -2
  157. package/src/lib/progress-hook/progress-hook.types.js +13 -0
  158. package/src/lib/push-chain/push-chain.d.ts +58 -16
  159. package/src/lib/push-chain/push-chain.js +68 -8
  160. package/src/lib/push-client/push-client.d.ts +7 -0
  161. package/src/lib/push-client/push-client.js +41 -15
  162. package/src/lib/read-state/destination.js +6 -1
  163. package/src/lib/read-state/envelopes/evm.js +2 -3
  164. package/src/lib/read-state/envelopes/svm.js +11 -1
  165. package/src/lib/read-state/read-executor.js +4 -0
  166. package/src/lib/read-state/read-params.d.ts +71 -26
  167. package/src/lib/read-state/read-params.js +60 -15
  168. package/src/lib/read-state/read-state.types.d.ts +44 -1
  169. package/src/lib/read-state/read-state.types.js +23 -1
  170. package/src/lib/read-state/read-tracker.d.ts +6 -1
  171. package/src/lib/read-state/read-tracker.js +83 -17
  172. package/src/lib/read-state/registry.js +2 -3
  173. package/src/lib/read-state/result-decoder.js +6 -0
  174. package/src/lib/read-state/spec-builder.js +2 -2
  175. package/src/lib/read-state/svm-account.d.ts +20 -0
  176. package/src/lib/read-state/svm-account.js +114 -0
  177. package/src/lib/read-state/svm-pda.d.ts +13 -0
  178. package/src/lib/read-state/svm-pda.js +147 -0
  179. package/src/lib/universal/prc20-address.d.ts +15 -0
  180. package/src/lib/universal/prc20-address.js +135 -0
  181. package/src/lib/utils.d.ts +6 -13
  182. package/src/lib/utils.js +5 -128
  183. package/src/lib/vm-client/evm-client.js +34 -20
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.trackRead = trackRead;
4
4
  exports.toRequestIdHex = toRequestIdHex;
5
+ exports.deriveReadOutcome = deriveReadOutcome;
5
6
  exports.inferResultShape = inferResultShape;
6
7
  exports.statusName = statusName;
7
8
  exports.defaultWaitTimeoutMs = defaultWaitTimeoutMs;
@@ -61,16 +62,23 @@ async function fetchRecords(deps, ref) {
61
62
  /** A request is indexed when its block is processed — briefly retry a miss. */
62
63
  async function lookupWithRetry(deps, ref, opts) {
63
64
  const now = deps.now ?? Date.now;
65
+ const emit = deps.emit ?? (() => undefined);
64
66
  const interval = pollInterval(opts);
65
67
  const start = now();
68
+ const hookRef = 'txHash' in ref ? { txHash: ref.txHash } : { requestId: toRequestIdHex(ref.requestId) };
69
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_03, hookRef);
66
70
  for (;;) {
67
71
  const records = await fetchRecords(deps, ref);
68
- if (records.length > 0)
72
+ if (records.length > 0) {
73
+ for (const r of records)
74
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_04, toRequestIdHex(r.id), statusName(r.status));
69
75
  return records;
76
+ }
70
77
  if (now() - start + interval > read_state_1.READ_TRACK_LOOKUP_TIMEOUT_MS)
71
78
  break;
72
79
  await sleep(interval);
73
80
  }
81
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_05, hookRef, now() - start);
74
82
  const label = 'txHash' in ref ? ref.txHash : toRequestIdHex(ref.requestId);
75
83
  throw new errors_1.ReadNotFoundError(label, 'txHash' in ref ? { txHash: ref.txHash } : { requestId: label });
76
84
  }
@@ -144,6 +152,8 @@ async function buildResponse(deps, record, opts) {
144
152
  }
145
153
  const txHash = req.requestedTxHash.toLowerCase();
146
154
  const response = {
155
+ requestIdUint: BigInt(requestId),
156
+ outcome: deriveReadOutcome(status, raw?.status, callbackDelivered, decodeError),
147
157
  requestId,
148
158
  txHash,
149
159
  destination,
@@ -174,23 +184,51 @@ async function buildResponse(deps, record, opts) {
174
184
  };
175
185
  return response;
176
186
  }
187
+ /**
188
+ * One answer to "did it work". Order matters: a source error is delivered to the
189
+ * callback as an ERROR result, so it is reported before any callback outcome.
190
+ */
191
+ function deriveReadOutcome(status, rawStatus, callbackDelivered, decodeError) {
192
+ switch (status) {
193
+ case read_state_types_1.UNIVERSAL_READ_STATUS.EXPIRED: return read_state_types_1.READ_OUTCOME.EXPIRED;
194
+ case read_state_types_1.UNIVERSAL_READ_STATUS.FAILED: return read_state_types_1.READ_OUTCOME.FAILED;
195
+ case read_state_types_1.UNIVERSAL_READ_STATUS.ABORTED: return read_state_types_1.READ_OUTCOME.ABORTED;
196
+ case read_state_types_1.UNIVERSAL_READ_STATUS.FULFILLED:
197
+ if (rawStatus !== undefined && rawStatus !== read_state_types_1.READ_STATUS.SUCCESS)
198
+ return read_state_types_1.READ_OUTCOME.SOURCE_ERROR;
199
+ if (callbackDelivered === false)
200
+ return read_state_types_1.READ_OUTCOME.CALLBACK_FAILED;
201
+ if (callbackDelivered !== true)
202
+ return read_state_types_1.READ_OUTCOME.UNKNOWN;
203
+ if (decodeError !== undefined)
204
+ return read_state_types_1.READ_OUTCOME.DECODE_FAILED;
205
+ return rawStatus === read_state_types_1.READ_STATUS.SUCCESS ? read_state_types_1.READ_OUTCOME.SUCCESS : read_state_types_1.READ_OUTCOME.UNKNOWN;
206
+ default:
207
+ return read_state_types_1.READ_OUTCOME.PENDING;
208
+ }
209
+ }
177
210
  /** Parse every pc_tx receipt (fulfil, settle) into one merged outcome. Missing receipts are skipped. */
178
211
  async function collectOutcome(deps, record, requestId) {
179
212
  const uc = chain_1.UNIVERSAL_CALLBACK_ADDRESSES[deps.pushNetwork];
180
213
  const merged = {};
181
- for (const t of record.pcTx) {
214
+ // Fetch in parallel, merge in pc_tx order (settle facts overwrite fulfil facts as before).
215
+ const outcomes = await Promise.all(record.pcTx.map(async (t) => {
182
216
  if (!t.txHash)
183
- continue;
217
+ return undefined;
184
218
  try {
185
219
  const receipt = await deps.pushClient.getTransactionReceiptWithArchiveFallback(t.txHash);
186
- const o = (0, read_events_1.parseFulfilOutcome)(receipt, uc, requestId);
187
- for (const [k, v] of Object.entries(o)) {
188
- if (v !== undefined)
189
- merged[k] = v;
190
- }
220
+ return (0, read_events_1.parseFulfilOutcome)(receipt, uc, requestId);
191
221
  }
192
222
  catch {
193
- // pruned or not yet available — leave those fields undefined rather than guess
223
+ return undefined; // pruned or not yet available — leave those fields undefined rather than guess
224
+ }
225
+ }));
226
+ for (const o of outcomes) {
227
+ if (!o)
228
+ continue;
229
+ for (const [k, v] of Object.entries(o)) {
230
+ if (v !== undefined)
231
+ merged[k] = v;
194
232
  }
195
233
  }
196
234
  return merged;
@@ -271,13 +309,13 @@ function inferResultShape(namespace, query) {
271
309
  }
272
310
  }
273
311
  function chainFromCaip2(caip2) {
274
- if (caip2 === enums_1.CHAIN.WEB2)
275
- return enums_1.CHAIN.WEB2;
312
+ if ((0, read_state_1.isWeb2ReadChain)(caip2))
313
+ return read_state_1.WEB2_READ_CHAIN;
276
314
  return Object.values(enums_1.CHAIN).includes(caip2) ? caip2 : undefined;
277
315
  }
278
316
  function explorerTxUrl(network, txHash) {
279
317
  const chain = network === enums_1.PUSH_NETWORK.MAINNET ? enums_1.CHAIN.PUSH_MAINNET : network === enums_1.PUSH_NETWORK.LOCALNET ? enums_1.CHAIN.PUSH_LOCALNET : enums_1.CHAIN.PUSH_TESTNET_DONUT;
280
- const base = chain_1.PUSH_CHAIN_INFO[chain].explorerUrl ?? 'https://explorer.donut.push.org';
318
+ const base = chain_1.PUSH_CHAIN_INFO[chain].explorerUrl ?? 'https://donut.push.network';
281
319
  return `${base}/tx/${txHash}`;
282
320
  }
283
321
  // ---------------------------------------------------------------------------
@@ -312,6 +350,8 @@ async function waitForRead(deps, initial, opts) {
312
350
  const interval = pollInterval(opts);
313
351
  const start = now();
314
352
  let timeoutMs = opts.timeoutMs ?? read_state_1.READ_TRACK_MAX_TIMEOUT_MS;
353
+ // Push head at a known time; later heights are estimated from the block time (no extra RPC per poll).
354
+ let head;
315
355
  // Resolve a fresh head for each wait/resume, only when a default is needed.
316
356
  // Bound this RPC too: a stalled height lookup must not hang the promise forever.
317
357
  if (opts.timeoutMs === undefined && !initial.isTerminal) {
@@ -327,6 +367,7 @@ async function waitForRead(deps, initial, opts) {
327
367
  }, read_state_1.READ_TRACK_MAX_TIMEOUT_MS);
328
368
  }),
329
369
  ]);
370
+ head = { height, at: now() };
330
371
  timeoutMs = Math.min(read_state_1.READ_TRACK_MAX_TIMEOUT_MS, now() - start + defaultWaitTimeoutMs(height, initial.request.spec.expiryPushChainHeight));
331
372
  }
332
373
  finally {
@@ -334,6 +375,23 @@ async function waitForRead(deps, initial, opts) {
334
375
  clearTimeout(timer);
335
376
  }
336
377
  }
378
+ else if (!initial.isTerminal) {
379
+ // Explicit timeout: the head only feeds the expiry warning, so never block on it.
380
+ deps.pushClient.publicClient.getBlockNumber({ cacheTime: 0 })
381
+ .then((height) => { head = { height, at: now() }; })
382
+ .catch(() => undefined);
383
+ }
384
+ let expiryWarned = false;
385
+ const warnNearExpiry = (r) => {
386
+ if (expiryWarned || !head)
387
+ return;
388
+ const estimated = head.height + BigInt(Math.floor((now() - head.at) / read_state_1.PUSH_BLOCK_TIME_MS));
389
+ const left = r.request.spec.expiryPushChainHeight - estimated;
390
+ if (left > read_state_1.READ_EXPIRY_WARNING_BLOCKS)
391
+ return;
392
+ expiryWarned = true;
393
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_04, r.requestId, left > 0n ? left : 0n);
394
+ };
337
395
  emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_02, initial.txHash, initial.requestId, initial.request.logIndex);
338
396
  // Every snapshot taken from here on is built with the wait() options, so a
339
397
  // resultShape given to wait() decodes even a record that is already terminal.
@@ -388,6 +446,7 @@ async function waitForRead(deps, initial, opts) {
388
446
  else if (current.status === read_state_types_1.UNIVERSAL_READ_STATUS.VOTING)
389
447
  emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_02, current.requestId);
390
448
  }
449
+ warnNearExpiry(current);
391
450
  const elapsed = now() - start;
392
451
  if (elapsed >= timeoutMs)
393
452
  timeout();
@@ -403,13 +462,20 @@ function emitTerminal(emit, r) {
403
462
  emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_03, r.requestId, r.callbackFailReason);
404
463
  if (r.fees.burned !== undefined)
405
464
  emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_04, r.requestId, r.fees.burned, r.fees.refunded ?? 0n);
406
- if (r.fees.refundFailed === true)
407
- emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_06, r.requestId, r.fees.refunded, r.request.refundTo);
408
- else if (r.fees.refunded !== undefined)
409
- emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_05, r.requestId, r.fees.refunded, r.request.refundTo);
465
+ }
466
+ // Refund facts exist for FULFILLED/FAILED (settle logs) and EXPIRED (EndBlock logs).
467
+ if (r.fees.refundFailed === true)
468
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_06, r.requestId, r.fees.refunded, r.request.refundTo);
469
+ else if (r.fees.refunded !== undefined)
470
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_05, r.requestId, r.fees.refunded, r.request.refundTo);
471
+ // 199-01 means it worked. A FULFILLED read that did not (source error, callback
472
+ // failure, undecodable, unconfirmed delivery) ends on 199-02 named by its outcome.
473
+ if (r.outcome === read_state_types_1.READ_OUTCOME.SUCCESS) {
410
474
  emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_01, r.requestId, r.value, r.raw?.resultData ?? '0x', r.callbackDelivered);
411
475
  return;
412
476
  }
413
- emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_02, r.requestId, statusName(r.status), r.raw?.errorCode, r.errorMsg, r.fees.refunded);
477
+ const ended = r.status === read_state_types_1.UNIVERSAL_READ_STATUS.FULFILLED ? r.outcome : statusName(r.status);
478
+ const detail = r.errorMsg || r.decodeError || '';
479
+ emit(progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_02, r.requestId, ended, r.raw?.errorCode, detail, r.fees.refunded);
414
480
  }
415
481
  //# sourceMappingURL=read-tracker.js.map
@@ -28,9 +28,8 @@ function resolveReadCallback(callback, network, queryKey) {
28
28
  if (callback && 'request' in callback)
29
29
  throw new errors_1.InvalidReadQueryError('callback.request was removed; use callback.abi, functionName and args');
30
30
  if (callback?.target !== undefined) {
31
- if (callback.gasLimit === undefined)
32
- throw new errors_1.InvalidReadQueryError('callback.gasLimit is required for a custom target');
33
- return { ...callback, gasLimit: callback.gasLimit };
31
+ // Same default as the registry: unused callback budget is refunded.
32
+ return { ...callback, gasLimit: callback.gasLimit ?? read_state_1.REGISTRY_CALLBACK_GAS };
34
33
  }
35
34
  if (callback?.abi !== undefined || callback?.functionName !== undefined || callback?.args !== undefined) {
36
35
  throw new errors_1.InvalidReadQueryError('callback abi, functionName and args require callback.target');
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.decodeReadResult = decodeReadResult;
4
4
  const viem_1 = require("viem");
5
5
  const errors_1 = require("./errors");
6
+ const buffer_1 = require("buffer");
7
+ const svm_account_1 = require("./svm-account");
6
8
  const WEB2_ABI_TYPE = {
7
9
  uint256: 'uint256',
8
10
  int256: 'int256',
@@ -29,6 +31,10 @@ function decodeReadResult(resultData, shape) {
29
31
  const len = (0, viem_1.size)(resultData);
30
32
  try {
31
33
  switch (shape.kind) {
34
+ case 'svmAccount': {
35
+ const { accountName, value } = (0, svm_account_1.decodeIdlAccount)(shape.idl, buffer_1.Buffer.from(resultData.slice(2), 'hex'), shape.accountName);
36
+ return { kind: 'svmAccount', value, accountName };
37
+ }
32
38
  case 'uint256': {
33
39
  if (len !== 32)
34
40
  throw new errors_1.ReadDecodeError(`expected 32 bytes for uint256, got ${len}`);
@@ -106,7 +106,7 @@ function buildReadSpecFromPreflight(preflight, params, defaults = {}) {
106
106
  return {
107
107
  callback: params.callback,
108
108
  queryKey: (0, registry_1.computeReadQueryKey)(params.destination, params.query),
109
- chain: dest.caip2,
109
+ chain: (isWeb2 ? read_state_1.WEB2_READ_CHAIN : dest.caip2),
110
110
  spec,
111
111
  specTuple: toTuple(spec),
112
112
  encodedSpec: encodeSpec(spec),
@@ -185,7 +185,7 @@ function toCallData(prepared, target) {
185
185
  */
186
186
  async function simulateRead(deps, prepared, opts) {
187
187
  const age = Date.now() - prepared.preflight.fetchedAt;
188
- if (age > (opts.staleAfterMs ?? 60_000)) {
188
+ if (age > (opts.staleAfterMs ?? read_state_1.READ_PREFLIGHT_STALE_MS)) {
189
189
  prepared.warnings.push(`preflight is ${Math.round(age / 1000)} s old — pushBlockNumber moves every block; rebuild before sending`);
190
190
  }
191
191
  try {
@@ -0,0 +1,20 @@
1
+ import { type Idl } from '@coral-xyz/anchor';
2
+ import { PublicKey } from '@solana/web3.js';
3
+ import type { CHAIN } from '../constants/enums';
4
+ /** snake_case, camelCase and PascalCase spellings of one name share a key. */
5
+ export declare function idlNameKey(name: string): string;
6
+ /** Structural checks the coder does not make, so a bad IDL fails at prepare time. */
7
+ export declare function validateIdl(idl: Idl): void;
8
+ /** The IDL's own spelling of an account layout name given in any case style. */
9
+ export declare function resolveAccountName(idl: Idl, name: string): string;
10
+ /**
11
+ * Decode account bytes with the IDL. With `accountName`, the data's discriminator
12
+ * must match that layout; without it, the layout is the one whose discriminator
13
+ * prefixes the data.
14
+ */
15
+ export declare function decodeIdlAccount(idl: Idl, data: Uint8Array, accountName?: string): {
16
+ accountName: string;
17
+ value: unknown;
18
+ };
19
+ /** Inspect the mint owner; the chain alone cannot distinguish SPL Token and Token-2022. */
20
+ export declare function detectTokenProgram(mint: string, chain: CHAIN, rpcUrls?: string[]): Promise<PublicKey>;
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.idlNameKey = idlNameKey;
4
+ exports.validateIdl = validateIdl;
5
+ exports.resolveAccountName = resolveAccountName;
6
+ exports.decodeIdlAccount = decodeIdlAccount;
7
+ exports.detectTokenProgram = detectTokenProgram;
8
+ const anchor_1 = require("@coral-xyz/anchor");
9
+ const web3_js_1 = require("@solana/web3.js");
10
+ const chain_1 = require("../constants/chain");
11
+ const buffer_1 = require("buffer");
12
+ const errors_1 = require("./errors");
13
+ const svm_1 = require("./envelopes/svm");
14
+ /** snake_case, camelCase and PascalCase spellings of one name share a key. */
15
+ function idlNameKey(name) {
16
+ return name.replace(/_/g, '').toLowerCase();
17
+ }
18
+ /** Structural checks the coder does not make, so a bad IDL fails at prepare time. */
19
+ function validateIdl(idl) {
20
+ try {
21
+ if (!idl || typeof idl !== 'object')
22
+ throw new Error('idl must be an Anchor IDL object');
23
+ new web3_js_1.PublicKey(idl.address);
24
+ if (!idl.accounts?.length)
25
+ throw new Error('the IDL declares no accounts');
26
+ for (const a of idl.accounts) {
27
+ const d = a.discriminator;
28
+ if (!Array.isArray(d) || d.length === 0 || d.some(b => !Number.isInteger(b) || b < 0 || b > 255)) {
29
+ throw new Error(`account ${a.name}: discriminator must be a non-empty byte array`);
30
+ }
31
+ }
32
+ new anchor_1.BorshAccountsCoder(idl);
33
+ }
34
+ catch (error) {
35
+ throw new errors_1.InvalidReadQueryError(`invalid Solana account IDL: ${error.message}`);
36
+ }
37
+ }
38
+ /** The IDL's own spelling of an account layout name given in any case style. */
39
+ function resolveAccountName(idl, name) {
40
+ const accounts = idl.accounts ?? [];
41
+ const exact = accounts.find(a => a.name === name);
42
+ if (exact)
43
+ return exact.name;
44
+ const key = idlNameKey(name);
45
+ const matches = accounts.filter(a => idlNameKey(a.name) === key);
46
+ if (matches.length === 1)
47
+ return matches[0].name;
48
+ const known = accounts.map(a => a.name).join(', ') || 'none';
49
+ throw new errors_1.InvalidReadQueryError(matches.length > 1 ? `functionName ${name} is ambiguous in the IDL (${matches.map(a => a.name).join(', ')})` : `functionName ${name} is not an account in the IDL (accounts: ${known})`);
50
+ }
51
+ function hasDiscriminator(a, data) {
52
+ return data.length >= a.discriminator.length && a.discriminator.every((b, i) => data[i] === b);
53
+ }
54
+ /**
55
+ * Decode account bytes with the IDL. With `accountName`, the data's discriminator
56
+ * must match that layout; without it, the layout is the one whose discriminator
57
+ * prefixes the data.
58
+ */
59
+ function decodeIdlAccount(idl, data, accountName) {
60
+ const accounts = idl.accounts ?? [];
61
+ let def;
62
+ if (accountName !== undefined) {
63
+ def = accounts.find(a => a.name === resolveAccountName(idl, accountName));
64
+ if (def && !hasDiscriminator(def, data)) {
65
+ throw new errors_1.ReadDecodeError(`account data discriminator does not match ${def.name}`);
66
+ }
67
+ }
68
+ else {
69
+ const found = accounts.filter(a => hasDiscriminator(a, data));
70
+ // Longest match wins if one discriminator prefixes another.
71
+ def = found.sort((x, y) => y.discriminator.length - x.discriminator.length)[0];
72
+ if (!def) {
73
+ const head = buffer_1.Buffer.from(data.subarray(0, 8)).toString('hex');
74
+ throw new errors_1.ReadDecodeError(`no IDL account discriminator matches the account data (0x${head})`);
75
+ }
76
+ }
77
+ if (!def)
78
+ throw new errors_1.ReadDecodeError('account not found in the IDL');
79
+ return { accountName: def.name, value: new anchor_1.BorshAccountsCoder(idl).decode(def.name, buffer_1.Buffer.from(data)) };
80
+ }
81
+ /** Inspect the mint owner; the chain alone cannot distinguish SPL Token and Token-2022. */
82
+ async function detectTokenProgram(mint, chain, rpcUrls) {
83
+ const address = new web3_js_1.PublicKey(mint);
84
+ const urls = rpcUrls ?? chain_1.CHAIN_INFO[chain]?.defaultRPC;
85
+ if (!urls?.length)
86
+ throw new errors_1.InvalidReadQueryError(`no Solana RPC configured for ${chain}`);
87
+ let lastError;
88
+ for (const url of urls) {
89
+ let info;
90
+ try {
91
+ info = await new web3_js_1.Connection(url, 'finalized').getAccountInfo(address, 'finalized');
92
+ }
93
+ catch (error) {
94
+ lastError = error;
95
+ continue;
96
+ }
97
+ if (!info)
98
+ throw new errors_1.InvalidReadQueryError(`token mint does not exist: ${mint}`);
99
+ if (!info.owner.equals(svm_1.TOKEN_PROGRAM_ID) && !info.owner.equals(svm_1.TOKEN_2022_PROGRAM_ID)) {
100
+ throw new errors_1.InvalidReadQueryError('mint is not owned by SPL Token or Token-2022');
101
+ }
102
+ // Mint base layout: 82 bytes, initialized flag at byte 45. Token-2022
103
+ // extensions pad to 165 bytes and carry AccountType.Mint (1) at byte 165.
104
+ if (info.executable || info.data.length < 82 || info.data[45] !== 1 ||
105
+ (info.owner.equals(svm_1.TOKEN_PROGRAM_ID) && info.data.length !== 82) ||
106
+ (info.owner.equals(svm_1.TOKEN_2022_PROGRAM_ID) && info.data.length !== 82 &&
107
+ (info.data.length < 166 || info.data[165] !== 1))) {
108
+ throw new errors_1.InvalidReadQueryError('token address is not an initialized mint');
109
+ }
110
+ return info.owner;
111
+ }
112
+ throw lastError;
113
+ }
114
+ //# sourceMappingURL=svm-account.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * PDA derivation for `read(programId, { idl, functionName, args })`.
3
+ *
4
+ * The seed layout comes from the IDL, never from a guessed encoding: Anchor
5
+ * records each PDA's seeds on the instruction accounts that use it. `args` fill
6
+ * the non-constant seeds in order, encoded as the IDL declares them.
7
+ */
8
+ import type { Idl } from '@coral-xyz/anchor';
9
+ import { PublicKey } from '@solana/web3.js';
10
+ /** Derive the PDA of account layout `functionName` from its IDL seed template and positional `args`. */
11
+ export declare function deriveIdlPda(idl: Idl, functionName: string, args?: readonly unknown[]): PublicKey;
12
+ /** Whether `subject` is the IDL's program id (base58 or 0x-hex). */
13
+ export declare function isProgramSubject(idl: Idl, subject: string): boolean;
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deriveIdlPda = deriveIdlPda;
4
+ exports.isProgramSubject = isProgramSubject;
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ const buffer_1 = require("buffer");
7
+ const normalize_address_1 = require("../orchestrator/svm-idl/normalize-address");
8
+ const errors_1 = require("./errors");
9
+ const svm_account_1 = require("./svm-account");
10
+ /** Every instruction account named like `name` that carries PDA seeds. */
11
+ function findSeedTemplates(idl, name) {
12
+ const key = (0, svm_account_1.idlNameKey)(name);
13
+ const out = [];
14
+ const visit = (instruction, accounts) => {
15
+ for (const a of accounts) {
16
+ if (a.accounts)
17
+ visit(instruction, a.accounts); // composite account groups
18
+ else if (a.pda && (0, svm_account_1.idlNameKey)(a.name) === key)
19
+ out.push({ pda: a.pda, instruction });
20
+ }
21
+ };
22
+ for (const ix of idl.instructions ?? [])
23
+ visit(ix, ix.accounts);
24
+ return out;
25
+ }
26
+ function toPublicKey(value, what) {
27
+ if (value instanceof web3_js_1.PublicKey)
28
+ return value;
29
+ try {
30
+ return new web3_js_1.PublicKey(buffer_1.Buffer.from((0, normalize_address_1.toSvmHexAddress)(value).slice(2), 'hex'));
31
+ }
32
+ catch (e) {
33
+ throw new errors_1.InvalidReadQueryError(`${what} must be a Solana pubkey (base58, 0x 32-byte hex, or PublicKey): ${e.message}`);
34
+ }
35
+ }
36
+ const INT_WIDTH = {
37
+ u8: [1, false], i8: [1, true], u16: [2, false], i16: [2, true], u32: [4, false], i32: [4, true],
38
+ u64: [8, false], i64: [8, true], u128: [16, false], i128: [16, true],
39
+ };
40
+ function encodeInt(value, type, what) {
41
+ const [bytes, signed] = INT_WIDTH[type];
42
+ let n;
43
+ try {
44
+ n = typeof value === 'bigint' ? value : BigInt(value);
45
+ }
46
+ catch {
47
+ throw new errors_1.InvalidReadQueryError(`${what} must be an integer for ${type}`);
48
+ }
49
+ const bits = BigInt(bytes * 8);
50
+ const min = signed ? -(1n << (bits - 1n)) : 0n;
51
+ const max = signed ? (1n << (bits - 1n)) - 1n : (1n << bits) - 1n;
52
+ if (n < min || n > max)
53
+ throw new errors_1.InvalidReadQueryError(`${what} out of ${type} range: ${n}`);
54
+ let u = n < 0n ? (1n << bits) + n : n;
55
+ const out = buffer_1.Buffer.alloc(bytes);
56
+ for (let i = 0; i < bytes; i++) {
57
+ out[i] = Number(u & 0xffn);
58
+ u >>= 8n;
59
+ }
60
+ return out;
61
+ }
62
+ function encodeSeed(value, type, what) {
63
+ if (type === 'pubkey')
64
+ return toPublicKey(value, what).toBuffer();
65
+ if (typeof type === 'string' && type in INT_WIDTH)
66
+ return encodeInt(value, type, what);
67
+ if (type === 'bool') {
68
+ if (typeof value !== 'boolean')
69
+ throw new errors_1.InvalidReadQueryError(`${what} must be a boolean`);
70
+ return buffer_1.Buffer.from([value ? 1 : 0]);
71
+ }
72
+ if (type === 'string') {
73
+ if (typeof value !== 'string')
74
+ throw new errors_1.InvalidReadQueryError(`${what} must be a string`);
75
+ return buffer_1.Buffer.from(value, 'utf8');
76
+ }
77
+ const isBytes = type === 'bytes' || (typeof type === 'object' && type !== null && 'array' in type && type.array[0] === 'u8');
78
+ if (isBytes) {
79
+ if (value instanceof Uint8Array)
80
+ return buffer_1.Buffer.from(value);
81
+ if (typeof value === 'string' && /^0x([0-9a-fA-F]{2})*$/.test(value))
82
+ return buffer_1.Buffer.from(value.slice(2), 'hex');
83
+ throw new errors_1.InvalidReadQueryError(`${what} must be bytes (Uint8Array or 0x-hex)`);
84
+ }
85
+ throw new errors_1.InvalidReadQueryError(`${what}: seed type ${JSON.stringify(type)} is not supported`);
86
+ }
87
+ function argType(ix, path) {
88
+ if (path.includes('.'))
89
+ throw new errors_1.InvalidReadQueryError(`seed arg path ${path} reads a struct field; only top-level instruction args are supported`);
90
+ const arg = ix.args.find(a => a.name === path) ?? ix.args.find(a => (0, svm_account_1.idlNameKey)(a.name) === (0, svm_account_1.idlNameKey)(path));
91
+ if (!arg)
92
+ throw new errors_1.InvalidReadQueryError(`seed arg ${path} is not an argument of ${ix.name}`);
93
+ return arg.type;
94
+ }
95
+ function describeSeeds(t) {
96
+ return t.pda.seeds.map(s => (s.kind === 'const' ? `"${buffer_1.Buffer.from(s.value).toString('utf8')}"` : `${s.kind}:${s.path}`)).join(', ');
97
+ }
98
+ /** Same seeds, same order: two instructions describing one PDA agree. */
99
+ function sameLayout(a, b) {
100
+ return JSON.stringify([a.pda.seeds, a.pda.program]) === JSON.stringify([b.pda.seeds, b.pda.program]);
101
+ }
102
+ /** Derive the PDA of account layout `functionName` from its IDL seed template and positional `args`. */
103
+ function deriveIdlPda(idl, functionName, args = []) {
104
+ const templates = findSeedTemplates(idl, functionName);
105
+ if (templates.length === 0) {
106
+ throw new errors_1.InvalidReadQueryError(`the IDL has no PDA seeds for ${functionName}; pass the account address as the subject instead of the program id`);
107
+ }
108
+ const [template] = templates;
109
+ if (templates.some(t => !sameLayout(t, template))) {
110
+ throw new errors_1.InvalidReadQueryError(`the IDL describes ${functionName} with different seeds in different instructions; pass the account address as the subject`);
111
+ }
112
+ const dynamic = template.pda.seeds.filter(s => s.kind !== 'const');
113
+ if (args.length !== dynamic.length) {
114
+ throw new errors_1.InvalidReadQueryError(`${functionName} is derived from seeds [${describeSeeds(template)}]: expected ${dynamic.length} args, got ${args.length}`);
115
+ }
116
+ let i = 0;
117
+ const seeds = template.pda.seeds.map((seed) => {
118
+ if (seed.kind === 'const')
119
+ return buffer_1.Buffer.from(seed.value);
120
+ const what = `args[${i}] (${seed.kind}:${seed.path})`;
121
+ const value = args[i++];
122
+ if (seed.kind === 'account') {
123
+ if (seed.path.includes('.'))
124
+ throw new errors_1.InvalidReadQueryError(`seed ${seed.path} reads another account's field; pass the account address as the subject`);
125
+ return encodeSeed(value, 'pubkey', what);
126
+ }
127
+ return encodeSeed(value, argType(template.instruction, seed.path), what);
128
+ });
129
+ let programId = new web3_js_1.PublicKey(idl.address);
130
+ const program = template.pda.program;
131
+ if (program) {
132
+ if (program.kind !== 'const')
133
+ throw new errors_1.InvalidReadQueryError(`${functionName} is derived under a non-constant program; pass the account address as the subject`);
134
+ programId = new web3_js_1.PublicKey(buffer_1.Buffer.from(program.value));
135
+ }
136
+ return web3_js_1.PublicKey.findProgramAddressSync(seeds, programId)[0];
137
+ }
138
+ /** Whether `subject` is the IDL's program id (base58 or 0x-hex). */
139
+ function isProgramSubject(idl, subject) {
140
+ try {
141
+ return (0, normalize_address_1.toSvmHexAddress)(subject) === (0, normalize_address_1.toSvmHexAddress)(idl.address);
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ }
147
+ //# sourceMappingURL=svm-pda.js.map
@@ -0,0 +1,15 @@
1
+ import { CHAIN, PUSH_NETWORK } from '../constants/enums';
2
+ import { type MoveableToken } from '../constants/tokens';
3
+ /** Shared pure origin-to-PRC20 mapping; no signer or network reads. */
4
+ export declare function getPRC20Address(token: MoveableToken | {
5
+ chain: string;
6
+ address: string;
7
+ }, options?: {
8
+ network?: PUSH_NETWORK;
9
+ }): {
10
+ address: `0x${string}`;
11
+ chain: CHAIN;
12
+ symbol: string;
13
+ decimals: number;
14
+ network: PUSH_NETWORK;
15
+ };