@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.
- package/CHANGELOG.md +48 -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 +3 -0
- 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 -329
- 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.js +306 -294
- 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
|
@@ -5,7 +5,6 @@ exports.deriveChildUniversalTxId = deriveChildUniversalTxId;
|
|
|
5
5
|
exports.derivePcUniversalTxId = derivePcUniversalTxId;
|
|
6
6
|
exports.resolveChildInboundsFromDetection = resolveChildInboundsFromDetection;
|
|
7
7
|
exports.resolveChildInboundsFromLogs = resolveChildInboundsFromLogs;
|
|
8
|
-
const tslib_1 = require("tslib");
|
|
9
8
|
/**
|
|
10
9
|
* Stage 2 — resolve child universal-txs spawned by the inbound legs of a
|
|
11
10
|
* destination-chain transaction.
|
|
@@ -86,83 +85,35 @@ function derivePcUniversalTxId(pushChainCaip, pushTxHash) {
|
|
|
86
85
|
*
|
|
87
86
|
* Returns one entry per inbound log present in the receipt.
|
|
88
87
|
*/
|
|
89
|
-
function resolveChildInboundsFromDetection(pushClient, detection, diagnostics) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return resolutions.map(normalize_1.normalizeChildInboundResolutionForUser);
|
|
102
|
-
});
|
|
88
|
+
async function resolveChildInboundsFromDetection(pushClient, detection, diagnostics) {
|
|
89
|
+
const inboundLogs = detection.detections
|
|
90
|
+
.filter((d) => INBOUND_EVENT_NAMES.has(d.log.eventName))
|
|
91
|
+
.map((d) => d.log);
|
|
92
|
+
const resolutions = await resolveChildInboundsFromLogs(pushClient, detection.chain, detection.txHash, inboundLogs, diagnostics);
|
|
93
|
+
// User-facing normalization pass: rewrites nested
|
|
94
|
+
// `outboundHashes[n].externalTxHash` to base58 for SVM destinations.
|
|
95
|
+
// `pcTxHashes` is Push Chain (EVM) and stays hex by chain type. The lower-
|
|
96
|
+
// level `resolveChildInboundsFromLogs` is left producing raw hex so
|
|
97
|
+
// internal callers (`findChildUtxIdFromExternalTx` via the detector path)
|
|
98
|
+
// that go through it directly still see the canonical form.
|
|
99
|
+
return resolutions.map(normalize_1.normalizeChildInboundResolutionForUser);
|
|
103
100
|
}
|
|
104
101
|
/**
|
|
105
102
|
* Lower-level variant — resolve children from an explicit list of inbound
|
|
106
103
|
* logs (each with a logIndex).
|
|
107
104
|
*/
|
|
108
|
-
function resolveChildInboundsFromLogs(pushClient, sourceChainCaip, externalTxHash, inboundLogs, diagnostics) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const utx = resp === null || resp === void 0 ? void 0 : resp.universalTx;
|
|
121
|
-
if (!utx || !utx.id) {
|
|
122
|
-
out.push({
|
|
123
|
-
universalTxId: utxIdHex,
|
|
124
|
-
sourceLogIndex: log.logIndex,
|
|
125
|
-
sourceEventName: log.eventName,
|
|
126
|
-
status: 0,
|
|
127
|
-
statusName: STATUS_NAMES[0],
|
|
128
|
-
pcTxHashes: [],
|
|
129
|
-
outboundHashes: [],
|
|
130
|
-
notFound: true,
|
|
131
|
-
});
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
const status = ((_a = utx.universalStatus) !== null && _a !== void 0 ? _a : 0);
|
|
135
|
-
const pcTxHashes = ((_b = utx.pcTx) !== null && _b !== void 0 ? _b : [])
|
|
136
|
-
.map((p) => p === null || p === void 0 ? void 0 : p.txHash)
|
|
137
|
-
.filter((h) => Boolean(h));
|
|
138
|
-
const outboundHashes = ((_c = utx.outboundTx) !== null && _c !== void 0 ? _c : []).map((ob) => {
|
|
139
|
-
var _a, _b, _c, _d;
|
|
140
|
-
return ({
|
|
141
|
-
subTxId: (_a = ob.id) !== null && _a !== void 0 ? _a : '',
|
|
142
|
-
status: (_b = OUTBOUND_STATUS_NAMES[ob.outboundStatus]) !== null && _b !== void 0 ? _b : `UNKNOWN(${ob.outboundStatus})`,
|
|
143
|
-
destinationChain: (_c = ob.destinationChain) !== null && _c !== void 0 ? _c : '',
|
|
144
|
-
externalTxHash: ((_d = ob.observedTx) === null || _d === void 0 ? void 0 : _d.txHash) || undefined,
|
|
145
|
-
amount: ob.amount,
|
|
146
|
-
recipient: ob.recipient,
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
out.push({
|
|
150
|
-
universalTxId: utxIdHex,
|
|
151
|
-
sourceLogIndex: log.logIndex,
|
|
152
|
-
sourceEventName: log.eventName,
|
|
153
|
-
status,
|
|
154
|
-
statusName: (_d = STATUS_NAMES[status]) !== null && _d !== void 0 ? _d : `UNKNOWN(${status})`,
|
|
155
|
-
pcTxHashes,
|
|
156
|
-
outboundHashes,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
catch (err) {
|
|
160
|
-
diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.push(`getUniversalTxByIdV2(${utxIdHex}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
161
|
-
// Cosmos lookup failed (commonly NotFound while the indexer is still
|
|
162
|
-
// catching up). The utxId is deterministically derived from the source
|
|
163
|
-
// log, so surface it as notFound rather than dropping the entry —
|
|
164
|
-
// otherwise callers like inbound-tracker repeatedly re-run the full
|
|
165
|
-
// detector pass instead of advancing to lightweight status polling.
|
|
105
|
+
async function resolveChildInboundsFromLogs(pushClient, sourceChainCaip, externalTxHash, inboundLogs, diagnostics) {
|
|
106
|
+
const out = [];
|
|
107
|
+
for (const log of inboundLogs) {
|
|
108
|
+
if (log.logIndex < 0) {
|
|
109
|
+
diagnostics?.push(`skipped log with negative logIndex (eventName=${log.eventName})`);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const utxIdHex = deriveChildUniversalTxId(sourceChainCaip, externalTxHash, log.logIndex);
|
|
113
|
+
try {
|
|
114
|
+
const resp = await pushClient.getUniversalTxByIdV2(utxIdHex.slice(2));
|
|
115
|
+
const utx = resp?.universalTx;
|
|
116
|
+
if (!utx || !utx.id) {
|
|
166
117
|
out.push({
|
|
167
118
|
universalTxId: utxIdHex,
|
|
168
119
|
sourceLogIndex: log.logIndex,
|
|
@@ -173,10 +124,51 @@ function resolveChildInboundsFromLogs(pushClient, sourceChainCaip, externalTxHas
|
|
|
173
124
|
outboundHashes: [],
|
|
174
125
|
notFound: true,
|
|
175
126
|
});
|
|
127
|
+
continue;
|
|
176
128
|
}
|
|
129
|
+
const status = (utx.universalStatus ?? 0);
|
|
130
|
+
const pcTxHashes = (utx.pcTx ?? [])
|
|
131
|
+
.map((p) => p?.txHash)
|
|
132
|
+
.filter((h) => Boolean(h));
|
|
133
|
+
const outboundHashes = (utx.outboundTx ?? []).map((ob) => ({
|
|
134
|
+
subTxId: ob.id ?? '',
|
|
135
|
+
status: OUTBOUND_STATUS_NAMES[ob.outboundStatus] ??
|
|
136
|
+
`UNKNOWN(${ob.outboundStatus})`,
|
|
137
|
+
destinationChain: ob.destinationChain ?? '',
|
|
138
|
+
externalTxHash: ob.observedTx?.txHash || undefined,
|
|
139
|
+
amount: ob.amount,
|
|
140
|
+
recipient: ob.recipient,
|
|
141
|
+
}));
|
|
142
|
+
out.push({
|
|
143
|
+
universalTxId: utxIdHex,
|
|
144
|
+
sourceLogIndex: log.logIndex,
|
|
145
|
+
sourceEventName: log.eventName,
|
|
146
|
+
status,
|
|
147
|
+
statusName: STATUS_NAMES[status] ?? `UNKNOWN(${status})`,
|
|
148
|
+
pcTxHashes,
|
|
149
|
+
outboundHashes,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
diagnostics?.push(`getUniversalTxByIdV2(${utxIdHex}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
154
|
+
// Cosmos lookup failed (commonly NotFound while the indexer is still
|
|
155
|
+
// catching up). The utxId is deterministically derived from the source
|
|
156
|
+
// log, so surface it as notFound rather than dropping the entry —
|
|
157
|
+
// otherwise callers like inbound-tracker repeatedly re-run the full
|
|
158
|
+
// detector pass instead of advancing to lightweight status polling.
|
|
159
|
+
out.push({
|
|
160
|
+
universalTxId: utxIdHex,
|
|
161
|
+
sourceLogIndex: log.logIndex,
|
|
162
|
+
sourceEventName: log.eventName,
|
|
163
|
+
status: 0,
|
|
164
|
+
statusName: STATUS_NAMES[0],
|
|
165
|
+
pcTxHashes: [],
|
|
166
|
+
outboundHashes: [],
|
|
167
|
+
notFound: true,
|
|
168
|
+
});
|
|
177
169
|
}
|
|
178
|
-
|
|
179
|
-
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
180
172
|
}
|
|
181
173
|
// Debug-only re-export (avoid importing into production paths).
|
|
182
174
|
exports.__internal = { toHex: viem_1.toHex };
|
|
@@ -152,7 +152,7 @@ function asBigint(v) {
|
|
|
152
152
|
try {
|
|
153
153
|
return BigInt(v);
|
|
154
154
|
}
|
|
155
|
-
catch
|
|
155
|
+
catch {
|
|
156
156
|
return undefined;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
@@ -164,7 +164,6 @@ function assignHex(out, key, v) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
function setTxType(out, raw) {
|
|
167
|
-
var _a;
|
|
168
167
|
const n = typeof raw === 'number'
|
|
169
168
|
? raw
|
|
170
169
|
: typeof raw === 'bigint'
|
|
@@ -173,7 +172,7 @@ function setTxType(out, raw) {
|
|
|
173
172
|
if (n === undefined)
|
|
174
173
|
return;
|
|
175
174
|
out.txType = n;
|
|
176
|
-
out.txTypeName =
|
|
175
|
+
out.txTypeName = TX_TYPE_NAMES[n] ?? 'UNKNOWN';
|
|
177
176
|
}
|
|
178
177
|
function setPayload(out, raw) {
|
|
179
178
|
if (typeof raw !== 'string' || !raw.startsWith('0x'))
|
|
@@ -37,158 +37,152 @@ const INBOUND_KINDS = new Set([
|
|
|
37
37
|
* consumer (classify, cascade, child-inbounds, inbound-tracker) can treat
|
|
38
38
|
* EVM and SVM results uniformly.
|
|
39
39
|
*/
|
|
40
|
-
function detectUniversalTxSvm(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
async function detectUniversalTxSvm(signature, chain, opts = {}) {
|
|
41
|
+
const notes = [];
|
|
42
|
+
const chainInfo = chain_1.CHAIN_INFO[chain];
|
|
43
|
+
const castHash = signature; // intentional — we widen downstream
|
|
44
|
+
if (!chainInfo) {
|
|
45
|
+
throw new Error(`detectUniversalTxSvm: unknown chain ${chain}`);
|
|
46
|
+
}
|
|
47
|
+
const connection = await resolveConnection(chain, opts);
|
|
48
|
+
// The cascade (and cosmos) stores Solana signatures as 0x-prefixed hex of
|
|
49
|
+
// the 64-byte signature bytes. Solana RPC needs base58 — normalize here
|
|
50
|
+
// so callers can pass either form interchangeably.
|
|
51
|
+
const rpcSig = normalizeSolanaSignature(signature);
|
|
52
|
+
let tx;
|
|
53
|
+
try {
|
|
54
|
+
tx = await connection.getTransaction(rpcSig, {
|
|
55
|
+
commitment: 'confirmed',
|
|
56
|
+
maxSupportedTransactionVersion: 0,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
notes.push(`svm tx fetch failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
61
|
+
return emptyDetection(castHash, chain, notes);
|
|
62
|
+
}
|
|
63
|
+
if (!tx || !tx.meta) {
|
|
64
|
+
notes.push('no svm tx returned by RPC');
|
|
65
|
+
return emptyDetection(castHash, chain, notes);
|
|
66
|
+
}
|
|
67
|
+
// Reverted with no logs — same early-out as EVM path.
|
|
68
|
+
const err = tx.meta.err;
|
|
69
|
+
const logMessages = (tx.meta.logMessages ?? []);
|
|
70
|
+
if (err && logMessages.length === 0) {
|
|
71
|
+
notes.push('svm tx reverted with no logs');
|
|
72
|
+
return emptyDetection(castHash, chain, notes);
|
|
73
|
+
}
|
|
74
|
+
// Emitter for SVM is the gateway program id from CHAIN_INFO.
|
|
75
|
+
// Encoded as 0x-prefixed 32-byte hex so MatchingLog.address stays
|
|
76
|
+
// assignable to the `0x${string}` type without widening.
|
|
77
|
+
const emitterBase58 = chainInfo.lockerContract || '';
|
|
78
|
+
let emitter = '0x';
|
|
79
|
+
if (emitterBase58 && emitterBase58 !== 'TBD') {
|
|
55
80
|
try {
|
|
56
|
-
|
|
57
|
-
commitment: 'confirmed',
|
|
58
|
-
maxSupportedTransactionVersion: 0,
|
|
59
|
-
});
|
|
81
|
+
emitter = (0, viem_1.bytesToHex)(new web3_js_1.PublicKey(emitterBase58).toBytes());
|
|
60
82
|
}
|
|
61
|
-
catch
|
|
62
|
-
|
|
63
|
-
return emptyDetection(castHash, chain, notes);
|
|
83
|
+
catch {
|
|
84
|
+
emitter = '0x';
|
|
64
85
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
}
|
|
87
|
+
const eventCoder = new anchor_1.BorshEventCoder(universalGatewayV0_json_1.default);
|
|
88
|
+
const matchingLogs = [];
|
|
89
|
+
// Walk logMessages for `Program data:` entries. Each matched event keeps
|
|
90
|
+
// the actual Solana log-message index because that is the value validators
|
|
91
|
+
// submit as the inbound log_index and the keeper uses for the UTX key.
|
|
92
|
+
for (let logIndex = 0; logIndex < logMessages.length; logIndex++) {
|
|
93
|
+
const rawLog = logMessages[logIndex];
|
|
94
|
+
if (typeof rawLog !== 'string')
|
|
95
|
+
continue;
|
|
96
|
+
const prefix = 'Program data: ';
|
|
97
|
+
if (!rawLog.startsWith(prefix))
|
|
98
|
+
continue;
|
|
99
|
+
const base64Data = rawLog.slice(prefix.length).trim();
|
|
100
|
+
// Fast discriminator check — skip non-universal events without running
|
|
101
|
+
// the full Borsh decode.
|
|
102
|
+
let bytes;
|
|
103
|
+
try {
|
|
104
|
+
bytes = new Uint8Array(Buffer.from(base64Data, 'base64'));
|
|
68
105
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const logMessages = ((_a = tx.meta.logMessages) !== null && _a !== void 0 ? _a : []);
|
|
72
|
-
if (err && logMessages.length === 0) {
|
|
73
|
-
notes.push('svm tx reverted with no logs');
|
|
74
|
-
return emptyDetection(castHash, chain, notes);
|
|
106
|
+
catch {
|
|
107
|
+
continue;
|
|
75
108
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
emitter = '0x';
|
|
87
|
-
}
|
|
109
|
+
const disc = (0, svm_events_1.discriminatorHex)(bytes);
|
|
110
|
+
const eventName = svm_events_1.SVM_EVENT_DISCRIMINATORS[disc];
|
|
111
|
+
if (!eventName)
|
|
112
|
+
continue;
|
|
113
|
+
// BorshEventCoder can throw when the on-chain layout drifts from the
|
|
114
|
+
// bundled IDL (seen with older UniversalTx emissions). Isolate the
|
|
115
|
+
// failure to this event so the rest of the matching logs still surface.
|
|
116
|
+
let decoded = null;
|
|
117
|
+
try {
|
|
118
|
+
decoded = eventCoder.decode(base64Data);
|
|
88
119
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// the actual Solana log-message index because that is the value validators
|
|
93
|
-
// submit as the inbound log_index and the keeper uses for the UTX key.
|
|
94
|
-
for (let logIndex = 0; logIndex < logMessages.length; logIndex++) {
|
|
95
|
-
const rawLog = logMessages[logIndex];
|
|
96
|
-
if (typeof rawLog !== 'string')
|
|
97
|
-
continue;
|
|
98
|
-
const prefix = 'Program data: ';
|
|
99
|
-
if (!rawLog.startsWith(prefix))
|
|
100
|
-
continue;
|
|
101
|
-
const base64Data = rawLog.slice(prefix.length).trim();
|
|
102
|
-
// Fast discriminator check — skip non-universal events without running
|
|
103
|
-
// the full Borsh decode.
|
|
104
|
-
let bytes;
|
|
105
|
-
try {
|
|
106
|
-
bytes = new Uint8Array(Buffer.from(base64Data, 'base64'));
|
|
107
|
-
}
|
|
108
|
-
catch (_c) {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
const disc = (0, svm_events_1.discriminatorHex)(bytes);
|
|
112
|
-
const eventName = svm_events_1.SVM_EVENT_DISCRIMINATORS[disc];
|
|
113
|
-
if (!eventName)
|
|
114
|
-
continue;
|
|
115
|
-
// BorshEventCoder can throw when the on-chain layout drifts from the
|
|
116
|
-
// bundled IDL (seen with older UniversalTx emissions). Isolate the
|
|
117
|
-
// failure to this event so the rest of the matching logs still surface.
|
|
118
|
-
let decoded = null;
|
|
119
|
-
try {
|
|
120
|
-
decoded = eventCoder.decode(base64Data);
|
|
121
|
-
}
|
|
122
|
-
catch (e) {
|
|
123
|
-
notes.push(`svm: borsh decode threw for ${eventName}: ${e instanceof Error ? e.message : String(e)}`);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (!decoded || decoded.name !== eventName) {
|
|
127
|
-
notes.push(`svm: discriminator matched ${eventName} but borsh decode failed`);
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
const args = normalizeSvmEventArgs(eventName, decoded.data);
|
|
131
|
-
matchingLogs.push({
|
|
132
|
-
eventName,
|
|
133
|
-
address: emitter,
|
|
134
|
-
logIndex,
|
|
135
|
-
args,
|
|
136
|
-
});
|
|
120
|
+
catch (e) {
|
|
121
|
+
notes.push(`svm: borsh decode threw for ${eventName}: ${e instanceof Error ? e.message : String(e)}`);
|
|
122
|
+
continue;
|
|
137
123
|
}
|
|
138
|
-
if (
|
|
139
|
-
notes.push(
|
|
140
|
-
|
|
124
|
+
if (!decoded || decoded.name !== eventName) {
|
|
125
|
+
notes.push(`svm: discriminator matched ${eventName} but borsh decode failed`);
|
|
126
|
+
continue;
|
|
141
127
|
}
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
128
|
+
const args = normalizeSvmEventArgs(eventName, decoded.data);
|
|
129
|
+
matchingLogs.push({
|
|
130
|
+
eventName,
|
|
131
|
+
address: emitter,
|
|
132
|
+
logIndex,
|
|
133
|
+
args,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (matchingLogs.length === 0) {
|
|
137
|
+
notes.push('svm tx has no decoded universal-tx events');
|
|
138
|
+
return emptyDetection(castHash, chain, notes);
|
|
139
|
+
}
|
|
140
|
+
const classified = (0, classify_1.classify)(matchingLogs);
|
|
141
|
+
notes.push(...classified.notes);
|
|
142
|
+
const decoded = { ...classified.decoded };
|
|
143
|
+
// Inbound fallback for universalTxId: same formula the EVM branch uses,
|
|
144
|
+
// with the canonical 0x-hex Solana signature and log-message index.
|
|
145
|
+
if (!decoded.universalTxId) {
|
|
146
|
+
const caip = chain;
|
|
147
|
+
if (INBOUND_KINDS.has(classified.kind) &&
|
|
148
|
+
classified.primaryLog &&
|
|
149
|
+
classified.primaryLog.logIndex >= 0) {
|
|
150
|
+
// Use the hex form (matches cosmos keeper's on-chain storage).
|
|
151
|
+
const hexSig = solanaSigToHex(rpcSig);
|
|
152
|
+
const input = `${caip}:${hexSig}:${classified.primaryLog.logIndex}`;
|
|
153
|
+
decoded.universalTxId = (0, viem_1.sha256)((0, viem_1.toBytes)(input));
|
|
154
|
+
notes.push(`universalTxId derived via sha256("${caip}:<hexSig>:${classified.primaryLog.logIndex}") — svm`);
|
|
158
155
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
156
|
+
}
|
|
157
|
+
const detections = (0, classify_1.classifyAll)(classified.matchingLogs);
|
|
158
|
+
return {
|
|
159
|
+
txHash: castHash,
|
|
160
|
+
chain,
|
|
161
|
+
kind: classified.kind,
|
|
162
|
+
emitters: classified.emitters,
|
|
163
|
+
decoded,
|
|
164
|
+
matchingLogs: classified.matchingLogs,
|
|
165
|
+
detections,
|
|
166
|
+
// SVM detector doesn't do the cosmos cross-reference itself; upstream
|
|
167
|
+
// (orchestrator / cascade) already does its own lookup when needed.
|
|
168
|
+
notes,
|
|
169
|
+
};
|
|
173
170
|
}
|
|
174
171
|
// ── Helpers ───────────────────────────────────────────────────────────
|
|
175
|
-
function resolveConnection(chain, opts) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const { Connection } = yield Promise.resolve().then(() => tslib_1.__importStar(require('@solana/web3.js')));
|
|
190
|
-
return new Connection(rpcUrls[0], 'confirmed');
|
|
191
|
-
});
|
|
172
|
+
async function resolveConnection(chain, opts) {
|
|
173
|
+
if (opts.connection)
|
|
174
|
+
return opts.connection;
|
|
175
|
+
const info = chain_1.CHAIN_INFO[chain];
|
|
176
|
+
const rpcUrls = opts.rpcUrls?.[chain] && opts.rpcUrls[chain].length > 0
|
|
177
|
+
? opts.rpcUrls[chain]
|
|
178
|
+
: (info?.defaultRPC ?? []).filter((r) => r && r.length > 0);
|
|
179
|
+
if (rpcUrls.length === 0) {
|
|
180
|
+
throw new Error(`detectUniversalTxSvm: no RPC URL configured for ${chain}`);
|
|
181
|
+
}
|
|
182
|
+
// Lazy import to avoid a top-level dependency cycle through @solana/web3.js
|
|
183
|
+
// for consumers of the EVM-only path.
|
|
184
|
+
const { Connection } = await Promise.resolve().then(() => tslib_1.__importStar(require('@solana/web3.js')));
|
|
185
|
+
return new Connection(rpcUrls[0], 'confirmed');
|
|
192
186
|
}
|
|
193
187
|
function emptyDetection(txHash, chain, notes) {
|
|
194
188
|
return {
|
|
@@ -215,14 +209,13 @@ function emptyDetection(txHash, chain, notes) {
|
|
|
215
209
|
* the expected keys.
|
|
216
210
|
*/
|
|
217
211
|
function normalizeSvmEventArgs(eventName, raw) {
|
|
218
|
-
var _a, _b;
|
|
219
212
|
const src = raw;
|
|
220
213
|
const out = {};
|
|
221
214
|
for (const [srcKey, value] of Object.entries(src)) {
|
|
222
|
-
const renamed =
|
|
215
|
+
const renamed = svm_events_1.SVM_FIELD_RENAMES[srcKey] ?? srcKey;
|
|
223
216
|
out[renamed] = coerceArgValue(srcKey, renamed, value);
|
|
224
217
|
}
|
|
225
|
-
const aliases =
|
|
218
|
+
const aliases = svm_events_1.SVM_EVENT_FIELD_ALIASES[eventName] ?? [];
|
|
226
219
|
for (const { from, to } of aliases) {
|
|
227
220
|
if (out[to] === undefined && out[from] !== undefined) {
|
|
228
221
|
out[to] = out[from];
|
|
@@ -231,7 +224,6 @@ function normalizeSvmEventArgs(eventName, raw) {
|
|
|
231
224
|
return out;
|
|
232
225
|
}
|
|
233
226
|
function coerceArgValue(srcKey, renamedKey, value) {
|
|
234
|
-
var _a;
|
|
235
227
|
// Anchor returns PublicKey instances for `pubkey` types. Normalize to
|
|
236
228
|
// `0x${hex}` so asAddress() in classify.ts accepts them.
|
|
237
229
|
if (value && typeof value === 'object' && value instanceof web3_js_1.PublicKey) {
|
|
@@ -255,12 +247,12 @@ function coerceArgValue(srcKey, renamedKey, value) {
|
|
|
255
247
|
// BN from anchor — has toString().
|
|
256
248
|
if (value && typeof value === 'object' && typeof value.toString === 'function') {
|
|
257
249
|
const proto = Object.getPrototypeOf(value);
|
|
258
|
-
const ctorName =
|
|
250
|
+
const ctorName = proto?.constructor?.name;
|
|
259
251
|
if (ctorName === 'BN') {
|
|
260
252
|
try {
|
|
261
253
|
return BigInt(value.toString(10));
|
|
262
254
|
}
|
|
263
|
-
catch
|
|
255
|
+
catch {
|
|
264
256
|
return undefined;
|
|
265
257
|
}
|
|
266
258
|
}
|