@pushchain/core 6.0.20 → 6.0.21

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 (111) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/package.json +1 -1
  3. package/src/lib/cache/cache.js +2 -0
  4. package/src/lib/constants/abi/index.d.ts +1 -0
  5. package/src/lib/constants/abi/index.js +8 -1
  6. package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
  7. package/src/lib/constants/abi/pc20.evm.js +150 -0
  8. package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
  9. package/src/lib/constants/abi/prc20.evm.js +97 -0
  10. package/src/lib/constants/abi/universalGatewayV0.json +1 -1
  11. package/src/lib/constants/chain.js +38 -8
  12. package/src/lib/constants/selectors.js +2 -2
  13. package/src/lib/constants/tokens.js +4 -3
  14. package/src/lib/formatters.js +16 -6
  15. package/src/lib/generated/uexecutor/v1/query.js +2 -4
  16. package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
  17. package/src/lib/generated/uexecutor/v1/types.js +90 -47
  18. package/src/lib/generated/uexecutor/v2/query.js +2 -4
  19. package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
  20. package/src/lib/generated/uexecutor/v2/types.js +49 -33
  21. package/src/lib/generated/v1/tx.js +30 -37
  22. package/src/lib/index.d.ts +3 -0
  23. package/src/lib/index.js +21 -3
  24. package/src/lib/internal/buffer.js +1 -2
  25. package/src/lib/orchestrator/cea-utils.js +73 -83
  26. package/src/lib/orchestrator/internals/account-manager.js +130 -139
  27. package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
  28. package/src/lib/orchestrator/internals/cascade.js +1184 -1059
  29. package/src/lib/orchestrator/internals/confirmation.js +138 -148
  30. package/src/lib/orchestrator/internals/error-decoder.js +1 -1
  31. package/src/lib/orchestrator/internals/errors.js +12 -3
  32. package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
  33. package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
  34. package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
  35. package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
  36. package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
  37. package/src/lib/orchestrator/internals/execute-standard.js +339 -342
  38. package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
  39. package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
  40. package/src/lib/orchestrator/internals/gateway-client.js +102 -103
  41. package/src/lib/orchestrator/internals/helpers.js +30 -27
  42. package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
  43. package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
  44. package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
  45. package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
  46. package/src/lib/orchestrator/internals/payload-builder.js +119 -100
  47. package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
  48. package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
  49. package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
  50. package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
  51. package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
  52. package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
  53. package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
  54. package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
  55. package/src/lib/orchestrator/internals/pc20/export.js +412 -0
  56. package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
  57. package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
  58. package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
  59. package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
  60. package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
  61. package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
  62. package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
  63. package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
  64. package/src/lib/orchestrator/internals/preflight.js +1 -1
  65. package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
  66. package/src/lib/orchestrator/internals/push-chain-tx.js +319 -329
  67. package/src/lib/orchestrator/internals/quote.js +90 -94
  68. package/src/lib/orchestrator/internals/rescue.js +76 -79
  69. package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
  70. package/src/lib/orchestrator/internals/response-builder.js +817 -701
  71. package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
  72. package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
  73. package/src/lib/orchestrator/internals/signing.js +78 -83
  74. package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
  75. package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
  76. package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
  77. package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
  78. package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
  79. package/src/lib/orchestrator/internals/svm-rent.js +163 -141
  80. package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
  81. package/src/lib/orchestrator/internals/uea-manager.js +89 -86
  82. package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
  83. package/src/lib/orchestrator/orchestrator.js +217 -200
  84. package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
  85. package/src/lib/orchestrator/orchestrator.types.js +19 -0
  86. package/src/lib/orchestrator/payload-builders.d.ts +2 -2
  87. package/src/lib/orchestrator/payload-builders.js +26 -24
  88. package/src/lib/orchestrator/route-detector.js +26 -9
  89. package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
  90. package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
  91. package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
  92. package/src/lib/price-fetch/price-fetch.js +67 -68
  93. package/src/lib/progress-hook/progress-hook.js +124 -72
  94. package/src/lib/push-chain/push-chain.js +171 -153
  95. package/src/lib/push-client/push-client.js +223 -237
  96. package/src/lib/universal/account/account.js +349 -365
  97. package/src/lib/universal/signer/signer.js +306 -294
  98. package/src/lib/universal-tx-detector/auto-detect.js +55 -60
  99. package/src/lib/universal-tx-detector/cascade.js +160 -172
  100. package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
  101. package/src/lib/universal-tx-detector/classify.js +2 -3
  102. package/src/lib/universal-tx-detector/detector-svm.js +139 -147
  103. package/src/lib/universal-tx-detector/detector.js +145 -157
  104. package/src/lib/universal-tx-detector/normalize.js +7 -7
  105. package/src/lib/utils/external-tx-hash.js +1 -2
  106. package/src/lib/utils.d.ts +44 -0
  107. package/src/lib/utils.js +762 -683
  108. package/src/lib/vm-client/evm-client.js +186 -202
  109. package/src/lib/vm-client/svm-client.d.ts +1 -1
  110. package/src/lib/vm-client/svm-client.js +220 -224
  111. package/src/lib/vm-client/vm-client.types.d.ts +14 -2
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.listAutoProbeChains = listAutoProbeChains;
4
4
  exports.detectUniversalTxAuto = detectUniversalTxAuto;
5
- const tslib_1 = require("tslib");
6
5
  /**
7
6
  * Stage 4a — chain auto-detection.
8
7
  *
@@ -31,8 +30,7 @@ const PUSH_CHAIN_CAIPS = [
31
30
  */
32
31
  function listAutoProbeChains() {
33
32
  const supported = Object.keys(chain_1.CHAIN_INFO).filter((c) => {
34
- var _a;
35
- const vm = (_a = chain_1.CHAIN_INFO[c]) === null || _a === void 0 ? void 0 : _a.vm;
33
+ const vm = chain_1.CHAIN_INFO[c]?.vm;
36
34
  return vm === enums_1.VM.EVM || vm === enums_1.VM.SVM;
37
35
  });
38
36
  const push = [];
@@ -49,64 +47,61 @@ function listAutoProbeChains() {
49
47
  * Probe every supported chain in parallel and return the first detection
50
48
  * with a recognized universal-tx kind.
51
49
  */
52
- function detectUniversalTxAuto(txHash_1) {
53
- return tslib_1.__awaiter(this, arguments, void 0, function* (txHash, opts = {}) {
54
- var _a, _b;
55
- const chains = (_a = opts.chains) !== null && _a !== void 0 ? _a : listAutoProbeChains();
56
- const exhaustive = (_b = opts.exhaustive) !== null && _b !== void 0 ? _b : false;
57
- const attempts = [];
58
- // Race probes. When a non-UNKNOWN detection lands, resolve early (unless
59
- // `exhaustive` is set).
60
- const seen = [];
61
- yield new Promise((resolve) => {
62
- let remaining = chains.length;
63
- let resolved = false;
64
- const finish = () => {
65
- if (resolved)
66
- return;
67
- resolved = true;
68
- resolve();
69
- };
70
- if (chains.length === 0)
71
- return finish();
72
- for (const chain of chains) {
73
- (0, detector_1.detectUniversalTx)(txHash, chain, {
74
- pushClient: opts.pushClient,
75
- rpcUrls: opts.rpcUrls,
76
- pushNetwork: opts.pushNetwork,
77
- skipPushChainLookup: opts.skipPushChainLookup,
78
- })
79
- .then((d) => {
80
- const matched = d.kind !== 'UNKNOWN';
81
- attempts.push({ chain, matched, kind: d.kind });
82
- if (matched)
83
- seen.push(d);
84
- if (matched && !exhaustive)
85
- finish();
86
- })
87
- .catch((err) => {
88
- attempts.push({
89
- chain,
90
- matched: false,
91
- kind: 'UNKNOWN',
92
- error: err instanceof Error ? err.message : String(err),
93
- });
94
- })
95
- .finally(() => {
96
- remaining -= 1;
97
- if (remaining === 0)
98
- finish();
50
+ async function detectUniversalTxAuto(txHash, opts = {}) {
51
+ const chains = opts.chains ?? listAutoProbeChains();
52
+ const exhaustive = opts.exhaustive ?? false;
53
+ const attempts = [];
54
+ // Race probes. When a non-UNKNOWN detection lands, resolve early (unless
55
+ // `exhaustive` is set).
56
+ const seen = [];
57
+ await new Promise((resolve) => {
58
+ let remaining = chains.length;
59
+ let resolved = false;
60
+ const finish = () => {
61
+ if (resolved)
62
+ return;
63
+ resolved = true;
64
+ resolve();
65
+ };
66
+ if (chains.length === 0)
67
+ return finish();
68
+ for (const chain of chains) {
69
+ (0, detector_1.detectUniversalTx)(txHash, chain, {
70
+ pushClient: opts.pushClient,
71
+ rpcUrls: opts.rpcUrls,
72
+ pushNetwork: opts.pushNetwork,
73
+ skipPushChainLookup: opts.skipPushChainLookup,
74
+ })
75
+ .then((d) => {
76
+ const matched = d.kind !== 'UNKNOWN';
77
+ attempts.push({ chain, matched, kind: d.kind });
78
+ if (matched)
79
+ seen.push(d);
80
+ if (matched && !exhaustive)
81
+ finish();
82
+ })
83
+ .catch((err) => {
84
+ attempts.push({
85
+ chain,
86
+ matched: false,
87
+ kind: 'UNKNOWN',
88
+ error: err instanceof Error ? err.message : String(err),
99
89
  });
100
- }
101
- });
102
- // Sort attempts so matched chains come first for deterministic caller UX.
103
- attempts.sort((a, b) => (a.matched === b.matched ? 0 : a.matched ? -1 : 1));
104
- // Prefer the first chain from the probe list that matched — preserves
105
- // Push-first order when exhaustive=true.
106
- const winner = chains
107
- .map((c) => seen.find((d) => d.chain === c))
108
- .find((d) => d !== undefined);
109
- return { detection: winner, attempts };
90
+ })
91
+ .finally(() => {
92
+ remaining -= 1;
93
+ if (remaining === 0)
94
+ finish();
95
+ });
96
+ }
110
97
  });
98
+ // Sort attempts so matched chains come first for deterministic caller UX.
99
+ attempts.sort((a, b) => (a.matched === b.matched ? 0 : a.matched ? -1 : 1));
100
+ // Prefer the first chain from the probe list that matched — preserves
101
+ // Push-first order when exhaustive=true.
102
+ const winner = chains
103
+ .map((c) => seen.find((d) => d.chain === c))
104
+ .find((d) => d !== undefined);
105
+ return { detection: winner, attempts };
111
106
  }
112
107
  //# sourceMappingURL=auto-detect.js.map
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PUSH_NETWORK = void 0;
4
4
  exports.traceUniversalTxCascade = traceUniversalTxCascade;
5
5
  exports.flattenCascade = flattenCascade;
6
- const tslib_1 = require("tslib");
7
6
  /**
8
7
  * Stage 3 — recursive cascade walker.
9
8
  *
@@ -35,189 +34,178 @@ const PUSH_CHAIN_CAIPS = new Set([
35
34
  * Walk the universal-tx graph starting from `(startHash, startChain)` and
36
35
  * return the full cascade tree.
37
36
  */
38
- function traceUniversalTxCascade(startHash, startChain, opts) {
39
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
40
- var _a, _b;
41
- const state = {
42
- visited: new Set(),
43
- pushChain: (_a = opts.pushChain) !== null && _a !== void 0 ? _a : enums_1.CHAIN.PUSH_TESTNET_DONUT,
44
- maxDepth: (_b = opts.maxDepth) !== null && _b !== void 0 ? _b : 4,
45
- notes: [],
46
- };
47
- const root = yield walk(startHash, startChain, 0, state, opts);
48
- if (!root) {
49
- // Should never happen for depth=0; return an empty detection node so the
50
- // caller has something to render. No outbound summaries → nothing to
51
- // normalize, but we still pass through `normalizeCascadeNodeForUser`
52
- // for symmetry with the happy path below.
53
- return (0, normalize_1.normalizeCascadeNodeForUser)({
54
- detection: {
55
- txHash: startHash,
56
- chain: startChain,
57
- kind: 'UNKNOWN',
58
- emitters: [],
59
- decoded: {},
60
- matchingLogs: [],
61
- detections: [],
62
- notes: ['cascade: unable to fetch root'],
63
- },
64
- children: [],
65
- depth: 0,
66
- });
67
- }
68
- // User-facing normalization pass — recursively rewrites every
69
- // `PushChainOutboundSummary.externalTxHash` in the tree to base58 for SVM
70
- // destinations. Each internal `detectUniversalTx` call (in `walk`) already
71
- // produced a normalized detection; this final pass also normalizes the
72
- // edge-level `relation` summaries inside `expandPushOutbounds` /
73
- // `expandExternalChildInbounds` which build summaries DIRECTLY (without
74
- // going through `detectUniversalTx`).
75
- return (0, normalize_1.normalizeCascadeNodeForUser)(root);
76
- });
77
- }
78
- // ── Core recursion ────────────────────────────────────────────────────
79
- function walk(txHash, chain, depth, state, opts, knownUtxId) {
80
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
81
- var _a;
82
- const key = `${chain}::${txHash.toLowerCase()}`;
83
- if (state.visited.has(key)) {
84
- // Return a stub node representing the cycle — callers can detect via
85
- // `truncated === 'cycle'`.
86
- return null;
87
- }
88
- state.visited.add(key);
89
- const chainInfo = chain_1.CHAIN_INFO[chain];
90
- if (!chainInfo)
91
- return null;
92
- if (chainInfo.vm !== enums_1.VM.EVM && chainInfo.vm !== enums_1.VM.SVM)
93
- return null;
94
- const detection = yield (0, detector_1.detectUniversalTx)(txHash, chain, {
95
- pushClient: opts.pushClient,
96
- rpcUrls: opts.rpcUrls,
97
- // We run our own cosmos queries below to build the cascade; skip the
98
- // detector's built-in single-record lookup to avoid redundant traffic.
99
- skipPushChainLookup: true,
37
+ async function traceUniversalTxCascade(startHash, startChain, opts) {
38
+ const state = {
39
+ visited: new Set(),
40
+ pushChain: opts.pushChain ?? enums_1.CHAIN.PUSH_TESTNET_DONUT,
41
+ maxDepth: opts.maxDepth ?? 4,
42
+ notes: [],
43
+ };
44
+ const root = await walk(startHash, startChain, 0, state, opts);
45
+ if (!root) {
46
+ // Should never happen for depth=0; return an empty detection node so the
47
+ // caller has something to render. No outbound summaries → nothing to
48
+ // normalize, but we still pass through `normalizeCascadeNodeForUser`
49
+ // for symmetry with the happy path below.
50
+ return (0, normalize_1.normalizeCascadeNodeForUser)({
51
+ detection: {
52
+ txHash: startHash,
53
+ chain: startChain,
54
+ kind: 'UNKNOWN',
55
+ emitters: [],
56
+ decoded: {},
57
+ matchingLogs: [],
58
+ detections: [],
59
+ notes: ['cascade: unable to fetch root'],
60
+ },
61
+ children: [],
62
+ depth: 0,
100
63
  });
101
- const node = { detection, children: [], depth };
102
- (_a = opts.onNode) === null || _a === void 0 ? void 0 : _a.call(opts, node);
103
- if (depth >= state.maxDepth) {
104
- node.truncated = 'maxDepth';
105
- return node;
106
- }
107
- if (PUSH_CHAIN_CAIPS.has(chain)) {
108
- // Push Chain node — walk outbounds from the pc utx record.
109
- yield expandPushOutbounds(node, txHash, chain, state, opts, knownUtxId);
110
- }
111
- else {
112
- // External chain — walk child inbounds (CEA-originated UniversalTx logs).
113
- yield expandExternalChildInbounds(node, detection, state, opts);
114
- }
115
- return node;
116
- });
64
+ }
65
+ // User-facing normalization pass — recursively rewrites every
66
+ // `PushChainOutboundSummary.externalTxHash` in the tree to base58 for SVM
67
+ // destinations. Each internal `detectUniversalTx` call (in `walk`) already
68
+ // produced a normalized detection; this final pass also normalizes the
69
+ // edge-level `relation` summaries inside `expandPushOutbounds` /
70
+ // `expandExternalChildInbounds` which build summaries DIRECTLY (without
71
+ // going through `detectUniversalTx`).
72
+ return (0, normalize_1.normalizeCascadeNodeForUser)(root);
117
73
  }
118
- function expandPushOutbounds(node, txHash, chain, state, opts, knownUtxId) {
119
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
120
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
121
- // Prefer the caller-supplied utx id — this covers follow-up Push txs that
122
- // were triggered by an external CEA inbound (their outbounds live under
123
- // `sha256(externalCaip:externalHash:logIndex)`, not the PC-derived key).
124
- // For root Push txs the caller omits it and we derive the PC key.
125
- const pcUtxId = knownUtxId !== null && knownUtxId !== void 0 ? knownUtxId : (0, child_inbounds_1.derivePcUniversalTxId)(chain, txHash);
126
- try {
127
- const resp = yield opts.pushClient.getUniversalTxByIdV2(pcUtxId.slice(2));
128
- const utx = resp === null || resp === void 0 ? void 0 : resp.universalTx;
129
- if (!utx || !utx.outboundTx || utx.outboundTx.length === 0)
130
- return;
131
- for (const ob of utx.outboundTx) {
132
- const destChainStr = (_a = ob.destinationChain) !== null && _a !== void 0 ? _a : '';
133
- const externalTxHash = ((_b = ob.observedTx) === null || _b === void 0 ? void 0 : _b.txHash) || '';
134
- const summary = {
135
- subTxId: (_c = ob.id) !== null && _c !== void 0 ? _c : '',
136
- status: outboundStatusName(ob.outboundStatus),
137
- destinationChain: destChainStr,
138
- externalTxHash: externalTxHash || undefined,
139
- amount: ob.amount,
140
- recipient: ob.recipient,
141
- };
142
- if (!externalTxHash || !isSupportedChainCaip(destChainStr)) {
143
- node.children.push({
144
- edgeKind: 'outbound',
145
- relation: summary,
146
- node: null,
147
- });
148
- }
149
- else {
150
- const childNode = yield walk(externalTxHash, destChainStr, node.depth + 1, state, opts);
151
- node.children.push({
152
- edgeKind: 'outbound',
153
- relation: summary,
154
- node: childNode,
155
- });
156
- }
157
- // Refund edges: the chain records two refund-tx fields on each outbound.
158
- // - pcRefundExecution (field 18) — gas refund tx after a successful
159
- // outbound (push-chain/x/uexecutor/keeper/outbound.go).
160
- // - pcRevertExecution — revert/refund tx when the outbound reverted.
161
- // Surface both as pc-refund edges and recurse into the refund tx on
162
- // Push Chain.
163
- const refundTxs = [];
164
- if (ob.pcRefundExecution)
165
- refundTxs.push(ob.pcRefundExecution);
166
- if (ob.pcRevertExecution)
167
- refundTxs.push(ob.pcRevertExecution);
168
- for (const refund of refundTxs) {
169
- if (!refund.txHash)
170
- continue;
171
- const refundSummary = {
172
- txHash: refund.txHash,
173
- sender: (_d = refund.sender) !== null && _d !== void 0 ? _d : '',
174
- gasUsed: typeof refund.gasUsed === 'bigint'
175
- ? Number(refund.gasUsed)
176
- : (_e = refund.gasUsed) !== null && _e !== void 0 ? _e : 0,
177
- blockHeight: typeof refund.blockHeight === 'bigint'
178
- ? Number(refund.blockHeight)
179
- : (_f = refund.blockHeight) !== null && _f !== void 0 ? _f : 0,
180
- status: (_g = refund.status) !== null && _g !== void 0 ? _g : '',
181
- errorMsg: (_h = refund.errorMsg) !== null && _h !== void 0 ? _h : '',
182
- parentOutboundId: (_j = ob.id) !== null && _j !== void 0 ? _j : '',
183
- };
184
- const refundNode = yield walk(refund.txHash, chain, node.depth + 1, state, opts);
185
- node.children.push({
186
- edgeKind: 'pc-refund',
187
- relation: refundSummary,
188
- node: refundNode,
189
- });
190
- }
191
- }
192
- }
193
- catch (err) {
194
- node.detection.notes.push(`cascade: pc outbound lookup failed: ${err instanceof Error ? err.message : String(err)}`);
195
- }
74
+ // ── Core recursion ────────────────────────────────────────────────────
75
+ async function walk(txHash, chain, depth, state, opts, knownUtxId) {
76
+ const key = `${chain}::${txHash.toLowerCase()}`;
77
+ if (state.visited.has(key)) {
78
+ // Return a stub node representing the cycle — callers can detect via
79
+ // `truncated === 'cycle'`.
80
+ return null;
81
+ }
82
+ state.visited.add(key);
83
+ const chainInfo = chain_1.CHAIN_INFO[chain];
84
+ if (!chainInfo)
85
+ return null;
86
+ if (chainInfo.vm !== enums_1.VM.EVM && chainInfo.vm !== enums_1.VM.SVM)
87
+ return null;
88
+ const detection = await (0, detector_1.detectUniversalTx)(txHash, chain, {
89
+ pushClient: opts.pushClient,
90
+ rpcUrls: opts.rpcUrls,
91
+ // We run our own cosmos queries below to build the cascade; skip the
92
+ // detector's built-in single-record lookup to avoid redundant traffic.
93
+ skipPushChainLookup: true,
196
94
  });
95
+ const node = { detection, children: [], depth };
96
+ opts.onNode?.(node);
97
+ if (depth >= state.maxDepth) {
98
+ node.truncated = 'maxDepth';
99
+ return node;
100
+ }
101
+ if (PUSH_CHAIN_CAIPS.has(chain)) {
102
+ // Push Chain node — walk outbounds from the pc utx record.
103
+ await expandPushOutbounds(node, txHash, chain, state, opts, knownUtxId);
104
+ }
105
+ else {
106
+ // External chain — walk child inbounds (CEA-originated UniversalTx logs).
107
+ await expandExternalChildInbounds(node, detection, state, opts);
108
+ }
109
+ return node;
197
110
  }
198
- function expandExternalChildInbounds(node, detection, state, opts) {
199
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
200
- const resolutions = yield (0, child_inbounds_1.resolveChildInboundsFromDetection)(opts.pushClient, detection, node.detection.notes);
201
- for (const res of resolutions) {
202
- // Walk each Push follow-up tx produced by this inbound.
203
- if (res.pcTxHashes.length === 0) {
111
+ async function expandPushOutbounds(node, txHash, chain, state, opts, knownUtxId) {
112
+ // Prefer the caller-supplied utx id — this covers follow-up Push txs that
113
+ // were triggered by an external CEA inbound (their outbounds live under
114
+ // `sha256(externalCaip:externalHash:logIndex)`, not the PC-derived key).
115
+ // For root Push txs the caller omits it and we derive the PC key.
116
+ const pcUtxId = knownUtxId ?? (0, child_inbounds_1.derivePcUniversalTxId)(chain, txHash);
117
+ try {
118
+ const resp = await opts.pushClient.getUniversalTxByIdV2(pcUtxId.slice(2));
119
+ const utx = resp?.universalTx;
120
+ if (!utx || !utx.outboundTx || utx.outboundTx.length === 0)
121
+ return;
122
+ for (const ob of utx.outboundTx) {
123
+ const destChainStr = ob.destinationChain ?? '';
124
+ const externalTxHash = ob.observedTx?.txHash || '';
125
+ const summary = {
126
+ subTxId: ob.id ?? '',
127
+ status: outboundStatusName(ob.outboundStatus),
128
+ destinationChain: destChainStr,
129
+ externalTxHash: externalTxHash || undefined,
130
+ amount: ob.amount,
131
+ recipient: ob.recipient,
132
+ };
133
+ if (!externalTxHash || !isSupportedChainCaip(destChainStr)) {
204
134
  node.children.push({
205
- edgeKind: 'child-inbound',
206
- relation: res,
135
+ edgeKind: 'outbound',
136
+ relation: summary,
207
137
  node: null,
208
138
  });
209
- continue;
210
139
  }
211
- for (const pcHash of res.pcTxHashes) {
212
- const childNode = yield walk(pcHash, state.pushChain, node.depth + 1, state, opts, res.universalTxId);
140
+ else {
141
+ const childNode = await walk(externalTxHash, destChainStr, node.depth + 1, state, opts);
213
142
  node.children.push({
214
- edgeKind: 'child-inbound',
215
- relation: res,
143
+ edgeKind: 'outbound',
144
+ relation: summary,
216
145
  node: childNode,
217
146
  });
218
147
  }
148
+ // Refund edges: the chain records two refund-tx fields on each outbound.
149
+ // - pcRefundExecution (field 18) — gas refund tx after a successful
150
+ // outbound (push-chain/x/uexecutor/keeper/outbound.go).
151
+ // - pcRevertExecution — revert/refund tx when the outbound reverted.
152
+ // Surface both as pc-refund edges and recurse into the refund tx on
153
+ // Push Chain.
154
+ const refundTxs = [];
155
+ if (ob.pcRefundExecution)
156
+ refundTxs.push(ob.pcRefundExecution);
157
+ if (ob.pcRevertExecution)
158
+ refundTxs.push(ob.pcRevertExecution);
159
+ for (const refund of refundTxs) {
160
+ if (!refund.txHash)
161
+ continue;
162
+ const refundSummary = {
163
+ txHash: refund.txHash,
164
+ sender: refund.sender ?? '',
165
+ gasUsed: typeof refund.gasUsed === 'bigint'
166
+ ? Number(refund.gasUsed)
167
+ : refund.gasUsed ?? 0,
168
+ blockHeight: typeof refund.blockHeight === 'bigint'
169
+ ? Number(refund.blockHeight)
170
+ : refund.blockHeight ?? 0,
171
+ status: refund.status ?? '',
172
+ errorMsg: refund.errorMsg ?? '',
173
+ parentOutboundId: ob.id ?? '',
174
+ };
175
+ const refundNode = await walk(refund.txHash, chain, node.depth + 1, state, opts);
176
+ node.children.push({
177
+ edgeKind: 'pc-refund',
178
+ relation: refundSummary,
179
+ node: refundNode,
180
+ });
181
+ }
219
182
  }
220
- });
183
+ }
184
+ catch (err) {
185
+ node.detection.notes.push(`cascade: pc outbound lookup failed: ${err instanceof Error ? err.message : String(err)}`);
186
+ }
187
+ }
188
+ async function expandExternalChildInbounds(node, detection, state, opts) {
189
+ const resolutions = await (0, child_inbounds_1.resolveChildInboundsFromDetection)(opts.pushClient, detection, node.detection.notes);
190
+ for (const res of resolutions) {
191
+ // Walk each Push follow-up tx produced by this inbound.
192
+ if (res.pcTxHashes.length === 0) {
193
+ node.children.push({
194
+ edgeKind: 'child-inbound',
195
+ relation: res,
196
+ node: null,
197
+ });
198
+ continue;
199
+ }
200
+ for (const pcHash of res.pcTxHashes) {
201
+ const childNode = await walk(pcHash, state.pushChain, node.depth + 1, state, opts, res.universalTxId);
202
+ node.children.push({
203
+ edgeKind: 'child-inbound',
204
+ relation: res,
205
+ node: childNode,
206
+ });
207
+ }
208
+ }
221
209
  }
222
210
  // ── Utilities ─────────────────────────────────────────────────────────
223
211
  function isSupportedChainCaip(caip) {
@@ -239,7 +227,7 @@ function outboundStatusName(n) {
239
227
  case 3:
240
228
  return 'REVERTED';
241
229
  default:
242
- return `UNKNOWN(${n !== null && n !== void 0 ? n : '?'})`;
230
+ return `UNKNOWN(${n ?? '?'})`;
243
231
  }
244
232
  }
245
233
  /** Flatten a cascade tree into depth-first linear node list (root first). */