@pushchain/core 6.0.23 → 6.0.25

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 (94) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/package.json +1 -1
  3. package/src/lib/constants/abi/index.d.ts +1 -0
  4. package/src/lib/constants/abi/index.js +4 -1
  5. package/src/lib/constants/abi/prc20.evm.d.ts +32 -0
  6. package/src/lib/constants/abi/prc20.evm.js +20 -0
  7. package/src/lib/constants/abi/uea-factory.d.ts +31 -0
  8. package/src/lib/constants/abi/uea-factory.js +19 -0
  9. package/src/lib/constants/abi/universalCallback.evm.d.ts +561 -0
  10. package/src/lib/constants/abi/universalCallback.evm.js +247 -0
  11. package/src/lib/constants/abi/universalGatewayV0.json +1 -1
  12. package/src/lib/constants/abi/universalReadRegistry.evm.d.ts +247 -0
  13. package/src/lib/constants/abi/universalReadRegistry.evm.js +38 -0
  14. package/src/lib/constants/chain.d.ts +12 -0
  15. package/src/lib/constants/chain.js +23 -1
  16. package/src/lib/constants/enums.d.ts +7 -0
  17. package/src/lib/constants/enums.js +11 -0
  18. package/src/lib/constants/index.d.ts +52 -0
  19. package/src/lib/constants/index.js +37 -8
  20. package/src/lib/constants/read-state.d.ts +53 -0
  21. package/src/lib/constants/read-state.js +59 -0
  22. package/src/lib/generated/ucallback/v1/index.d.ts +2 -0
  23. package/src/lib/generated/ucallback/v1/index.js +6 -0
  24. package/src/lib/generated/ucallback/v1/query.d.ts +47 -0
  25. package/src/lib/generated/ucallback/v1/query.js +131 -0
  26. package/src/lib/generated/ucallback/v1/types.d.ts +99 -0
  27. package/src/lib/generated/ucallback/v1/types.js +366 -0
  28. package/src/lib/generated/uexecutor/v1/query.d.ts +29 -0
  29. package/src/lib/generated/uexecutor/v1/query.js +98 -1
  30. package/src/lib/index.d.ts +9 -0
  31. package/src/lib/index.js +37 -1
  32. package/src/lib/orchestrator/internals/cascade.js +5 -2
  33. package/src/lib/orchestrator/internals/errors.d.ts +6 -0
  34. package/src/lib/orchestrator/internals/errors.js +13 -1
  35. package/src/lib/orchestrator/internals/index.d.ts +1 -0
  36. package/src/lib/orchestrator/internals/index.js +6 -1
  37. package/src/lib/orchestrator/internals/push-chain-tx.js +81 -61
  38. package/src/lib/orchestrator/internals/read-state.d.ts +24 -0
  39. package/src/lib/orchestrator/internals/read-state.js +47 -0
  40. package/src/lib/orchestrator/internals/route-handlers.js +6 -1
  41. package/src/lib/orchestrator/internals/svm-helpers.js +24 -0
  42. package/src/lib/orchestrator/orchestrator.d.ts +26 -0
  43. package/src/lib/orchestrator/orchestrator.js +22 -0
  44. package/src/lib/orchestrator/orchestrator.types.d.ts +2 -0
  45. package/src/lib/orchestrator/route-detector.js +4 -0
  46. package/src/lib/progress-hook/progress-hook.js +271 -0
  47. package/src/lib/progress-hook/progress-hook.types.d.ts +32 -0
  48. package/src/lib/progress-hook/progress-hook.types.js +34 -0
  49. package/src/lib/push-chain/push-chain.d.ts +70 -0
  50. package/src/lib/push-chain/push-chain.js +27 -0
  51. package/src/lib/push-client/push-client.d.ts +35 -2
  52. package/src/lib/push-client/push-client.js +117 -4
  53. package/src/lib/read-state/budget.d.ts +16 -0
  54. package/src/lib/read-state/budget.js +32 -0
  55. package/src/lib/read-state/destination.d.ts +12 -0
  56. package/src/lib/read-state/destination.js +51 -0
  57. package/src/lib/read-state/envelopes/evm.d.ts +24 -0
  58. package/src/lib/read-state/envelopes/evm.js +148 -0
  59. package/src/lib/read-state/envelopes/index.d.ts +12 -0
  60. package/src/lib/read-state/envelopes/index.js +45 -0
  61. package/src/lib/read-state/envelopes/svm.d.ts +32 -0
  62. package/src/lib/read-state/envelopes/svm.js +107 -0
  63. package/src/lib/read-state/envelopes/web2.d.ts +29 -0
  64. package/src/lib/read-state/envelopes/web2.js +149 -0
  65. package/src/lib/read-state/errors.d.ts +70 -0
  66. package/src/lib/read-state/errors.js +116 -0
  67. package/src/lib/read-state/index.d.ts +13 -0
  68. package/src/lib/read-state/index.js +38 -0
  69. package/src/lib/read-state/preflight.d.ts +21 -0
  70. package/src/lib/read-state/preflight.js +70 -0
  71. package/src/lib/read-state/read-events.d.ts +27 -0
  72. package/src/lib/read-state/read-events.js +135 -0
  73. package/src/lib/read-state/read-executor.d.ts +18 -0
  74. package/src/lib/read-state/read-executor.js +212 -0
  75. package/src/lib/read-state/read-params.d.ts +205 -0
  76. package/src/lib/read-state/read-params.js +120 -0
  77. package/src/lib/read-state/read-state.types.d.ts +417 -0
  78. package/src/lib/read-state/read-state.types.js +50 -0
  79. package/src/lib/read-state/read-tracker.d.ts +50 -0
  80. package/src/lib/read-state/read-tracker.js +415 -0
  81. package/src/lib/read-state/registry.d.ts +21 -0
  82. package/src/lib/read-state/registry.js +54 -0
  83. package/src/lib/read-state/result-decoder.d.ts +16 -0
  84. package/src/lib/read-state/result-decoder.js +73 -0
  85. package/src/lib/read-state/spec-builder.d.ts +47 -0
  86. package/src/lib/read-state/spec-builder.js +251 -0
  87. package/src/lib/read-state/validate.d.ts +22 -0
  88. package/src/lib/read-state/validate.js +80 -0
  89. package/src/lib/universal-tx-detector/child-inbounds.d.ts +3 -1
  90. package/src/lib/universal-tx-detector/child-inbounds.js +4 -5
  91. package/src/lib/universal-tx-detector/detector-svm.js +29 -20
  92. package/src/lib/universal-tx-detector/svm-events.d.ts +17 -5
  93. package/src/lib/universal-tx-detector/svm-events.js +81 -6
  94. package/src/lib/vm-client/evm-client.js +27 -10
@@ -9,6 +9,7 @@ const formatters_1 = require("../formatters");
9
9
  const route_detector_1 = require("./route-detector");
10
10
  const data_utils_1 = require("./data-utils");
11
11
  const internals_1 = require("./internals");
12
+ const spec_builder_1 = require("../read-state/spec-builder");
12
13
  const gate_1 = require("./internals/pc20/gate");
13
14
  class Orchestrator {
14
15
  universalSigner;
@@ -117,6 +118,27 @@ class Orchestrator {
117
118
  async migrateCEA(chain) {
118
119
  return (0, internals_1.migrateCEA)(this.ctx, chain, this.execute.bind(this));
119
120
  }
121
+ /**
122
+ * Build a validated cross-chain ReadSpec (preflight + envelope + fee/budget) for the
123
+ * caller to splice into its own contract call. Works in read-only mode.
124
+ */
125
+ async prepareRead(params, progressHook) {
126
+ return (0, internals_1.prepareRead)(this.ctx, params, progressHook);
127
+ }
128
+ async revalidateRead(prepared) {
129
+ return (0, spec_builder_1.revalidateRead)({ pushClient: this.ctx.pushClient, pushNetwork: this.ctx.pushNetwork }, prepared);
130
+ }
131
+ /** Current native Push balance of the account that will fund read requests. */
132
+ async getReadBalance() {
133
+ return this.ctx.pushClient.getBalance(this.computeUEAOffchain());
134
+ }
135
+ /** eth_call requestExternalReadSelf as the app contract; decodes contract errors. */
136
+ async simulateRead(prepared, opts) {
137
+ return (0, internals_1.simulateRead)(this.ctx, prepared, opts);
138
+ }
139
+ trackRead(ref, opts) {
140
+ return 'txHash' in ref ? (0, internals_1.trackRead)(this.ctx, ref, opts) : (0, internals_1.trackRead)(this.ctx, ref, opts);
141
+ }
120
142
  /**
121
143
  * Rescue stuck funds on a source chain.
122
144
  * When a CEA-to-Push inbound transaction fails, tokens get locked in the
@@ -352,6 +352,8 @@ export interface UniversalTxResponse {
352
352
  * (separate per-call txs — an earlier call can commit while a later one reverts).
353
353
  */
354
354
  atomic: boolean;
355
+ /** All Push hashes in submission order when a batch uses sequential fallback. */
356
+ transactionHashes?: `0x${string}`[];
355
357
  signature: Signature;
356
358
  raw?: {
357
359
  from: string;
@@ -214,6 +214,10 @@ function detectRoute(params) {
214
214
  * @throws ChainNotSupportedError if chain is not supported
215
215
  */
216
216
  function validateRouteParams(params, context) {
217
+ const toChain = isChainTarget(params.to) ? String(params.to.chain) : undefined;
218
+ if (String(params.from?.chain ?? '') === enums_1.CHAIN.WEB2 || toChain === enums_1.CHAIN.WEB2) {
219
+ throw new RouteValidationError('CHAIN.WEB2 is a read-only destination and cannot be used with transaction APIs');
220
+ }
217
221
  const route = detectRoute(params);
218
222
  // Validate from.chain is supported external chain (Routes 3, 4)
219
223
  if (params.from?.chain) {
@@ -4,6 +4,16 @@ exports.classifyDeclineError = classifyDeclineError;
4
4
  const formatters_1 = require("../formatters");
5
5
  const utils_1 = require("../utils");
6
6
  const progress_hook_types_1 = require("./progress-hook.types");
7
+ function serializeReadValue(value) {
8
+ if (typeof value === 'bigint')
9
+ return value.toString();
10
+ if (Array.isArray(value))
11
+ return value.map(serializeReadValue);
12
+ if (value !== null && typeof value === 'object') {
13
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, serializeReadValue(item)]));
14
+ }
15
+ return value;
16
+ }
7
17
  // Helper to wrap a hook function with timestamp
8
18
  const withTimestamp = (fn) => {
9
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -942,6 +952,266 @@ const RAW_HOOKS_MULTICHAIN = {
942
952
  level: 'ERROR',
943
953
  }),
944
954
  };
955
+ // ---------------------------------------------------------------------------
956
+ // Read state (cross-chain reads) — READ-TX band.
957
+ // Copy is locked by __tests__/read-tx-spec-strings.spec.ts; change both together.
958
+ // `response` objects carry the machine-readable values (bigints as strings).
959
+ // ---------------------------------------------------------------------------
960
+ const str = (v) => v === undefined ? undefined : v.toString();
961
+ const RAW_HOOKS_READ = {
962
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_101]: (chain, namespace, queryType) => ({
963
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_101,
964
+ title: `${friendlyChain(chain)} Read Requested`,
965
+ message: `Preparing a ${namespace} read (query type ${queryType}) of ${chain}`,
966
+ response: { chain, namespace, queryType },
967
+ level: 'INFO',
968
+ }),
969
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_01]: (chain) => ({
970
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_01,
971
+ title: 'Fetching Destination Height & Fee',
972
+ message: `Reading the oracle height and protocol fee for ${chain}`,
973
+ response: { chain, stage: 'preflight' },
974
+ level: 'INFO',
975
+ }),
976
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_02]: (protocolFee, callbackBudget, total, blockNumber, expiryPushChainHeight) => ({
977
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_02,
978
+ title: 'Read Spec Assembled',
979
+ message: `Pinned at block ${blockNumber}, expires at Push height ${expiryPushChainHeight}; fee ${protocolFee} + budget ${callbackBudget} = ${total} UPC`,
980
+ response: {
981
+ protocolFee: str(protocolFee),
982
+ callbackBudget: str(callbackBudget),
983
+ totalValue: str(total),
984
+ blockNumber: str(blockNumber),
985
+ expiryPushChainHeight: str(expiryPushChainHeight),
986
+ },
987
+ level: 'SUCCESS',
988
+ }),
989
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_03]: (chain) => ({
990
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_03,
991
+ title: 'Destination Height Unavailable',
992
+ message: `The oracle has no height for ${chain} — this chain is not readable`,
993
+ response: { chain },
994
+ level: 'ERROR',
995
+ }),
996
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_04]: (fetchedAt, ageMs) => ({
997
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_04,
998
+ title: 'Preflight Stale, Refetching',
999
+ message: `Preflight is ${Math.round(ageMs / 1000)}s old — refetching the Push height`,
1000
+ response: { fetchedAt, ageMs },
1001
+ level: 'WARNING',
1002
+ }),
1003
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_05]: (refundTo) => ({
1004
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_102_05,
1005
+ title: 'Refund Target Is A Contract',
1006
+ message: `${refundTo} is a contract that is not a UEA — it needs a payable receive() or the unspent budget is forfeited`,
1007
+ response: { refundTo },
1008
+ level: 'WARNING',
1009
+ }),
1010
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_01]: (required, available, enforceGasCheck = false) => {
1011
+ const sufficient = available >= required;
1012
+ const shortfall = sufficient ? BigInt(0) : required - available;
1013
+ return {
1014
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_01,
1015
+ title: 'Checking Balance Requirements',
1016
+ message: sufficient
1017
+ ? `Balance ${available} UPC covers the ${required} UPC read`
1018
+ : `Balance ${available} UPC is ${shortfall} UPC short of ${required} UPC`,
1019
+ response: {
1020
+ required: str(required),
1021
+ available: str(available),
1022
+ sufficient,
1023
+ shortfall: str(shortfall),
1024
+ enforceGasCheck,
1025
+ },
1026
+ level: sufficient ? 'INFO' : 'WARNING',
1027
+ };
1028
+ },
1029
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_02]: (required, available) => ({
1030
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_02,
1031
+ title: 'Insufficient Balance',
1032
+ message: `Need ${required} UPC, have ${available} UPC`,
1033
+ response: {
1034
+ required: str(required),
1035
+ available: str(available),
1036
+ shortfall: str(required - available),
1037
+ },
1038
+ level: 'ERROR',
1039
+ }),
1040
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_03]: (matchedHeaders) => ({
1041
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_103_03,
1042
+ title: 'Sensitive Header Detected',
1043
+ message: `Headers are written to a public event log forever: ${matchedHeaders.join(', ')}`,
1044
+ response: { matchedHeaders },
1045
+ level: 'WARNING',
1046
+ }),
1047
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_01]: () => ({
1048
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_01,
1049
+ title: 'Broadcasting Read Request',
1050
+ message: 'Sending the read request to Push Chain',
1051
+ response: { stage: 'broadcasting' },
1052
+ level: 'INFO',
1053
+ }),
1054
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_02]: (txHash, requestId, logIndex) => ({
1055
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_104_02,
1056
+ title: 'Request Confirmed, Read Detected',
1057
+ message: `Read ${requestId} requested in ${txHash} (log ${logIndex})`,
1058
+ response: { txHash, requestId, logIndex },
1059
+ level: 'SUCCESS',
1060
+ }),
1061
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_01]: (requestId) => ({
1062
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_01,
1063
+ title: 'Awaiting Quorum',
1064
+ message: `Validators are observing the destination for ${requestId}`,
1065
+ response: { requestId, status: 'PENDING' },
1066
+ level: 'INFO',
1067
+ }),
1068
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_02]: (requestId) => ({
1069
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_02,
1070
+ title: 'Voting In Progress',
1071
+ message: `Validators are voting on the result of ${requestId}`,
1072
+ response: { requestId, status: 'VOTING' },
1073
+ level: 'INFO',
1074
+ }),
1075
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_03]: (requestId, current, required) => ({
1076
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_03,
1077
+ title: 'Awaiting Destination Confirmations',
1078
+ message: `${current} of ${required} confirmations on the destination for ${requestId}`,
1079
+ response: { requestId, current: str(current), required: str(required) },
1080
+ level: 'INFO',
1081
+ }),
1082
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_04]: (requestId, pushBlocksRemaining) => ({
1083
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_105_04,
1084
+ title: 'Approaching Expiry',
1085
+ message: `${pushBlocksRemaining} Push blocks until ${requestId} expires`,
1086
+ response: { requestId, pushBlocksRemaining: str(pushBlocksRemaining) },
1087
+ level: 'WARNING',
1088
+ }),
1089
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_01]: (requestId, callbackTarget) => ({
1090
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_01,
1091
+ title: 'Quorum Reached, Executing Callback',
1092
+ message: `Delivering the result of ${requestId} to ${callbackTarget}`,
1093
+ response: { requestId, callbackTarget },
1094
+ level: 'INFO',
1095
+ }),
1096
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_02]: (requestId) => ({
1097
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_02,
1098
+ title: 'Callback Delivered',
1099
+ message: `ReadFulfilled emitted for ${requestId}`,
1100
+ response: { requestId },
1101
+ level: 'SUCCESS',
1102
+ }),
1103
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_03]: (requestId, reason) => ({
1104
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_03,
1105
+ title: 'Callback Reverted',
1106
+ message: `CallbackFailed for ${requestId} — the read is still FULFILLED but your callback did not run`,
1107
+ response: { requestId, reason: reason ?? null },
1108
+ level: 'WARNING',
1109
+ }),
1110
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_04]: (requestId, burned, refunded) => ({
1111
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_04,
1112
+ title: 'Callback Gas Settled',
1113
+ message: `Burned ${burned} UPC, refunding ${refunded} UPC for ${requestId}`,
1114
+ response: { requestId, burned: str(burned), refunded: str(refunded) },
1115
+ level: 'INFO',
1116
+ }),
1117
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_05]: (requestId, amount, refundTo) => ({
1118
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_05,
1119
+ title: 'Refund Sent',
1120
+ message: `${amount} UPC pushed to ${refundTo}`,
1121
+ response: { requestId, amount: str(amount), refundTo },
1122
+ level: 'INFO',
1123
+ }),
1124
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_06]: (requestId, amount, refundTo) => ({
1125
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_106_06,
1126
+ title: 'Refund Rejected',
1127
+ message: `${refundTo} rejected the refund — it sits in the admin rescue pool`,
1128
+ response: { requestId, amount: str(amount) ?? null, refundTo },
1129
+ level: 'WARNING',
1130
+ }),
1131
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_01]: (requestId, value, resultData, callbackDelivered) => ({
1132
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_01,
1133
+ title: 'Read Fulfilled',
1134
+ message: callbackDelivered
1135
+ ? `Read ${requestId} fulfilled and delivered`
1136
+ : `Read ${requestId} fulfilled — callback not delivered`,
1137
+ response: {
1138
+ requestId,
1139
+ value: serializeReadValue(value) ?? null,
1140
+ resultData,
1141
+ callbackDelivered: callbackDelivered ?? null,
1142
+ },
1143
+ level: 'SUCCESS',
1144
+ }),
1145
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_02]: (requestId, status, errorCode, errorMsg, refunded) => ({
1146
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_02,
1147
+ title: 'Read Failed / Expired / Aborted',
1148
+ message: `Read ${requestId} ended ${status}${errorMsg ? `: ${errorMsg}` : ''}`,
1149
+ response: {
1150
+ requestId,
1151
+ status,
1152
+ errorCode: errorCode ?? null,
1153
+ errorMsg,
1154
+ refunded: str(refunded) ?? null,
1155
+ },
1156
+ level: 'ERROR',
1157
+ }),
1158
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_03]: (requestId, lastStatus, elapsedMs) => ({
1159
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_03,
1160
+ title: 'Read Timeout',
1161
+ message: `Gave up waiting for ${requestId} after ${Math.round(elapsedMs / 1000)}s (last status ${lastStatus}) — resume with trackRead`,
1162
+ response: { requestId, lastStatus, elapsedMs },
1163
+ level: 'ERROR',
1164
+ }),
1165
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_99]: (requestId, txHash) => ({
1166
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_199_99,
1167
+ title: 'Intermediate Read Step Completed',
1168
+ message: `Read ${requestId} advanced in ${txHash}`,
1169
+ response: { requestId, txHash },
1170
+ level: 'INFO',
1171
+ }),
1172
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_001]: (count, chains) => ({
1173
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_001,
1174
+ title: 'Batch Read Initiated',
1175
+ message: `Preparing ${count} reads across ${chains.join(', ')}`,
1176
+ response: { count, chains },
1177
+ level: 'INFO',
1178
+ }),
1179
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_002_01]: (n, total, chain) => ({
1180
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_002_01,
1181
+ title: `Starting Read #${n}/${total}`,
1182
+ message: `Read ${n} of ${total} targets ${chain}`,
1183
+ response: { n, total, chain },
1184
+ level: 'INFO',
1185
+ }),
1186
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_002_99_99]: (n, total, requestId) => ({
1187
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_002_99_99,
1188
+ title: `Read #${n}/${total} Complete`,
1189
+ message: `Read ${n} of ${total} settled as ${requestId}`,
1190
+ response: { n, total, requestId },
1191
+ level: 'INFO',
1192
+ }),
1193
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_999_01]: (count) => ({
1194
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_999_01,
1195
+ title: 'All Reads Fulfilled',
1196
+ message: `All ${count} reads fulfilled`,
1197
+ response: { count },
1198
+ level: 'SUCCESS',
1199
+ }),
1200
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_999_02]: (failedAt, total, error) => ({
1201
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_999_02,
1202
+ title: 'Batch Reads Failed',
1203
+ message: `Batch failed at read ${failedAt} of ${total}: ${error}`,
1204
+ response: { failedAt, total, error },
1205
+ level: 'ERROR',
1206
+ }),
1207
+ [progress_hook_types_1.PROGRESS_HOOK.READ_TX_999_03]: (failedAt, total) => ({
1208
+ id: progress_hook_types_1.PROGRESS_HOOK.READ_TX_999_03,
1209
+ title: 'Batch Reads Timeout',
1210
+ message: `Batch timed out at read ${failedAt} of ${total}`,
1211
+ response: { failedAt, total, error: 'read timeout' },
1212
+ level: 'ERROR',
1213
+ }),
1214
+ };
945
1215
  // Combine all routes into the master record
946
1216
  const RAW_HOOKS = {
947
1217
  ...RAW_HOOKS_R1,
@@ -949,6 +1219,7 @@ const RAW_HOOKS = {
949
1219
  ...RAW_HOOKS_R3,
950
1220
  ...RAW_HOOKS_MULTICHAIN,
951
1221
  ...RAW_HOOKS_MIG,
1222
+ ...RAW_HOOKS_READ,
952
1223
  };
953
1224
  // Build final hooks with timestamp injection
954
1225
  const PROGRESS_HOOKS = Object.fromEntries(Object.entries(RAW_HOOKS).map(([key, value]) => [key, withTimestamp(value)]));
@@ -95,6 +95,37 @@ export declare enum PROGRESS_HOOK {
95
95
  SEND_TX_999_01 = "SEND-TX-999-01",
96
96
  SEND_TX_999_02 = "SEND-TX-999-02",
97
97
  SEND_TX_999_03 = "SEND-TX-999-03",
98
+ READ_TX_101 = "READ-TX-101",
99
+ READ_TX_102_01 = "READ-TX-102-01",
100
+ READ_TX_102_02 = "READ-TX-102-02",
101
+ READ_TX_102_03 = "READ-TX-102-03",
102
+ READ_TX_102_04 = "READ-TX-102-04",
103
+ READ_TX_102_05 = "READ-TX-102-05",
104
+ READ_TX_103_01 = "READ-TX-103-01",
105
+ READ_TX_103_02 = "READ-TX-103-02",
106
+ READ_TX_103_03 = "READ-TX-103-03",
107
+ READ_TX_104_01 = "READ-TX-104-01",
108
+ READ_TX_104_02 = "READ-TX-104-02",
109
+ READ_TX_105_01 = "READ-TX-105-01",
110
+ READ_TX_105_02 = "READ-TX-105-02",
111
+ READ_TX_105_03 = "READ-TX-105-03",
112
+ READ_TX_105_04 = "READ-TX-105-04",
113
+ READ_TX_106_01 = "READ-TX-106-01",
114
+ READ_TX_106_02 = "READ-TX-106-02",
115
+ READ_TX_106_03 = "READ-TX-106-03",
116
+ READ_TX_106_04 = "READ-TX-106-04",
117
+ READ_TX_106_05 = "READ-TX-106-05",
118
+ READ_TX_106_06 = "READ-TX-106-06",
119
+ READ_TX_199_01 = "READ-TX-199-01",
120
+ READ_TX_199_02 = "READ-TX-199-02",
121
+ READ_TX_199_03 = "READ-TX-199-03",
122
+ READ_TX_199_99 = "READ-TX-199-99",
123
+ READ_TX_001 = "READ-TX-001",
124
+ READ_TX_002_01 = "READ-TX-002-01",
125
+ READ_TX_002_99_99 = "READ-TX-002-99-99",
126
+ READ_TX_999_01 = "READ-TX-999-01",
127
+ READ_TX_999_02 = "READ-TX-999-02",
128
+ READ_TX_999_03 = "READ-TX-999-03",
98
129
  UEA_MIG_01 = "UEA-MIG-01",
99
130
  UEA_MIG_02 = "UEA-MIG-02",
100
131
  UEA_MIG_03 = "UEA-MIG-03",
@@ -107,4 +138,5 @@ export type PROGRESS_HOOK_R2 = PROGRESS_HOOK.SEND_TX_201 | PROGRESS_HOOK.SEND_TX
107
138
  export type PROGRESS_HOOK_R3 = PROGRESS_HOOK.SEND_TX_301 | PROGRESS_HOOK.SEND_TX_302_01 | PROGRESS_HOOK.SEND_TX_302_02 | PROGRESS_HOOK.SEND_TX_303_01 | PROGRESS_HOOK.SEND_TX_303_02 | PROGRESS_HOOK.SEND_TX_303_03_01 | PROGRESS_HOOK.SEND_TX_303_03_02 | PROGRESS_HOOK.SEND_TX_303_03_03 | PROGRESS_HOOK.SEND_TX_303_04 | PROGRESS_HOOK.SEND_TX_303_05 | PROGRESS_HOOK.SEND_TX_303_06 | PROGRESS_HOOK.SEND_TX_304_01 | PROGRESS_HOOK.SEND_TX_304_02 | PROGRESS_HOOK.SEND_TX_304_03 | PROGRESS_HOOK.SEND_TX_304_04 | PROGRESS_HOOK.SEND_TX_307 | PROGRESS_HOOK.SEND_TX_309_01 | PROGRESS_HOOK.SEND_TX_309_02 | PROGRESS_HOOK.SEND_TX_309_03 | PROGRESS_HOOK.SEND_TX_310_01 | PROGRESS_HOOK.SEND_TX_310_02 | PROGRESS_HOOK.SEND_TX_399_01 | PROGRESS_HOOK.SEND_TX_399_02 | PROGRESS_HOOK.SEND_TX_399_03 | PROGRESS_HOOK.SEND_TX_399_99;
108
139
  export type PROGRESS_HOOK_MULTICHAIN = PROGRESS_HOOK.SEND_TX_001 | PROGRESS_HOOK.SEND_TX_002_01 | PROGRESS_HOOK.SEND_TX_002_99_99 | PROGRESS_HOOK.SEND_TX_003_03 | PROGRESS_HOOK.SEND_TX_003_04 | PROGRESS_HOOK.SEND_TX_003_05 | PROGRESS_HOOK.SEND_TX_999_01 | PROGRESS_HOOK.SEND_TX_999_02 | PROGRESS_HOOK.SEND_TX_999_03;
109
140
  export type PROGRESS_HOOK_MIG = PROGRESS_HOOK.UEA_MIG_01 | PROGRESS_HOOK.UEA_MIG_02 | PROGRESS_HOOK.UEA_MIG_03 | PROGRESS_HOOK.UEA_MIG_9901 | PROGRESS_HOOK.UEA_MIG_9902 | PROGRESS_HOOK.UEA_MIG_9903;
141
+ export type PROGRESS_HOOK_READ = PROGRESS_HOOK.READ_TX_101 | PROGRESS_HOOK.READ_TX_102_01 | PROGRESS_HOOK.READ_TX_102_02 | PROGRESS_HOOK.READ_TX_102_03 | PROGRESS_HOOK.READ_TX_102_04 | PROGRESS_HOOK.READ_TX_102_05 | PROGRESS_HOOK.READ_TX_103_01 | PROGRESS_HOOK.READ_TX_103_02 | PROGRESS_HOOK.READ_TX_103_03 | PROGRESS_HOOK.READ_TX_104_01 | PROGRESS_HOOK.READ_TX_104_02 | PROGRESS_HOOK.READ_TX_105_01 | PROGRESS_HOOK.READ_TX_105_02 | PROGRESS_HOOK.READ_TX_105_03 | PROGRESS_HOOK.READ_TX_105_04 | PROGRESS_HOOK.READ_TX_106_01 | PROGRESS_HOOK.READ_TX_106_02 | PROGRESS_HOOK.READ_TX_106_03 | PROGRESS_HOOK.READ_TX_106_04 | PROGRESS_HOOK.READ_TX_106_05 | PROGRESS_HOOK.READ_TX_106_06 | PROGRESS_HOOK.READ_TX_199_01 | PROGRESS_HOOK.READ_TX_199_02 | PROGRESS_HOOK.READ_TX_199_03 | PROGRESS_HOOK.READ_TX_199_99 | PROGRESS_HOOK.READ_TX_001 | PROGRESS_HOOK.READ_TX_002_01 | PROGRESS_HOOK.READ_TX_002_99_99 | PROGRESS_HOOK.READ_TX_999_01 | PROGRESS_HOOK.READ_TX_999_02 | PROGRESS_HOOK.READ_TX_999_03;
110
142
  export {};
@@ -103,6 +103,40 @@ var PROGRESS_HOOK;
103
103
  PROGRESS_HOOK["SEND_TX_999_01"] = "SEND-TX-999-01";
104
104
  PROGRESS_HOOK["SEND_TX_999_02"] = "SEND-TX-999-02";
105
105
  PROGRESS_HOOK["SEND_TX_999_03"] = "SEND-TX-999-03";
106
+ // Read state (cross-chain reads) — single read 101–199, batch 001 / 999.
107
+ // A distinct flow from sendTransaction: NEVER add these to the R1 suppression
108
+ // set in orchestrator/internals/context.ts.
109
+ PROGRESS_HOOK["READ_TX_101"] = "READ-TX-101";
110
+ PROGRESS_HOOK["READ_TX_102_01"] = "READ-TX-102-01";
111
+ PROGRESS_HOOK["READ_TX_102_02"] = "READ-TX-102-02";
112
+ PROGRESS_HOOK["READ_TX_102_03"] = "READ-TX-102-03";
113
+ PROGRESS_HOOK["READ_TX_102_04"] = "READ-TX-102-04";
114
+ PROGRESS_HOOK["READ_TX_102_05"] = "READ-TX-102-05";
115
+ PROGRESS_HOOK["READ_TX_103_01"] = "READ-TX-103-01";
116
+ PROGRESS_HOOK["READ_TX_103_02"] = "READ-TX-103-02";
117
+ PROGRESS_HOOK["READ_TX_103_03"] = "READ-TX-103-03";
118
+ PROGRESS_HOOK["READ_TX_104_01"] = "READ-TX-104-01";
119
+ PROGRESS_HOOK["READ_TX_104_02"] = "READ-TX-104-02";
120
+ PROGRESS_HOOK["READ_TX_105_01"] = "READ-TX-105-01";
121
+ PROGRESS_HOOK["READ_TX_105_02"] = "READ-TX-105-02";
122
+ PROGRESS_HOOK["READ_TX_105_03"] = "READ-TX-105-03";
123
+ PROGRESS_HOOK["READ_TX_105_04"] = "READ-TX-105-04";
124
+ PROGRESS_HOOK["READ_TX_106_01"] = "READ-TX-106-01";
125
+ PROGRESS_HOOK["READ_TX_106_02"] = "READ-TX-106-02";
126
+ PROGRESS_HOOK["READ_TX_106_03"] = "READ-TX-106-03";
127
+ PROGRESS_HOOK["READ_TX_106_04"] = "READ-TX-106-04";
128
+ PROGRESS_HOOK["READ_TX_106_05"] = "READ-TX-106-05";
129
+ PROGRESS_HOOK["READ_TX_106_06"] = "READ-TX-106-06";
130
+ PROGRESS_HOOK["READ_TX_199_01"] = "READ-TX-199-01";
131
+ PROGRESS_HOOK["READ_TX_199_02"] = "READ-TX-199-02";
132
+ PROGRESS_HOOK["READ_TX_199_03"] = "READ-TX-199-03";
133
+ PROGRESS_HOOK["READ_TX_199_99"] = "READ-TX-199-99";
134
+ PROGRESS_HOOK["READ_TX_001"] = "READ-TX-001";
135
+ PROGRESS_HOOK["READ_TX_002_01"] = "READ-TX-002-01";
136
+ PROGRESS_HOOK["READ_TX_002_99_99"] = "READ-TX-002-99-99";
137
+ PROGRESS_HOOK["READ_TX_999_01"] = "READ-TX-999-01";
138
+ PROGRESS_HOOK["READ_TX_999_02"] = "READ-TX-999-02";
139
+ PROGRESS_HOOK["READ_TX_999_03"] = "READ-TX-999-03";
106
140
  // UEA Migration hooks (unchanged)
107
141
  PROGRESS_HOOK["UEA_MIG_01"] = "UEA-MIG-01";
108
142
  PROGRESS_HOOK["UEA_MIG_02"] = "UEA-MIG-02";
@@ -7,6 +7,9 @@ import { ProgressEvent } from '../progress-hook/progress-hook.types';
7
7
  import type { AccountStatus } from '../orchestrator/orchestrator.types';
8
8
  import { MoveableToken, PayableToken, ConversionQuote, MoveableTokenAccessor, PayableTokenAccessor } from '../constants/tokens';
9
9
  import type { PreparedUniversalTx, CascadedTxResponse, CascadeExecutionOptions } from '../orchestrator/orchestrator.types';
10
+ import type { Hex } from 'viem';
11
+ import type { BatchReadResponse, PreparedRead, UniversalReadResponse } from '../read-state/read-state.types';
12
+ import { type ReadOptions, type ReadPrepareOptions, type ReadValue, type ValidateReadCall, type ReadTrackOptions, type ReadExecuteOptions } from '../read-state/read-params';
10
13
  /**
11
14
  * @class PushChain
12
15
  *
@@ -32,6 +35,29 @@ export declare class PushChain {
32
35
  PAYABLE: {
33
36
  TOKEN: import("../constants").PayableTokenConstantsMap;
34
37
  };
38
+ READ: {
39
+ readonly WEB2: "web2:https";
40
+ readonly NAMESPACE: {
41
+ readonly EVM: "eip155";
42
+ readonly SVM: "solana";
43
+ readonly WEB2: "web2";
44
+ };
45
+ readonly MAX_CALLBACK_GAS_LIMIT: 1000000n;
46
+ readonly MIN_CONFIRMATIONS_FLOOR: 1;
47
+ readonly DEFAULT_EXPIRY_BLOCKS: 300n;
48
+ readonly CALLBACK_BUDGET_BUFFER: 3;
49
+ readonly REGISTRY_CALLBACK_GAS: 500000n;
50
+ readonly UNIVERSAL_READ_REGISTRY_ADDRESS: {
51
+ readonly TESTNET_DONUT: "0x91b09DAd1774bAfDE679F9ebB5F9046AE2b928C8";
52
+ };
53
+ readonly WEB2_MAX_EXTRACT_ENTRIES: 16;
54
+ readonly WEB2_DEFAULT_TIMEOUT_MS: 5000;
55
+ readonly UNIVERSAL_CORE_ADDRESSES: Record<PUSH_NETWORK, `0x${string}`>;
56
+ readonly UNIVERSAL_CALLBACK_ADDRESSES: Record<PUSH_NETWORK, `0x${string}`>;
57
+ readonly STATUS: typeof import("../read-state/read-state.types").UNIVERSAL_READ_STATUS;
58
+ readonly RESULT_STATUS: typeof import("../read-state/read-state.types").READ_STATUS;
59
+ readonly ERROR_CODE: typeof import("../read-state/read-state.types").READ_ERROR_CODE;
60
+ };
35
61
  };
36
62
  /**
37
63
  * @static
@@ -124,6 +150,50 @@ export declare class PushChain {
124
150
  * This triggers a manual revert via TSS to release those funds.
125
151
  */
126
152
  rescueFunds: Orchestrator['rescueFunds'];
153
+ /**
154
+ * Cross-chain read state — one-shot. `read ≡ prepareRead → executeReads → wait`.
155
+ * Defaults to the canonical registry on Donut. For your own application receiver,
156
+ * pass callback.target, gasLimit, abi and functionName, plus an optional args mapper.
157
+ */
158
+ read: <const O extends ReadOptions>(subject: string, options: O & ValidateReadCall<O>) => Promise<UniversalReadResponse<ReadValue<O>>>;
159
+ /**
160
+ * Build a validated `ReadSpec` for `subject` on `options.chain`: preflight (oracle
161
+ * height, protocol fee, gas price), envelope encoding, budget sizing, expiry math.
162
+ * Works in read-only mode. Splice `prepared.spec` / `prepared.value` into your
163
+ * contract's entrypoint (`toCallData`), send it with `sendTransaction`, then
164
+ * `trackRead({ txHash })`.
165
+ *
166
+ * @example
167
+ * const prepared = await client.universal.prepareRead(user, {
168
+ * chain: CHAIN.ETHEREUM_SEPOLIA,
169
+ * callback: { target: myReadClient, gasLimit: 200_000n },
170
+ * });
171
+ */
172
+ prepareRead: <const O extends ReadPrepareOptions>(subject: string, options: O & ValidateReadCall<O>) => Promise<PreparedRead<ReadValue<O>>>;
173
+ /**
174
+ * Execute app request calls as a multicall; wallets without EIP-7702 support
175
+ * use separate transactions. Returns a typed BatchReadResponse containing
176
+ * transaction metadata and results in prepared order. Waits for completion
177
+ * unless waitForCompletion is false. Requires a signer.
178
+ */
179
+ executeReads: <const R extends readonly PreparedRead[]>(reads: R, options?: ReadExecuteOptions) => Promise<BatchReadResponse<R>>;
180
+ /**
181
+ * Resume a read by the Push tx that requested it (array — one tx can carry several)
182
+ * or by requestId (single). Each response has `wait()` / `refresh()`.
183
+ * Works in read-only mode.
184
+ */
185
+ trackRead: {
186
+ (ref: {
187
+ txHash: Hex;
188
+ }, options?: ReadTrackOptions & {
189
+ progressHook?: (e: ProgressEvent) => void;
190
+ }): Promise<UniversalReadResponse[]>;
191
+ (ref: {
192
+ requestId: Hex | bigint;
193
+ }, options?: ReadTrackOptions & {
194
+ progressHook?: (e: ProgressEvent) => void;
195
+ }): Promise<UniversalReadResponse>;
196
+ };
127
197
  /**
128
198
  * Signs an arbitrary message
129
199
  */
@@ -11,6 +11,8 @@ const bs58_1 = require("../internal/bs58");
11
11
  const viem_1 = require("viem");
12
12
  const evm_client_1 = require("../vm-client/evm-client");
13
13
  const tokens_1 = require("../constants/tokens");
14
+ const read_params_1 = require("../read-state/read-params");
15
+ const read_executor_1 = require("../read-state/read-executor");
14
16
  /**
15
17
  * @class PushChain
16
18
  *
@@ -116,6 +118,31 @@ class PushChain {
116
118
  }
117
119
  return orchestrator.rescueFunds.bind(orchestrator)(params);
118
120
  },
121
+ // Only read()/executeReads() send transactions; prepare/simulate/track remain read-only.
122
+ read: async (subject, options) => {
123
+ const params = (0, read_params_1.toBuildReadSpecParams)(subject, options, orchestrator.getNetwork());
124
+ (0, read_executor_1.assertRequestEntrypoint)(params.callback, 'read');
125
+ if (this.isReadMode)
126
+ throw new Error('Read only mode cannot call read function');
127
+ const prepared = await orchestrator.prepareRead(params, options.progressHook);
128
+ const { reads: [response] } = await (0, read_executor_1.executeReads)(orchestrator, [prepared], options);
129
+ return response;
130
+ },
131
+ prepareRead: (subject, options) => {
132
+ return orchestrator.prepareRead.bind(orchestrator)((0, read_params_1.toBuildReadSpecParams)(subject, options, orchestrator.getNetwork()));
133
+ },
134
+ executeReads: (async (reads, options) => {
135
+ reads.forEach((r) => (0, read_executor_1.assertRequestEntrypoint)(r.callback));
136
+ if (this.isReadMode)
137
+ throw new Error('Read only mode cannot call executeReads function');
138
+ return (0, read_executor_1.executeReads)(orchestrator, reads, options);
139
+ }),
140
+ trackRead: ((ref, options) => {
141
+ const opts = { ...(0, read_params_1.toLifecycleOptions)(options), progressHook: options?.progressHook };
142
+ return 'txHash' in ref
143
+ ? orchestrator.trackRead.bind(orchestrator)(ref, opts)
144
+ : orchestrator.trackRead.bind(orchestrator)(ref, opts);
145
+ }),
119
146
  signMessage: async (data) => {
120
147
  if (this.isReadMode) {
121
148
  throw new Error('Read only mode cannot call signMessage function');
@@ -5,12 +5,15 @@ import { TxBody, TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
5
5
  import { DeliverTxResponse } from '@cosmjs/stargate';
6
6
  import { QueryGetUniversalTxResponse } from '../generated/uexecutor/v1/query';
7
7
  import { QueryGetUniversalTxResponseV2 } from '../generated/uexecutor/v2/query';
8
+ import { QueryReadsByTxResponse, QueryUniversalReadResponse } from '../generated/ucallback/v1';
8
9
  import { EvmClient } from '../vm-client/evm-client';
9
10
  import { PushClientOptions } from './push-client.types';
10
11
  import { TxResponse } from '../vm-client/vm-client.types';
11
12
  export declare class PushClient extends EvmClient {
12
- /** Gas limit for Cosmos transactions on Push Chain */
13
- private static readonly COSMOS_GAS_LIMIT;
13
+ /** Conservative SDK ceiling and fallback for gasless Cosmos transactions. */
14
+ private static readonly DEFAULT_COSMOS_GAS_LIMIT;
15
+ private static readonly GASLESS_GAS_LIMIT_CACHE_TTL_MS;
16
+ private static readonly MSG_EXECUTE_PAYLOAD_TYPE_URL;
14
17
  pushChainInfo: {
15
18
  chainId: string;
16
19
  vm: import("../constants/enums").VM;
@@ -42,6 +45,7 @@ export declare class PushClient extends EvmClient {
42
45
  private readonly ephemeralKey;
43
46
  private readonly ephemeralAccount;
44
47
  private currentRpcIndex;
48
+ private gaslessGasLimitCache?;
45
49
  /**
46
50
  * Archive (full-history) endpoints. History-sensitive reads fall back from
47
51
  * the prune RPC to these on a pruned-history miss. Resolved from the chain's
@@ -93,11 +97,40 @@ export declare class PushClient extends EvmClient {
93
97
  * In prod, signer should be passed in instead.
94
98
  */
95
99
  signCosmosTx(txBody: TxBody): Promise<TxRaw>;
100
+ private resolveCosmosGasLimit;
96
101
  broadcastCosmosTx(txRaw: TxRaw): Promise<DeliverTxResponse>;
97
102
  /**
98
103
  * Queries Push Chain's uexecutor gRPC service for a UniversalTx by its ID.
99
104
  */
100
105
  getUniversalTxById(id: string): Promise<QueryGetUniversalTxResponse>;
106
+ /**
107
+ * Queries x/ucallback for one cross-chain read by its requestId (0x-prefixed uint256 hex).
108
+ *
109
+ * Current-state query — an absent `read` is a real "does not exist", so there is
110
+ * deliberately no archive fallback (see getUniversalTxByIdV2 for the rationale).
111
+ */
112
+ getUniversalRead(requestId: string): Promise<QueryUniversalReadResponse>;
113
+ /**
114
+ * Cosmos `block_results` for one height, raw over the Tendermint HTTP RPC. Push Chain
115
+ * runs CometBFT 0.38 and emits `finalize_block_events`, which the cosmjs 0.33 decoders
116
+ * still drop (they only read `end_block_events`) — hence the direct call. This is the
117
+ * only place the EndBlocker's work is visible: read-state expiry runs there and leaves
118
+ * no EVM-indexed tx or receipt. Attribute values are plain strings.
119
+ */
120
+ getBlockResultEvents(height: number): Promise<readonly {
121
+ type: string;
122
+ attributes: readonly {
123
+ key: string;
124
+ value: string;
125
+ }[];
126
+ }[]>;
127
+ /**
128
+ * Queries x/ucallback for every read a Push transaction requested. One tx can emit
129
+ * several ReadRequested logs; this reassembles that batch. The node keys on the exact
130
+ * lowercase 0x hash, which is what the SDK's own tx responses carry — verified for
131
+ * both EOA and UEA-originated requests.
132
+ */
133
+ getReadsByTx(txHash: string): Promise<QueryReadsByTxResponse>;
101
134
  /**
102
135
  * Queries Push Chain's uexecutor v2 gRPC service for a UniversalTx by its ID.
103
136
  * V2 returns expanded OutboundTx fields and repeated outbound_tx array.