@pushchain/core 5.1.5-alpha.1 → 5.1.5
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 +19 -0
- package/package.json +1 -1
- package/src/lib/constants/abi/index.d.ts +2 -0
- package/src/lib/constants/abi/index.js +6 -1
- package/src/lib/constants/abi/uniswap-v3-router.evm.d.ts +58 -0
- package/src/lib/constants/abi/uniswap-v3-router.evm.js +41 -0
- package/src/lib/constants/abi/wpc.evm.d.ts +24 -0
- package/src/lib/constants/abi/wpc.evm.js +27 -0
- package/src/lib/constants/chain.d.ts +1 -0
- package/src/lib/constants/chain.js +8 -6
- package/src/lib/constants/tokens.js +3 -3
- package/src/lib/generated/uexecutor/v2/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v2/types.js +96 -3
- package/src/lib/orchestrator/internals/cascade.d.ts +1 -1
- package/src/lib/orchestrator/internals/cascade.js +521 -239
- package/src/lib/orchestrator/internals/confirmation.js +60 -15
- package/src/lib/orchestrator/internals/context.d.ts +23 -0
- package/src/lib/orchestrator/internals/context.js +54 -0
- package/src/lib/orchestrator/internals/execute-funds-only.js +47 -21
- package/src/lib/orchestrator/internals/execute-funds-payload.js +53 -31
- package/src/lib/orchestrator/internals/execute-standard.js +137 -26
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +5 -2
- package/src/lib/orchestrator/internals/gas-calculator.js +59 -11
- package/src/lib/orchestrator/internals/gas-usd-sizer.d.ts +53 -0
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +165 -0
- package/src/lib/orchestrator/internals/helpers.js +2 -0
- package/src/lib/orchestrator/internals/inbound-tracker.d.ts +83 -0
- package/src/lib/orchestrator/internals/inbound-tracker.js +322 -0
- package/src/lib/orchestrator/internals/index.d.ts +3 -1
- package/src/lib/orchestrator/internals/index.js +8 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +32 -1
- package/src/lib/orchestrator/internals/outbound-sync.js +154 -17
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +28 -0
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +285 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +23 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.js +72 -0
- package/src/lib/orchestrator/internals/push-chain-tx.d.ts +27 -1
- package/src/lib/orchestrator/internals/push-chain-tx.js +111 -15
- package/src/lib/orchestrator/internals/rescue.js +1 -1
- package/src/lib/orchestrator/internals/response-builder.d.ts +5 -0
- package/src/lib/orchestrator/internals/response-builder.js +242 -66
- package/src/lib/orchestrator/internals/route-handlers.js +480 -206
- package/src/lib/orchestrator/internals/tx-transformer.js +293 -35
- package/src/lib/orchestrator/orchestrator.d.ts +7 -1
- package/src/lib/orchestrator/orchestrator.js +108 -56
- package/src/lib/orchestrator/orchestrator.types.d.ts +111 -5
- package/src/lib/orchestrator/payload-builders.d.ts +16 -0
- package/src/lib/orchestrator/payload-builders.js +6 -5
- package/src/lib/orchestrator/route-detector.js +20 -8
- package/src/lib/orchestrator/svm-idl/normalize-address.d.ts +19 -0
- package/src/lib/orchestrator/svm-idl/normalize-address.js +56 -0
- package/src/lib/orchestrator/svm-idl/registry.d.ts +13 -4
- package/src/lib/orchestrator/svm-idl/registry.js +15 -14
- package/src/lib/orchestrator/svm-idl/resolve.js +5 -2
- package/src/lib/progress-hook/progress-hook.d.ts +28 -0
- package/src/lib/progress-hook/progress-hook.js +545 -131
- package/src/lib/progress-hook/progress-hook.types.d.ts +76 -29
- package/src/lib/progress-hook/progress-hook.types.js +74 -35
- package/src/lib/push-client/push-client.d.ts +7 -0
- package/src/lib/push-client/push-client.js +18 -1
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.d.ts +32 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.js +65 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.d.ts +72 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.js +669 -0
- package/src/lib/universal-tx-detector/auto-detect.d.ts +37 -0
- package/src/lib/universal-tx-detector/auto-detect.js +112 -0
- package/src/lib/universal-tx-detector/cascade.d.ts +64 -0
- package/src/lib/universal-tx-detector/cascade.js +254 -0
- package/src/lib/universal-tx-detector/child-inbounds.d.ts +58 -0
- package/src/lib/universal-tx-detector/child-inbounds.js +145 -0
- package/src/lib/universal-tx-detector/classify.d.ts +33 -0
- package/src/lib/universal-tx-detector/classify.js +228 -0
- package/src/lib/universal-tx-detector/detector-svm.d.ts +46 -0
- package/src/lib/universal-tx-detector/detector-svm.js +324 -0
- package/src/lib/universal-tx-detector/detector.d.ts +13 -0
- package/src/lib/universal-tx-detector/detector.js +233 -0
- package/src/lib/universal-tx-detector/events.d.ts +765 -0
- package/src/lib/universal-tx-detector/events.js +241 -0
- package/src/lib/universal-tx-detector/index.d.ts +18 -0
- package/src/lib/universal-tx-detector/index.js +36 -0
- package/src/lib/universal-tx-detector/svm-events.d.ts +41 -0
- package/src/lib/universal-tx-detector/svm-events.js +68 -0
- package/src/lib/universal-tx-detector/types.d.ts +100 -0
- package/src/lib/universal-tx-detector/types.js +3 -0
- package/src/lib/utils.d.ts +30 -13
- package/src/lib/utils.js +47 -21
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CHAIN } from '../constants/enums';
|
|
2
|
+
import type { DetectUniversalTxOptions, UniversalTxDetection } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Every chain registered in CHAIN_INFO whose vm the detector supports
|
|
5
|
+
* (EVM + SVM), ordered Push-first.
|
|
6
|
+
*/
|
|
7
|
+
export declare function listAutoProbeChains(): CHAIN[];
|
|
8
|
+
export interface DetectUniversalTxAutoOptions extends Omit<DetectUniversalTxOptions, 'rpcUrls'> {
|
|
9
|
+
/** Per-chain RPC overrides. Falls back to CHAIN_INFO defaults. */
|
|
10
|
+
rpcUrls?: Partial<Record<CHAIN, string[]>>;
|
|
11
|
+
/**
|
|
12
|
+
* Override the set of chains to probe. Defaults to every EVM chain in
|
|
13
|
+
* CHAIN_INFO with Push Chain first.
|
|
14
|
+
*/
|
|
15
|
+
chains?: CHAIN[];
|
|
16
|
+
/**
|
|
17
|
+
* When true, continue probing all chains even after the first match and
|
|
18
|
+
* return every non-UNKNOWN detection. Default false (return first match).
|
|
19
|
+
*/
|
|
20
|
+
exhaustive?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface AutoDetectionResult {
|
|
23
|
+
/** The chosen detection — the first non-UNKNOWN result. `undefined` if no chain had a universal-tx event. */
|
|
24
|
+
detection?: UniversalTxDetection;
|
|
25
|
+
/** Every chain that was probed, whether or not it matched. */
|
|
26
|
+
attempts: Array<{
|
|
27
|
+
chain: CHAIN;
|
|
28
|
+
matched: boolean;
|
|
29
|
+
kind: UniversalTxDetection['kind'];
|
|
30
|
+
error?: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Probe every supported chain in parallel and return the first detection
|
|
35
|
+
* with a recognized universal-tx kind.
|
|
36
|
+
*/
|
|
37
|
+
export declare function detectUniversalTxAuto(txHash: `0x${string}`, opts?: DetectUniversalTxAutoOptions): Promise<AutoDetectionResult>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listAutoProbeChains = listAutoProbeChains;
|
|
4
|
+
exports.detectUniversalTxAuto = detectUniversalTxAuto;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
/**
|
|
7
|
+
* Stage 4a — chain auto-detection.
|
|
8
|
+
*
|
|
9
|
+
* When a user pastes a tx hash without knowing which chain it lives on,
|
|
10
|
+
* probe every registered EVM chain in parallel, classify the first one that
|
|
11
|
+
* contains a universal-tx event, and return the detection.
|
|
12
|
+
*
|
|
13
|
+
* Probe order:
|
|
14
|
+
* 1. Push Chain CAIPs (most common case for "PC Execution" hashes)
|
|
15
|
+
* 2. All other EVM chains from CHAIN_INFO, in parallel
|
|
16
|
+
*
|
|
17
|
+
* The function resolves as soon as a non-UNKNOWN detection is found. Other
|
|
18
|
+
* pending probes are abandoned via an AbortController-style race.
|
|
19
|
+
*/
|
|
20
|
+
const chain_1 = require("../constants/chain");
|
|
21
|
+
const enums_1 = require("../constants/enums");
|
|
22
|
+
const detector_1 = require("./detector");
|
|
23
|
+
const PUSH_CHAIN_CAIPS = [
|
|
24
|
+
enums_1.CHAIN.PUSH_TESTNET_DONUT,
|
|
25
|
+
enums_1.CHAIN.PUSH_MAINNET,
|
|
26
|
+
enums_1.CHAIN.PUSH_LOCALNET,
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Every chain registered in CHAIN_INFO whose vm the detector supports
|
|
30
|
+
* (EVM + SVM), ordered Push-first.
|
|
31
|
+
*/
|
|
32
|
+
function listAutoProbeChains() {
|
|
33
|
+
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;
|
|
36
|
+
return vm === enums_1.VM.EVM || vm === enums_1.VM.SVM;
|
|
37
|
+
});
|
|
38
|
+
const push = [];
|
|
39
|
+
const rest = [];
|
|
40
|
+
for (const c of supported) {
|
|
41
|
+
if (PUSH_CHAIN_CAIPS.includes(c))
|
|
42
|
+
push.push(c);
|
|
43
|
+
else
|
|
44
|
+
rest.push(c);
|
|
45
|
+
}
|
|
46
|
+
return [...push, ...rest];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Probe every supported chain in parallel and return the first detection
|
|
50
|
+
* with a recognized universal-tx kind.
|
|
51
|
+
*/
|
|
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();
|
|
99
|
+
});
|
|
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 };
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=auto-detect.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { CHAIN, PUSH_NETWORK } from '../constants/enums';
|
|
2
|
+
import type { PushClient } from '../push-client/push-client';
|
|
3
|
+
import { type ChildInboundResolution } from './child-inbounds';
|
|
4
|
+
import type { PushChainOutboundSummary, UniversalTxDetection } from './types';
|
|
5
|
+
export interface PcRefundSummary {
|
|
6
|
+
/** Refund tx on Push Chain. */
|
|
7
|
+
txHash: string;
|
|
8
|
+
sender: string;
|
|
9
|
+
gasUsed: number;
|
|
10
|
+
blockHeight: number;
|
|
11
|
+
status: string;
|
|
12
|
+
errorMsg: string;
|
|
13
|
+
/** subTxId of the parent outbound — useful for UI correlation. */
|
|
14
|
+
parentOutboundId: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CascadeEdge {
|
|
17
|
+
edgeKind: 'outbound' | 'child-inbound' | 'pc-refund';
|
|
18
|
+
/**
|
|
19
|
+
* Summary of the relationship.
|
|
20
|
+
* - `outbound` → PushChainOutboundSummary (cosmos outbound tuple)
|
|
21
|
+
* - `child-inbound` → ChildInboundResolution (destination → Push follow-up)
|
|
22
|
+
* - `pc-refund` → PcRefundSummary (gas-refund tx on Push)
|
|
23
|
+
*/
|
|
24
|
+
relation: PushChainOutboundSummary | ChildInboundResolution | PcRefundSummary;
|
|
25
|
+
/**
|
|
26
|
+
* Expanded child node, or null when the target chain isn't supported /
|
|
27
|
+
* depth is exhausted / an RPC lookup failed.
|
|
28
|
+
*/
|
|
29
|
+
node: CascadeNode | null;
|
|
30
|
+
}
|
|
31
|
+
export interface CascadeNode {
|
|
32
|
+
detection: UniversalTxDetection;
|
|
33
|
+
children: CascadeEdge[];
|
|
34
|
+
/** Depth from the starting node (0 = root). */
|
|
35
|
+
depth: number;
|
|
36
|
+
/** Set when we stopped expanding because of maxDepth or a cycle. */
|
|
37
|
+
truncated?: 'maxDepth' | 'cycle';
|
|
38
|
+
}
|
|
39
|
+
export interface TraceCascadeOptions {
|
|
40
|
+
/** Required — cosmos queries drive the cascade. */
|
|
41
|
+
pushClient: PushClient;
|
|
42
|
+
/** Default 4. Depth 0 is the root. */
|
|
43
|
+
maxDepth?: number;
|
|
44
|
+
/** Per-chain RPC overrides. Falls back to CHAIN_INFO defaultRPC. */
|
|
45
|
+
rpcUrls?: Partial<Record<CHAIN, string[]>>;
|
|
46
|
+
/**
|
|
47
|
+
* Which Push Chain CAIP to recurse into when walking child-inbounds.
|
|
48
|
+
* Defaults to CHAIN.PUSH_TESTNET_DONUT.
|
|
49
|
+
*/
|
|
50
|
+
pushChain?: CHAIN;
|
|
51
|
+
/**
|
|
52
|
+
* Called with each node as it is resolved. Useful for progressive UI.
|
|
53
|
+
*/
|
|
54
|
+
onNode?: (node: CascadeNode) => void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Walk the universal-tx graph starting from `(startHash, startChain)` and
|
|
58
|
+
* return the full cascade tree.
|
|
59
|
+
*/
|
|
60
|
+
export declare function traceUniversalTxCascade(startHash: `0x${string}`, startChain: CHAIN, opts: TraceCascadeOptions): Promise<CascadeNode>;
|
|
61
|
+
/** Flatten a cascade tree into depth-first linear node list (root first). */
|
|
62
|
+
export declare function flattenCascade(root: CascadeNode): CascadeNode[];
|
|
63
|
+
export type { PublicClient } from 'viem';
|
|
64
|
+
export { PUSH_NETWORK };
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PUSH_NETWORK = void 0;
|
|
4
|
+
exports.traceUniversalTxCascade = traceUniversalTxCascade;
|
|
5
|
+
exports.flattenCascade = flattenCascade;
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
/**
|
|
8
|
+
* Stage 3 — recursive cascade walker.
|
|
9
|
+
*
|
|
10
|
+
* Starting from any universal-tx hash on a supported chain, walk forward
|
|
11
|
+
* across the universal-tx graph and return a tree:
|
|
12
|
+
*
|
|
13
|
+
* Push root ──outbound──▶ Destination finalize ──child-inbound──▶ Follow-up Push tx ─...
|
|
14
|
+
*
|
|
15
|
+
* Uses the chain-module key formulas (sha256-based; see
|
|
16
|
+
* push-chain/x/uexecutor/types/keys.go) to resolve:
|
|
17
|
+
* - Push-initiated outbounds → destination external txs (via pcTx utx record)
|
|
18
|
+
* - Destination CEA-originated inbounds → child Push txs (via inbound utx record)
|
|
19
|
+
*
|
|
20
|
+
* Cycle-safe via a `visited` set on (chain, txHash). Bounded by maxDepth.
|
|
21
|
+
*/
|
|
22
|
+
const viem_1 = require("viem");
|
|
23
|
+
const chain_1 = require("../constants/chain");
|
|
24
|
+
const enums_1 = require("../constants/enums");
|
|
25
|
+
Object.defineProperty(exports, "PUSH_NETWORK", { enumerable: true, get: function () { return enums_1.PUSH_NETWORK; } });
|
|
26
|
+
const child_inbounds_1 = require("./child-inbounds");
|
|
27
|
+
const detector_1 = require("./detector");
|
|
28
|
+
const PUSH_CHAIN_CAIPS = new Set([
|
|
29
|
+
enums_1.CHAIN.PUSH_MAINNET,
|
|
30
|
+
enums_1.CHAIN.PUSH_TESTNET_DONUT,
|
|
31
|
+
enums_1.CHAIN.PUSH_LOCALNET,
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Walk the universal-tx graph starting from `(startHash, startChain)` and
|
|
35
|
+
* return the full cascade tree.
|
|
36
|
+
*/
|
|
37
|
+
function traceUniversalTxCascade(startHash, startChain, opts) {
|
|
38
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
const state = {
|
|
41
|
+
visited: new Set(),
|
|
42
|
+
pushChain: (_a = opts.pushChain) !== null && _a !== void 0 ? _a : enums_1.CHAIN.PUSH_TESTNET_DONUT,
|
|
43
|
+
maxDepth: (_b = opts.maxDepth) !== null && _b !== void 0 ? _b : 4,
|
|
44
|
+
notes: [],
|
|
45
|
+
};
|
|
46
|
+
const root = yield walk(startHash, startChain, 0, state, opts);
|
|
47
|
+
if (!root) {
|
|
48
|
+
// Should never happen for depth=0; return an empty detection node so the
|
|
49
|
+
// caller has something to render.
|
|
50
|
+
return {
|
|
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,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return root;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// ── Core recursion ────────────────────────────────────────────────────
|
|
69
|
+
function walk(txHash, chain, depth, state, opts, knownUtxId) {
|
|
70
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
var _a;
|
|
72
|
+
const key = `${chain}::${txHash.toLowerCase()}`;
|
|
73
|
+
if (state.visited.has(key)) {
|
|
74
|
+
// Return a stub node representing the cycle — callers can detect via
|
|
75
|
+
// `truncated === 'cycle'`.
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
state.visited.add(key);
|
|
79
|
+
const chainInfo = chain_1.CHAIN_INFO[chain];
|
|
80
|
+
if (!chainInfo)
|
|
81
|
+
return null;
|
|
82
|
+
if (chainInfo.vm !== enums_1.VM.EVM && chainInfo.vm !== enums_1.VM.SVM)
|
|
83
|
+
return null;
|
|
84
|
+
const detection = yield (0, detector_1.detectUniversalTx)(txHash, chain, {
|
|
85
|
+
pushClient: opts.pushClient,
|
|
86
|
+
rpcUrls: opts.rpcUrls,
|
|
87
|
+
// We run our own cosmos queries below to build the cascade; skip the
|
|
88
|
+
// detector's built-in single-record lookup to avoid redundant traffic.
|
|
89
|
+
skipPushChainLookup: true,
|
|
90
|
+
});
|
|
91
|
+
const node = { detection, children: [], depth };
|
|
92
|
+
(_a = opts.onNode) === null || _a === void 0 ? void 0 : _a.call(opts, node);
|
|
93
|
+
if (depth >= state.maxDepth) {
|
|
94
|
+
node.truncated = 'maxDepth';
|
|
95
|
+
return node;
|
|
96
|
+
}
|
|
97
|
+
if (PUSH_CHAIN_CAIPS.has(chain)) {
|
|
98
|
+
// Push Chain node — walk outbounds from the pc utx record.
|
|
99
|
+
yield expandPushOutbounds(node, txHash, chain, state, opts, knownUtxId);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// External chain — walk child inbounds (CEA-originated UniversalTx logs).
|
|
103
|
+
yield expandExternalChildInbounds(node, detection, state, opts);
|
|
104
|
+
}
|
|
105
|
+
return node;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function expandPushOutbounds(node, txHash, chain, state, opts, knownUtxId) {
|
|
109
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
110
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
111
|
+
// Prefer the caller-supplied utx id — this covers follow-up Push txs that
|
|
112
|
+
// were triggered by an external CEA inbound (their outbounds live under
|
|
113
|
+
// `sha256(externalCaip:externalHash:logIndex)`, not the PC-derived key).
|
|
114
|
+
// For root Push txs the caller omits it and we derive the PC key.
|
|
115
|
+
const pcUtxId = knownUtxId !== null && knownUtxId !== void 0 ? knownUtxId : (0, child_inbounds_1.derivePcUniversalTxId)(chain, txHash);
|
|
116
|
+
try {
|
|
117
|
+
const resp = yield opts.pushClient.getUniversalTxByIdV2(pcUtxId.slice(2));
|
|
118
|
+
const utx = resp === null || resp === void 0 ? void 0 : resp.universalTx;
|
|
119
|
+
if (!utx || !utx.outboundTx || utx.outboundTx.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
for (const ob of utx.outboundTx) {
|
|
122
|
+
const destChainStr = (_a = ob.destinationChain) !== null && _a !== void 0 ? _a : '';
|
|
123
|
+
const externalTxHash = ((_b = ob.observedTx) === null || _b === void 0 ? void 0 : _b.txHash) || '';
|
|
124
|
+
const summary = {
|
|
125
|
+
subTxId: (_c = ob.id) !== null && _c !== void 0 ? _c : '',
|
|
126
|
+
status: outboundStatusName(ob.outboundStatus),
|
|
127
|
+
destinationChain: destChainStr,
|
|
128
|
+
externalTxHash: externalTxHash || undefined,
|
|
129
|
+
amount: ob.amount,
|
|
130
|
+
recipient: ob.recipient,
|
|
131
|
+
};
|
|
132
|
+
if (!externalTxHash || !isSupportedChainCaip(destChainStr)) {
|
|
133
|
+
node.children.push({
|
|
134
|
+
edgeKind: 'outbound',
|
|
135
|
+
relation: summary,
|
|
136
|
+
node: null,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const childNode = yield walk(externalTxHash, destChainStr, node.depth + 1, state, opts);
|
|
141
|
+
node.children.push({
|
|
142
|
+
edgeKind: 'outbound',
|
|
143
|
+
relation: summary,
|
|
144
|
+
node: childNode,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// Refund edges: the chain records two refund-tx fields on each outbound.
|
|
148
|
+
// - pcRefundExecution (field 18) — gas refund tx after a successful
|
|
149
|
+
// outbound (push-chain/x/uexecutor/keeper/outbound.go).
|
|
150
|
+
// - pcRevertExecution — revert/refund tx when the outbound reverted.
|
|
151
|
+
// Surface both as pc-refund edges and recurse into the refund tx on
|
|
152
|
+
// Push Chain.
|
|
153
|
+
const refundTxs = [];
|
|
154
|
+
if (ob.pcRefundExecution)
|
|
155
|
+
refundTxs.push(ob.pcRefundExecution);
|
|
156
|
+
if (ob.pcRevertExecution)
|
|
157
|
+
refundTxs.push(ob.pcRevertExecution);
|
|
158
|
+
for (const refund of refundTxs) {
|
|
159
|
+
if (!refund.txHash)
|
|
160
|
+
continue;
|
|
161
|
+
const refundSummary = {
|
|
162
|
+
txHash: refund.txHash,
|
|
163
|
+
sender: (_d = refund.sender) !== null && _d !== void 0 ? _d : '',
|
|
164
|
+
gasUsed: typeof refund.gasUsed === 'bigint'
|
|
165
|
+
? Number(refund.gasUsed)
|
|
166
|
+
: (_e = refund.gasUsed) !== null && _e !== void 0 ? _e : 0,
|
|
167
|
+
blockHeight: typeof refund.blockHeight === 'bigint'
|
|
168
|
+
? Number(refund.blockHeight)
|
|
169
|
+
: (_f = refund.blockHeight) !== null && _f !== void 0 ? _f : 0,
|
|
170
|
+
status: (_g = refund.status) !== null && _g !== void 0 ? _g : '',
|
|
171
|
+
errorMsg: (_h = refund.errorMsg) !== null && _h !== void 0 ? _h : '',
|
|
172
|
+
parentOutboundId: (_j = ob.id) !== null && _j !== void 0 ? _j : '',
|
|
173
|
+
};
|
|
174
|
+
const refundNode = yield walk(refund.txHash, chain, node.depth + 1, state, opts);
|
|
175
|
+
node.children.push({
|
|
176
|
+
edgeKind: 'pc-refund',
|
|
177
|
+
relation: refundSummary,
|
|
178
|
+
node: refundNode,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
node.detection.notes.push(`cascade: pc outbound lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function expandExternalChildInbounds(node, detection, state, opts) {
|
|
189
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
const resolutions = yield (0, child_inbounds_1.resolveChildInboundsFromDetection)(opts.pushClient, detection, node.detection.notes);
|
|
191
|
+
for (const res of resolutions) {
|
|
192
|
+
// Walk each Push follow-up tx produced by this inbound.
|
|
193
|
+
if (res.pcTxHashes.length === 0) {
|
|
194
|
+
node.children.push({
|
|
195
|
+
edgeKind: 'child-inbound',
|
|
196
|
+
relation: res,
|
|
197
|
+
node: null,
|
|
198
|
+
});
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
for (const pcHash of res.pcTxHashes) {
|
|
202
|
+
const childNode = yield walk(pcHash, state.pushChain, node.depth + 1, state, opts, res.universalTxId);
|
|
203
|
+
node.children.push({
|
|
204
|
+
edgeKind: 'child-inbound',
|
|
205
|
+
relation: res,
|
|
206
|
+
node: childNode,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// ── Utilities ─────────────────────────────────────────────────────────
|
|
213
|
+
function isSupportedChainCaip(caip) {
|
|
214
|
+
if (!caip)
|
|
215
|
+
return false;
|
|
216
|
+
const info = chain_1.CHAIN_INFO[caip];
|
|
217
|
+
if (!info)
|
|
218
|
+
return false;
|
|
219
|
+
return info.vm === enums_1.VM.EVM || info.vm === enums_1.VM.SVM;
|
|
220
|
+
}
|
|
221
|
+
function outboundStatusName(n) {
|
|
222
|
+
switch (n) {
|
|
223
|
+
case 0:
|
|
224
|
+
return 'OUTBOUND_STATUS_UNSPECIFIED';
|
|
225
|
+
case 1:
|
|
226
|
+
return 'PENDING';
|
|
227
|
+
case 2:
|
|
228
|
+
return 'OBSERVED';
|
|
229
|
+
case 3:
|
|
230
|
+
return 'REVERTED';
|
|
231
|
+
default:
|
|
232
|
+
return `UNKNOWN(${n !== null && n !== void 0 ? n : '?'})`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/** Flatten a cascade tree into depth-first linear node list (root first). */
|
|
236
|
+
function flattenCascade(root) {
|
|
237
|
+
const out = [];
|
|
238
|
+
const stack = [root];
|
|
239
|
+
while (stack.length > 0) {
|
|
240
|
+
const n = stack.pop();
|
|
241
|
+
out.push(n);
|
|
242
|
+
for (let i = n.children.length - 1; i >= 0; i--) {
|
|
243
|
+
const c = n.children[i].node;
|
|
244
|
+
if (c)
|
|
245
|
+
stack.push(c);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return out;
|
|
249
|
+
}
|
|
250
|
+
// silence unused-import warning for viem helpers not yet referenced
|
|
251
|
+
void viem_1.createPublicClient;
|
|
252
|
+
void viem_1.fallback;
|
|
253
|
+
void viem_1.http;
|
|
254
|
+
//# sourceMappingURL=cascade.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 2 — resolve child universal-txs spawned by the inbound legs of a
|
|
3
|
+
* destination-chain transaction.
|
|
4
|
+
*
|
|
5
|
+
* The chain derives a universalTxId per inbound log as:
|
|
6
|
+
* utxId = sha256(`<sourceChainCaip>:<txHash>:<logIndex>`)
|
|
7
|
+
* See push-chain/x/uexecutor/types/keys.go:49-53 (GetInboundUniversalTxKey).
|
|
8
|
+
*
|
|
9
|
+
* For Push-initiated outbounds (pcTx entries) the formula drops the log index:
|
|
10
|
+
* utxId = sha256(`<pcChainCaip>:<pcTxHash>`)
|
|
11
|
+
* See push-chain/x/uexecutor/types/keys.go:63-67 (GetPcUniversalTxKey).
|
|
12
|
+
*
|
|
13
|
+
* This module derives those ids deterministically and queries cosmos via
|
|
14
|
+
* `pushClient.getUniversalTxByIdV2`, no event-attribute predicate needed.
|
|
15
|
+
*/
|
|
16
|
+
import { toHex } from 'viem';
|
|
17
|
+
import type { PushClient } from '../push-client/push-client';
|
|
18
|
+
import type { MatchingLog, PushChainOutboundSummary, UniversalTxDetection } from './types';
|
|
19
|
+
export interface ChildInboundResolution {
|
|
20
|
+
/** Deterministically derived universalTxId for this inbound log. */
|
|
21
|
+
universalTxId: `0x${string}`;
|
|
22
|
+
/** Log that triggered the child inbound. */
|
|
23
|
+
sourceLogIndex: number;
|
|
24
|
+
sourceEventName: string;
|
|
25
|
+
status: number;
|
|
26
|
+
statusName: string;
|
|
27
|
+
/** Push Chain tx hashes that ran the child inbound payload. */
|
|
28
|
+
pcTxHashes: string[];
|
|
29
|
+
/** Any grandchild outbounds spawned from the child inbound. */
|
|
30
|
+
outboundHashes: PushChainOutboundSummary[];
|
|
31
|
+
/** Cosmos has no record for this id (not yet observed / relayer-voted). */
|
|
32
|
+
notFound?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Deterministic child universalTxId for an inbound event on an external chain.
|
|
36
|
+
* Mirrors `GetInboundUniversalTxKey` from the chain module.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deriveChildUniversalTxId(sourceChainCaip: string, externalTxHash: string, logIndex: number | string): `0x${string}`;
|
|
39
|
+
/**
|
|
40
|
+
* Deterministic universalTxId for a Push-Chain-initiated tx (no log index).
|
|
41
|
+
* Mirrors `GetPcUniversalTxKey` from the chain module.
|
|
42
|
+
*/
|
|
43
|
+
export declare function derivePcUniversalTxId(pushChainCaip: string, pushTxHash: string): `0x${string}`;
|
|
44
|
+
/**
|
|
45
|
+
* Given a destination-chain detection, resolve each inbound-log leg by
|
|
46
|
+
* computing its deterministic universalTxId and querying cosmos.
|
|
47
|
+
*
|
|
48
|
+
* Returns one entry per inbound log present in the receipt.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveChildInboundsFromDetection(pushClient: PushClient, detection: UniversalTxDetection, diagnostics?: string[]): Promise<ChildInboundResolution[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Lower-level variant — resolve children from an explicit list of inbound
|
|
53
|
+
* logs (each with a logIndex).
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveChildInboundsFromLogs(pushClient: PushClient, sourceChainCaip: string, externalTxHash: string, inboundLogs: Pick<MatchingLog, 'eventName' | 'logIndex'>[], diagnostics?: string[]): Promise<ChildInboundResolution[]>;
|
|
56
|
+
export declare const __internal: {
|
|
57
|
+
toHex: typeof toHex;
|
|
58
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__internal = void 0;
|
|
4
|
+
exports.deriveChildUniversalTxId = deriveChildUniversalTxId;
|
|
5
|
+
exports.derivePcUniversalTxId = derivePcUniversalTxId;
|
|
6
|
+
exports.resolveChildInboundsFromDetection = resolveChildInboundsFromDetection;
|
|
7
|
+
exports.resolveChildInboundsFromLogs = resolveChildInboundsFromLogs;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
/**
|
|
10
|
+
* Stage 2 — resolve child universal-txs spawned by the inbound legs of a
|
|
11
|
+
* destination-chain transaction.
|
|
12
|
+
*
|
|
13
|
+
* The chain derives a universalTxId per inbound log as:
|
|
14
|
+
* utxId = sha256(`<sourceChainCaip>:<txHash>:<logIndex>`)
|
|
15
|
+
* See push-chain/x/uexecutor/types/keys.go:49-53 (GetInboundUniversalTxKey).
|
|
16
|
+
*
|
|
17
|
+
* For Push-initiated outbounds (pcTx entries) the formula drops the log index:
|
|
18
|
+
* utxId = sha256(`<pcChainCaip>:<pcTxHash>`)
|
|
19
|
+
* See push-chain/x/uexecutor/types/keys.go:63-67 (GetPcUniversalTxKey).
|
|
20
|
+
*
|
|
21
|
+
* This module derives those ids deterministically and queries cosmos via
|
|
22
|
+
* `pushClient.getUniversalTxByIdV2`, no event-attribute predicate needed.
|
|
23
|
+
*/
|
|
24
|
+
const viem_1 = require("viem");
|
|
25
|
+
const STATUS_NAMES = {
|
|
26
|
+
0: 'UNIVERSAL_TX_STATUS_UNSPECIFIED',
|
|
27
|
+
1: 'INBOUND_SUCCESS',
|
|
28
|
+
2: 'PENDING_INBOUND_EXECUTION',
|
|
29
|
+
3: 'PC_EXECUTED_SUCCESS',
|
|
30
|
+
4: 'PC_EXECUTED_FAILED',
|
|
31
|
+
5: 'PC_PENDING_REVERT',
|
|
32
|
+
6: 'OUTBOUND_PENDING',
|
|
33
|
+
7: 'OUTBOUND_SUCCESS',
|
|
34
|
+
8: 'OUTBOUND_FAILED',
|
|
35
|
+
9: 'CANCELED',
|
|
36
|
+
};
|
|
37
|
+
const OUTBOUND_STATUS_NAMES = {
|
|
38
|
+
0: 'OUTBOUND_STATUS_UNSPECIFIED',
|
|
39
|
+
1: 'PENDING',
|
|
40
|
+
2: 'OBSERVED',
|
|
41
|
+
3: 'REVERTED',
|
|
42
|
+
};
|
|
43
|
+
const INBOUND_EVENT_NAMES = new Set([
|
|
44
|
+
'UniversalTx',
|
|
45
|
+
'RevertUniversalTx',
|
|
46
|
+
]);
|
|
47
|
+
/**
|
|
48
|
+
* Deterministic child universalTxId for an inbound event on an external chain.
|
|
49
|
+
* Mirrors `GetInboundUniversalTxKey` from the chain module.
|
|
50
|
+
*/
|
|
51
|
+
function deriveChildUniversalTxId(sourceChainCaip, externalTxHash, logIndex) {
|
|
52
|
+
const normHash = externalTxHash.startsWith('0x')
|
|
53
|
+
? externalTxHash
|
|
54
|
+
: `0x${externalTxHash}`;
|
|
55
|
+
const input = `${sourceChainCaip}:${normHash}:${logIndex}`;
|
|
56
|
+
return (0, viem_1.sha256)((0, viem_1.toBytes)(input));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Deterministic universalTxId for a Push-Chain-initiated tx (no log index).
|
|
60
|
+
* Mirrors `GetPcUniversalTxKey` from the chain module.
|
|
61
|
+
*/
|
|
62
|
+
function derivePcUniversalTxId(pushChainCaip, pushTxHash) {
|
|
63
|
+
const normHash = pushTxHash.startsWith('0x') ? pushTxHash : `0x${pushTxHash}`;
|
|
64
|
+
const input = `${pushChainCaip}:${normHash}`;
|
|
65
|
+
return (0, viem_1.sha256)((0, viem_1.toBytes)(input));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Given a destination-chain detection, resolve each inbound-log leg by
|
|
69
|
+
* computing its deterministic universalTxId and querying cosmos.
|
|
70
|
+
*
|
|
71
|
+
* Returns one entry per inbound log present in the receipt.
|
|
72
|
+
*/
|
|
73
|
+
function resolveChildInboundsFromDetection(pushClient, detection, diagnostics) {
|
|
74
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
const inboundLogs = detection.detections
|
|
76
|
+
.filter((d) => INBOUND_EVENT_NAMES.has(d.log.eventName))
|
|
77
|
+
.map((d) => d.log);
|
|
78
|
+
return resolveChildInboundsFromLogs(pushClient, detection.chain, detection.txHash, inboundLogs, diagnostics);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Lower-level variant — resolve children from an explicit list of inbound
|
|
83
|
+
* logs (each with a logIndex).
|
|
84
|
+
*/
|
|
85
|
+
function resolveChildInboundsFromLogs(pushClient, sourceChainCaip, externalTxHash, inboundLogs, diagnostics) {
|
|
86
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
var _a, _b, _c, _d;
|
|
88
|
+
const out = [];
|
|
89
|
+
for (const log of inboundLogs) {
|
|
90
|
+
if (log.logIndex < 0) {
|
|
91
|
+
diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.push(`skipped log with negative logIndex (eventName=${log.eventName})`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const utxIdHex = deriveChildUniversalTxId(sourceChainCaip, externalTxHash, log.logIndex);
|
|
95
|
+
try {
|
|
96
|
+
const resp = yield pushClient.getUniversalTxByIdV2(utxIdHex.slice(2));
|
|
97
|
+
const utx = resp === null || resp === void 0 ? void 0 : resp.universalTx;
|
|
98
|
+
if (!utx || !utx.id) {
|
|
99
|
+
out.push({
|
|
100
|
+
universalTxId: utxIdHex,
|
|
101
|
+
sourceLogIndex: log.logIndex,
|
|
102
|
+
sourceEventName: log.eventName,
|
|
103
|
+
status: 0,
|
|
104
|
+
statusName: STATUS_NAMES[0],
|
|
105
|
+
pcTxHashes: [],
|
|
106
|
+
outboundHashes: [],
|
|
107
|
+
notFound: true,
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const status = ((_a = utx.universalStatus) !== null && _a !== void 0 ? _a : 0);
|
|
112
|
+
const pcTxHashes = ((_b = utx.pcTx) !== null && _b !== void 0 ? _b : [])
|
|
113
|
+
.map((p) => p === null || p === void 0 ? void 0 : p.txHash)
|
|
114
|
+
.filter((h) => Boolean(h));
|
|
115
|
+
const outboundHashes = ((_c = utx.outboundTx) !== null && _c !== void 0 ? _c : []).map((ob) => {
|
|
116
|
+
var _a, _b, _c, _d;
|
|
117
|
+
return ({
|
|
118
|
+
subTxId: (_a = ob.id) !== null && _a !== void 0 ? _a : '',
|
|
119
|
+
status: (_b = OUTBOUND_STATUS_NAMES[ob.outboundStatus]) !== null && _b !== void 0 ? _b : `UNKNOWN(${ob.outboundStatus})`,
|
|
120
|
+
destinationChain: (_c = ob.destinationChain) !== null && _c !== void 0 ? _c : '',
|
|
121
|
+
externalTxHash: ((_d = ob.observedTx) === null || _d === void 0 ? void 0 : _d.txHash) || undefined,
|
|
122
|
+
amount: ob.amount,
|
|
123
|
+
recipient: ob.recipient,
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
out.push({
|
|
127
|
+
universalTxId: utxIdHex,
|
|
128
|
+
sourceLogIndex: log.logIndex,
|
|
129
|
+
sourceEventName: log.eventName,
|
|
130
|
+
status,
|
|
131
|
+
statusName: (_d = STATUS_NAMES[status]) !== null && _d !== void 0 ? _d : `UNKNOWN(${status})`,
|
|
132
|
+
pcTxHashes,
|
|
133
|
+
outboundHashes,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.push(`getUniversalTxByIdV2(${utxIdHex}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Debug-only re-export (avoid importing into production paths).
|
|
144
|
+
exports.__internal = { toHex: viem_1.toHex };
|
|
145
|
+
//# sourceMappingURL=child-inbounds.js.map
|