@pushchain/core 6.0.19 → 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.
- package/CHANGELOG.md +54 -0
- package/package.json +1 -1
- package/src/lib/cache/cache.js +2 -0
- package/src/lib/constants/abi/index.d.ts +1 -0
- package/src/lib/constants/abi/index.js +8 -1
- package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
- package/src/lib/constants/abi/pc20.evm.js +150 -0
- package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
- package/src/lib/constants/abi/prc20.evm.js +97 -0
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +38 -8
- package/src/lib/constants/selectors.js +2 -2
- package/src/lib/constants/tokens.js +4 -3
- package/src/lib/formatters.js +16 -6
- package/src/lib/generated/uexecutor/v1/query.js +2 -4
- package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v1/types.js +90 -47
- package/src/lib/generated/uexecutor/v2/query.js +2 -4
- package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
- package/src/lib/generated/uexecutor/v2/types.js +49 -33
- package/src/lib/generated/v1/tx.js +30 -37
- package/src/lib/index.d.ts +4 -1
- package/src/lib/index.js +21 -3
- package/src/lib/internal/buffer.js +1 -2
- package/src/lib/orchestrator/cea-utils.js +73 -83
- package/src/lib/orchestrator/internals/account-manager.js +130 -139
- package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
- package/src/lib/orchestrator/internals/cascade.js +1184 -1059
- package/src/lib/orchestrator/internals/confirmation.js +138 -148
- package/src/lib/orchestrator/internals/error-decoder.js +1 -1
- package/src/lib/orchestrator/internals/errors.js +12 -3
- package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
- package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
- package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
- package/src/lib/orchestrator/internals/execute-standard.js +339 -342
- package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
- package/src/lib/orchestrator/internals/gateway-client.js +102 -103
- package/src/lib/orchestrator/internals/helpers.js +30 -27
- package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
- package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
- package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
- package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
- package/src/lib/orchestrator/internals/payload-builder.js +119 -100
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
- package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
- package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
- package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
- package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
- package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
- package/src/lib/orchestrator/internals/pc20/export.js +412 -0
- package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
- package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
- package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
- package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
- package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
- package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
- package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
- package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
- package/src/lib/orchestrator/internals/preflight.js +1 -1
- package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
- package/src/lib/orchestrator/internals/push-chain-tx.js +319 -331
- package/src/lib/orchestrator/internals/quote.js +90 -94
- package/src/lib/orchestrator/internals/rescue.js +76 -79
- package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
- package/src/lib/orchestrator/internals/response-builder.js +817 -701
- package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
- package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
- package/src/lib/orchestrator/internals/signing.js +78 -83
- package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
- package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
- package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
- package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
- package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
- package/src/lib/orchestrator/internals/svm-rent.js +163 -141
- package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
- package/src/lib/orchestrator/internals/uea-manager.js +89 -86
- package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
- package/src/lib/orchestrator/orchestrator.js +217 -200
- package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
- package/src/lib/orchestrator/orchestrator.types.js +19 -0
- package/src/lib/orchestrator/payload-builders.d.ts +2 -2
- package/src/lib/orchestrator/payload-builders.js +26 -24
- package/src/lib/orchestrator/route-detector.js +26 -9
- package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
- package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
- package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
- package/src/lib/price-fetch/price-fetch.js +67 -68
- package/src/lib/progress-hook/progress-hook.js +124 -72
- package/src/lib/push-chain/push-chain.js +171 -153
- package/src/lib/push-client/push-client.js +223 -237
- package/src/lib/universal/account/account.js +349 -365
- package/src/lib/universal/signer/signer.d.ts +2 -1
- package/src/lib/universal/signer/signer.js +315 -299
- package/src/lib/universal-tx-detector/auto-detect.js +55 -60
- package/src/lib/universal-tx-detector/cascade.js +160 -172
- package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
- package/src/lib/universal-tx-detector/classify.js +2 -3
- package/src/lib/universal-tx-detector/detector-svm.js +139 -147
- package/src/lib/universal-tx-detector/detector.js +145 -157
- package/src/lib/universal-tx-detector/normalize.js +7 -7
- package/src/lib/utils/external-tx-hash.js +1 -2
- package/src/lib/utils.d.ts +44 -0
- package/src/lib/utils.js +762 -683
- package/src/lib/vm-client/evm-client.js +186 -202
- package/src/lib/vm-client/svm-client.d.ts +1 -1
- package/src/lib/vm-client/svm-client.js +220 -224
- 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
|
-
|
|
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(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
// `
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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: '
|
|
206
|
-
relation:
|
|
135
|
+
edgeKind: 'outbound',
|
|
136
|
+
relation: summary,
|
|
207
137
|
node: null,
|
|
208
138
|
});
|
|
209
|
-
continue;
|
|
210
139
|
}
|
|
211
|
-
|
|
212
|
-
const childNode =
|
|
140
|
+
else {
|
|
141
|
+
const childNode = await walk(externalTxHash, destChainStr, node.depth + 1, state, opts);
|
|
213
142
|
node.children.push({
|
|
214
|
-
edgeKind: '
|
|
215
|
-
relation:
|
|
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
|
|
230
|
+
return `UNKNOWN(${n ?? '?'})`;
|
|
243
231
|
}
|
|
244
232
|
}
|
|
245
233
|
/** Flatten a cascade tree into depth-first linear node list (root first). */
|