@pushchain/core 5.1.14 → 5.1.16

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 (26) hide show
  1. package/package.json +1 -1
  2. package/src/lib/orchestrator/internals/cascade.d.ts +16 -0
  3. package/src/lib/orchestrator/internals/cascade.js +205 -47
  4. package/src/lib/orchestrator/internals/error-decoder.d.ts +59 -0
  5. package/src/lib/orchestrator/internals/error-decoder.js +110 -0
  6. package/src/lib/orchestrator/internals/errors.d.ts +78 -0
  7. package/src/lib/orchestrator/internals/errors.js +83 -0
  8. package/src/lib/orchestrator/internals/outbound-sync.d.ts +2 -2
  9. package/src/lib/orchestrator/internals/outbound-sync.js +2 -2
  10. package/src/lib/orchestrator/internals/preflight.d.ts +80 -0
  11. package/src/lib/orchestrator/internals/preflight.js +145 -0
  12. package/src/lib/orchestrator/internals/push-chain-tx.d.ts +2 -18
  13. package/src/lib/orchestrator/internals/push-chain-tx.js +67 -40
  14. package/src/lib/orchestrator/internals/route-handlers.js +199 -114
  15. package/src/lib/orchestrator/internals/svm-rent.d.ts +46 -0
  16. package/src/lib/orchestrator/internals/svm-rent.js +100 -0
  17. package/src/lib/orchestrator/internals/tx-transformer.js +16 -1
  18. package/src/lib/orchestrator/orchestrator.js +34 -1
  19. package/src/lib/orchestrator/orchestrator.types.d.ts +27 -3
  20. package/src/lib/price-fetch/price-fetch.js +23 -5
  21. package/src/lib/progress-hook/progress-hook.js +130 -6
  22. package/src/lib/progress-hook/progress-hook.types.d.ts +8 -2
  23. package/src/lib/progress-hook/progress-hook.types.js +15 -0
  24. package/src/lib/universal/account/account.d.ts +1 -1
  25. package/src/lib/universal/account/account.js +1 -1
  26. package/src/lib/universal-tx-detector/child-inbounds.js +15 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Conditional CEA-ATA rent bump for SVM SPL outbounds.
3
+ *
4
+ * The gateway program (svm-gateway) computes per-tx fees with a conditional
5
+ * rent for first-time SPL transfers — see `calculateSplExecuteFees` in
6
+ * `push-chain-gateway-contracts/contracts/svm-gateway/tests/helpers/test-utils.ts`:
7
+ *
8
+ * const ataExists = await ceaAtaExists(connection, ceaAta);
9
+ * const ceaAtaRent = ataExists ? 0n : BigInt(getMinimumBalanceForRentExemption(165));
10
+ * gasFee = executedTxRent + ceaAtaRent + COMPUTE_BUFFER;
11
+ *
12
+ * The gateway's on-chain `getOutboundTxGasAndFees` quote does NOT factor in
13
+ * the ATA rent today, so the SDK has to bump `effectiveGasLimit` itself
14
+ * before calling that quote. Native-SOL outbounds use `calculateSolExecuteFees`
15
+ * which has no conditional rent, so no SDK bump is needed there.
16
+ */
17
+ import { PublicKey } from '@solana/web3.js';
18
+ import type { OrchestratorContext } from './context';
19
+ import type { CHAIN as ChainType } from '../../constants/enums';
20
+ /** ATA rent (165-byte SPL token account) + executed-tx rent (8-byte) + compute buffer.
21
+ * Mirrors getMinimumBalanceForRentExemption(165) ≈ 2_039_280
22
+ * + getMinimumBalanceForRentExemption(8) ≈ 9_200
23
+ * + COMPUTE_BUFFER 100_000.
24
+ * Signature fee (5_000) is already included in the gateway's base quote. */
25
+ export declare const CEA_ATA_RENT_LAMPORTS_BUMP: bigint;
26
+ /** Derive CEA PDA from a 20-byte EVM address. Seeds: ["push_identity", evmBytes]. */
27
+ export declare function deriveSvmCeaPda(evmAddress: `0x${string}`): PublicKey;
28
+ /** Derive a standard SPL Associated Token Account address. */
29
+ export declare function deriveAtaPubkey(owner: PublicKey, mint: PublicKey): PublicKey;
30
+ export interface MaybeBumpInput {
31
+ ctx: OrchestratorContext;
32
+ ueaAddress: `0x${string}`;
33
+ targetChain: ChainType;
34
+ /** SPL mint as base58 (from MoveableToken.address for SVM tokens). undefined ⇒ no SPL. */
35
+ splMintBase58: string | undefined;
36
+ /** Burn amount in token units. 0 ⇒ no SPL transferFrom ⇒ no ATA needed. */
37
+ burnAmount: bigint;
38
+ effectiveGasLimit: bigint;
39
+ }
40
+ /**
41
+ * Returns the (possibly bumped) effectiveGasLimit. Logs the decision via
42
+ * printLog. On any RPC failure or invalid input, logs a warning and returns
43
+ * the input unchanged — better to risk one underflow than to block all SPL
44
+ * outbounds on RPC flake; pre-flight will surface insufficient gas anyway.
45
+ */
46
+ export declare function maybeBumpForCeaAtaRent(input: MaybeBumpInput): Promise<bigint>;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CEA_ATA_RENT_LAMPORTS_BUMP = void 0;
4
+ exports.deriveSvmCeaPda = deriveSvmCeaPda;
5
+ exports.deriveAtaPubkey = deriveAtaPubkey;
6
+ exports.maybeBumpForCeaAtaRent = maybeBumpForCeaAtaRent;
7
+ const tslib_1 = require("tslib");
8
+ /**
9
+ * Conditional CEA-ATA rent bump for SVM SPL outbounds.
10
+ *
11
+ * The gateway program (svm-gateway) computes per-tx fees with a conditional
12
+ * rent for first-time SPL transfers — see `calculateSplExecuteFees` in
13
+ * `push-chain-gateway-contracts/contracts/svm-gateway/tests/helpers/test-utils.ts`:
14
+ *
15
+ * const ataExists = await ceaAtaExists(connection, ceaAta);
16
+ * const ceaAtaRent = ataExists ? 0n : BigInt(getMinimumBalanceForRentExemption(165));
17
+ * gasFee = executedTxRent + ceaAtaRent + COMPUTE_BUFFER;
18
+ *
19
+ * The gateway's on-chain `getOutboundTxGasAndFees` quote does NOT factor in
20
+ * the ATA rent today, so the SDK has to bump `effectiveGasLimit` itself
21
+ * before calling that quote. Native-SOL outbounds use `calculateSolExecuteFees`
22
+ * which has no conditional rent, so no SDK bump is needed there.
23
+ */
24
+ const web3_js_1 = require("@solana/web3.js");
25
+ const buffer_1 = require("buffer");
26
+ const context_1 = require("./context");
27
+ const chain_1 = require("../../constants/chain");
28
+ // ---------------------------------------------------------------------------
29
+ // Constants — mirror gateway test-utils.ts. These are SOL protocol values;
30
+ // they only change if Solana itself adjusts rent rates (effectively never).
31
+ // ---------------------------------------------------------------------------
32
+ /** ATA rent (165-byte SPL token account) + executed-tx rent (8-byte) + compute buffer.
33
+ * Mirrors getMinimumBalanceForRentExemption(165) ≈ 2_039_280
34
+ * + getMinimumBalanceForRentExemption(8) ≈ 9_200
35
+ * + COMPUTE_BUFFER 100_000.
36
+ * Signature fee (5_000) is already included in the gateway's base quote. */
37
+ exports.CEA_ATA_RENT_LAMPORTS_BUMP = BigInt(2148480);
38
+ /** SVM gateway program ID (matches CHAIN_INFO[SOLANA_DEVNET].lockerContract). */
39
+ const SVM_GATEWAY_PROGRAM = new web3_js_1.PublicKey('CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS');
40
+ const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
41
+ const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
42
+ // ---------------------------------------------------------------------------
43
+ // PDA derivations
44
+ // ---------------------------------------------------------------------------
45
+ /** Derive CEA PDA from a 20-byte EVM address. Seeds: ["push_identity", evmBytes]. */
46
+ function deriveSvmCeaPda(evmAddress) {
47
+ const senderBytes = buffer_1.Buffer.from(evmAddress.slice(2), 'hex');
48
+ const [ceaPda] = web3_js_1.PublicKey.findProgramAddressSync([buffer_1.Buffer.from('push_identity'), senderBytes], SVM_GATEWAY_PROGRAM);
49
+ return ceaPda;
50
+ }
51
+ /** Derive a standard SPL Associated Token Account address. */
52
+ function deriveAtaPubkey(owner, mint) {
53
+ const [ata] = web3_js_1.PublicKey.findProgramAddressSync([owner.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID);
54
+ return ata;
55
+ }
56
+ /**
57
+ * Returns the (possibly bumped) effectiveGasLimit. Logs the decision via
58
+ * printLog. On any RPC failure or invalid input, logs a warning and returns
59
+ * the input unchanged — better to risk one underflow than to block all SPL
60
+ * outbounds on RPC flake; pre-flight will surface insufficient gas anyway.
61
+ */
62
+ function maybeBumpForCeaAtaRent(input) {
63
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
64
+ var _a, _b, _c, _d, _e;
65
+ const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount, effectiveGasLimit, } = input;
66
+ // Only applies to SPL outbounds. Native SOL outbounds use the gateway's
67
+ // calculateSolExecuteFees which has no ATA conditional.
68
+ if (!splMintBase58 || burnAmount === BigInt(0)) {
69
+ return effectiveGasLimit;
70
+ }
71
+ const rpcUrl = (_c = (_b = (_a = ctx.rpcUrls) === null || _a === void 0 ? void 0 : _a[targetChain]) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : (_e = (_d = chain_1.CHAIN_INFO[targetChain]) === null || _d === void 0 ? void 0 : _d.defaultRPC) === null || _e === void 0 ? void 0 : _e[0];
72
+ if (!rpcUrl) {
73
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — no Solana RPC URL for ${targetChain}; skipping rent bump`);
74
+ return effectiveGasLimit;
75
+ }
76
+ try {
77
+ const ceaPda = deriveSvmCeaPda(ueaAddress);
78
+ const splMint = new web3_js_1.PublicKey(splMintBase58);
79
+ const ceaAta = deriveAtaPubkey(ceaPda, splMint);
80
+ const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
81
+ const info = yield conn.getAccountInfo(ceaAta);
82
+ const ataExists = info !== null && info.data.length > 0;
83
+ if (!ataExists) {
84
+ const bumped = effectiveGasLimit + exports.CEA_ATA_RENT_LAMPORTS_BUMP;
85
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — CEA ATA ${ceaAta.toBase58()} not deployed on ${targetChain}; ` +
86
+ `bumping effectiveGasLimit ${effectiveGasLimit} → ${bumped} ` +
87
+ `(+${exports.CEA_ATA_RENT_LAMPORTS_BUMP} lamports for ATA rent + exec rent + compute buffer)`);
88
+ return bumped;
89
+ }
90
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — CEA ATA ${ceaAta.toBase58()} already deployed on ${targetChain}; no rent bump`);
91
+ return effectiveGasLimit;
92
+ }
93
+ catch (err) {
94
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — RPC error querying CEA ATA on ${targetChain}: ` +
95
+ `${err instanceof Error ? err.message : String(err)}; proceeding without bump`);
96
+ return effectiveGasLimit;
97
+ }
98
+ });
99
+ }
100
+ //# sourceMappingURL=svm-rent.js.map
@@ -126,7 +126,7 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
126
126
  return events;
127
127
  }
128
128
  function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg) {
129
- var _a, _b, _c, _d;
129
+ var _a, _b, _c, _d, _e, _f, _g;
130
130
  const events = [];
131
131
  const targetChain = ((_a = universalTxResponse.chain) !== null && _a !== void 0 ? _a : 'external');
132
132
  const targetAddress = (_d = (_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.recipient) !== null && _d !== void 0 ? _d : universalTxResponse.to;
@@ -138,6 +138,18 @@ function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg)
138
138
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_202_02](targetChain, BigInt(0), BigInt(0)));
139
139
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_01](targetChain));
140
140
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_02](universalTxResponse.from, targetAddress, targetChain, true));
141
+ // Pre-flight reconstruction. Live R2 fires SEND_TX_203_03 once for PRC-20
142
+ // (when funds.amount > 0) and once for native — but historical chain data
143
+ // doesn't preserve the pre-flight values. Emit the native check unconditionally
144
+ // (every R2 outbound has one) and a second copy when the recorded outbound
145
+ // had a non-zero burn amount (proxy for "user supplied funds.amount > 0").
146
+ // Values are zero-placeholders matching the existing 202-02 pattern.
147
+ const ueaFrom = universalTxResponse.from;
148
+ const burnAmount = BigInt((_g = (_f = (_e = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.amount) !== null && _g !== void 0 ? _g : '0');
149
+ if (burnAmount > BigInt(0)) {
150
+ events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03](BigInt(0), BigInt(0), true, ueaFrom, 'R2_EVM', { kind: 'PRC20' }));
151
+ }
152
+ events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03](BigInt(0), BigInt(0), true, ueaFrom, 'R2_EVM', { kind: 'NATIVE' }));
141
153
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_01]());
142
154
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_02]());
143
155
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_03]());
@@ -162,6 +174,9 @@ function reconstructR3(universalTxResponse, universalTxData, isFailed, errorMsg)
162
174
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_02](sourceChain, BigInt(0), BigInt(0)));
163
175
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_01](sourceChain));
164
176
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_02](universalTxResponse.from, ceaAddress, sourceChain));
177
+ // R3 pre-flight reconstruction — R3 EVM burnAmount=0, R3 SVM burnAmount=0
178
+ // (post-fix). Only the NATIVE pre-flight check fires; no PRC-20 second hook.
179
+ events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03](BigInt(0), BigInt(0), true, universalTxResponse.from, 'R3_EVM', { kind: 'NATIVE' }));
165
180
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_304_01]());
166
181
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_304_02]());
167
182
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_304_03]());
@@ -177,7 +177,40 @@ class Orchestrator {
177
177
  // Check if this is a multi-chain request (has ChainTarget or from.chain)
178
178
  const isMultiChain = (0, route_detector_1.isChainTarget)(params.to) || ('from' in params && ((_d = params.from) === null || _d === void 0 ? void 0 : _d.chain));
179
179
  if (isMultiChain) {
180
- return yield (0, internals_1.executeMultiChain)(this.ctx, params, this.execute.bind(this));
180
+ try {
181
+ return yield (0, internals_1.executeMultiChain)(this.ctx, params, this.execute.bind(this));
182
+ }
183
+ catch (err) {
184
+ // R2/R3/R4 outer catch — fires the route-correct terminal failure
185
+ // hook (299-02 / 399-02) when an inner route handler throws BEFORE
186
+ // its own try/catch around executeFn (e.g. pre-flight balance
187
+ // check throws). Without this, the hook stream ends mid-flight and
188
+ // consumers have no terminal close-out marker.
189
+ if (!isRecursiveInnerCall && !this.ctx._routeTerminalEmitted) {
190
+ const errMessage = err instanceof Error
191
+ ? err.message
192
+ : typeof err === 'string'
193
+ ? err
194
+ : 'Unknown error';
195
+ // Lift any structured `decodedError` off the typed error so the
196
+ // formatter's optional payload field gets populated.
197
+ const decodedError = err instanceof Error && err.decodedError
198
+ ? err.decodedError
199
+ : undefined;
200
+ if (this.currentRoute === route_detector_1.TransactionRoute.CEA_TO_PUSH) {
201
+ (0, internals_1.fireProgressHook)(this.ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02, errMessage, 'push', undefined, decodedError);
202
+ }
203
+ else if (this.currentRoute === route_detector_1.TransactionRoute.UOA_TO_CEA) {
204
+ // 299-02 needs the target chain — pull it off ChainTarget.
205
+ const targetChain = (0, route_detector_1.isChainTarget)(params.to) && params.to ? params.to.chain : 'unknown';
206
+ (0, internals_1.fireProgressHook)(this.ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02, targetChain, errMessage, decodedError);
207
+ }
208
+ else {
209
+ (0, internals_1.fireProgressHook)(this.ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, errMessage, decodedError);
210
+ }
211
+ }
212
+ throw err;
213
+ }
181
214
  }
182
215
  // Standard Push Chain execution (Route 1)
183
216
  const execute = params;
@@ -397,6 +397,20 @@ export type UniversalExecuteParams = Omit<ExecuteParams, 'to'> & {
397
397
  * Only applicable for Route 2 (UOA_TO_CEA) on EVM chains.
398
398
  */
399
399
  migration?: boolean;
400
+ /**
401
+ * Per-call SDK behaviour overrides. Reserved for opt-out flags that must
402
+ * not affect the global orchestrator config.
403
+ */
404
+ options?: {
405
+ /**
406
+ * Restore the legacy clamp-and-refund behaviour for outbound paths whose
407
+ * UEA balance is below the buffered pool quote. Default `false` — the
408
+ * SDK throws `InsufficientUEABalanceError` (see `runPreflight`) and does
409
+ * NOT submit a cosmos tx. Set `true` only when the caller intentionally
410
+ * relies on `swapAndBurnGas` refunds to power through low balances.
411
+ */
412
+ allowUnderfundedSwap?: boolean;
413
+ };
400
414
  };
401
415
  /**
402
416
  * Account metadata for SVM CPI execution (Solana Gateway pattern).
@@ -627,9 +641,19 @@ export interface CascadeTrackOptions {
627
641
  /** Per-hop progress callback */
628
642
  progressHook?: (event: CascadeProgressEvent) => void;
629
643
  /**
630
- * Unified ProgressEvent stream for SEND-TX-08/99_03-05 telemetry.
631
- * Fires per outbound hop during external chain polling. Use alongside
632
- * `progressHook` — they emit complementary views of the same events.
644
+ * Unified ProgressEvent stream for the cascade marker set
645
+ * (001 / 002-xx / 203-xx / 204-xx / 209-xx / 299-01 / 999-xx and per-route
646
+ * awaiting/polling/success/failed/timeout hooks).
647
+ *
648
+ * Cascade markers ALSO fan out to the init-time `progressHook` set on
649
+ * `PushChain.initialize` (see `OrchestratorContext.progressHook`), so
650
+ * UI-kit consumers that wired progress at init receive the cascade stream
651
+ * without having to plumb `eventHook` through. When BOTH this `eventHook`
652
+ * and the init-time `ctx.progressHook` are wired, events are delivered to
653
+ * both with dedup (no double-fire if they reference the same function).
654
+ * If you don't want the global init-time `progressHook` to react to
655
+ * cascade markers, filter them inside that handler — there is no
656
+ * cascade-level opt-out for the init-time channel.
633
657
  */
634
658
  eventHook?: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void;
635
659
  }
@@ -54,11 +54,29 @@ class PriceFetch {
54
54
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
55
  }, { commitment: 'confirmed' });
56
56
  const program = new anchor_1.Program(feeLocker_json_1.default, provider);
57
- const result = yield program.methods['getSolPrice']()
58
- .accounts({
59
- priceUpdate: PRICE_ACCOUNT,
60
- })
61
- .view();
57
+ let result;
58
+ try {
59
+ result = yield program.methods['getSolPrice']()
60
+ .accounts({
61
+ priceUpdate: PRICE_ACCOUNT,
62
+ })
63
+ .view();
64
+ }
65
+ catch (err) {
66
+ const e = err;
67
+ console.error('[price-fetch][SVM getSolPrice] FAILED');
68
+ console.error(' rpc:', rpcUrls[0]);
69
+ console.error(' locker:', lockerContract);
70
+ console.error(' priceAccount:', PRICE_ACCOUNT.toBase58());
71
+ console.error(' message:', e === null || e === void 0 ? void 0 : e.message);
72
+ if (e === null || e === void 0 ? void 0 : e.logs)
73
+ console.error(' logs:', e.logs);
74
+ if (e === null || e === void 0 ? void 0 : e.simulationResponse)
75
+ console.error(' simulationResponse:', JSON.stringify(e.simulationResponse, null, 2));
76
+ if (e === null || e === void 0 ? void 0 : e.programErrorStack)
77
+ console.error(' programErrorStack:', e.programErrorStack);
78
+ throw err;
79
+ }
62
80
  if (!result || !result.price) {
63
81
  throw new Error('Invalid price data returned');
64
82
  }
@@ -22,6 +22,14 @@ const friendlyChain = (chainOrNs) => {
22
22
  const key = utils_1.Utils.chains.getChainName(asString);
23
23
  return key ? toTitleCase(key) : asString;
24
24
  };
25
+ /**
26
+ * Format a wei-denominated UPC bigint as a human-readable PC string for use
27
+ * in progress-hook `message` fields. Used by the pre-flight hooks
28
+ * (203-03/04/05 + 003-03/04/05) so consumers see "956.7834 PC" instead of
29
+ * "956783432238079848707 wei UPC". Response payload bigints are NOT
30
+ * transformed — programmatic consumers still get raw wei.
31
+ */
32
+ const formatPC = (wei, precision = 4) => `${utils_1.Utils.helpers.formatUnits(wei, { decimals: 18, precision })} PC`;
25
33
  /**
26
34
  * Classify a sign-time error as either a true wallet user-decline
27
35
  * (viem `UserRejectedRequestError`, ethers `ACTION_REJECTED`, EIP-1193 4001,
@@ -250,11 +258,11 @@ const RAW_HOOKS_R1 = {
250
258
  level: 'SUCCESS',
251
259
  };
252
260
  },
253
- [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02]: (errMessage) => ({
261
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02]: (errMessage, decodedError) => ({
254
262
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02,
255
263
  title: 'Push Chain Tx Failed',
256
264
  message: errMessage,
257
- response: { error: errMessage },
265
+ response: Object.assign({ error: errMessage }, (decodedError ? { decodedError } : {})),
258
266
  level: 'ERROR',
259
267
  }),
260
268
  };
@@ -302,6 +310,62 @@ const RAW_HOOKS_R2 = {
302
310
  response: { uea: ueaAddr, cea: ceaAddr, chain: targetChain, deployed },
303
311
  level: 'SUCCESS',
304
312
  }),
313
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
314
+ var _a, _b, _c;
315
+ const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
316
+ const availableStr = kind === 'PRC20' ? `${available} units` : formatPC(available);
317
+ const requiredStr = kind === 'PRC20' ? `${required} units` : formatPC(required);
318
+ return {
319
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03,
320
+ title: 'Pre-flight Balance Check',
321
+ message: `UEA balance: ${availableStr}; required: ${requiredStr}; ` +
322
+ `${sufficient ? 'sufficient' : 'INSUFFICIENT'} (${pathTag})`,
323
+ response: {
324
+ required,
325
+ available,
326
+ sufficient,
327
+ ueaAddress,
328
+ pathTag,
329
+ kind,
330
+ burnToken: (_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : null,
331
+ segmentIndex: (_c = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _c !== void 0 ? _c : null,
332
+ },
333
+ level: sufficient ? 'INFO' : 'ERROR',
334
+ };
335
+ },
336
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
337
+ var _a, _b, _c, _d;
338
+ const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
339
+ const shortfallStr = kind === 'PRC20' ? `${shortfall} units` : formatPC(shortfall);
340
+ const remediation = kind === 'PRC20'
341
+ ? `Bridge the burn token (${(_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : 'PRC-20'}) to UEA ${ueaAddress} before retrying.`
342
+ : `Bridge >=${shortfallStr} to UEA ${ueaAddress} before retrying.`;
343
+ return {
344
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_04,
345
+ title: 'Insufficient UEA Balance',
346
+ message: `Shortfall ${shortfallStr} on ${pathTag}. ${remediation}`,
347
+ response: {
348
+ required,
349
+ available,
350
+ shortfall,
351
+ ueaAddress,
352
+ pathTag,
353
+ kind,
354
+ burnToken: (_c = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _c !== void 0 ? _c : null,
355
+ segmentIndex: (_d = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _d !== void 0 ? _d : null,
356
+ },
357
+ level: 'ERROR',
358
+ };
359
+ },
360
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_05]: (quoted, threshold, gasToken, pathTag) => ({
361
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_05,
362
+ title: 'SVM Native-Value Warn Threshold',
363
+ message: `Buffered pool quote ${formatPC(quoted)} exceeds warn threshold ${formatPC(threshold)} ` +
364
+ `for ${gasToken} (${pathTag}). Pool may be skewed or quote is unusually large. ` +
365
+ `No action taken — pre-flight will determine if balance covers it.`,
366
+ response: { quoted, threshold, gasToken, pathTag },
367
+ level: 'INFO',
368
+ }),
305
369
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_01]: () => ({
306
370
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_204_01,
307
371
  title: 'Awaiting Signature',
@@ -365,11 +429,11 @@ const RAW_HOOKS_R2 = {
365
429
  response: Object.assign({ txHash: details.externalTxHash }, details),
366
430
  level: 'SUCCESS',
367
431
  }),
368
- [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02]: (targetChain, errorMessage) => ({
432
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02]: (targetChain, errorMessage, decodedError) => ({
369
433
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_02,
370
434
  title: `${friendlyChain(targetChain)} Tx Failed`,
371
435
  message: errorMessage,
372
- response: { error: errorMessage, chain: targetChain },
436
+ response: Object.assign({ error: errorMessage, chain: targetChain }, (decodedError ? { decodedError } : {})),
373
437
  level: 'ERROR',
374
438
  }),
375
439
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_03]: (targetChain, elapsedMs) => ({
@@ -550,7 +614,7 @@ const RAW_HOOKS_R3 = {
550
614
  // Phase is passed by the emission site so the title matches the leg that
551
615
  // actually failed. Default stays 'inbound' for callers that don't specify
552
616
  // (backwards-compat with fixtures + response-builder's inbound block).
553
- [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02]: (errorMessage, phase = 'inbound', chain) => ({
617
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02]: (errorMessage, phase = 'inbound', chain, decodedError) => ({
554
618
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02,
555
619
  title: phase === 'outbound'
556
620
  ? `${friendlyChain(chain)} Tx Failed`
@@ -558,7 +622,7 @@ const RAW_HOOKS_R3 = {
558
622
  ? 'Push Chain Tx Failed'
559
623
  : 'Push Chain Inbound Tx Failed',
560
624
  message: errorMessage,
561
- response: { error: errorMessage, phase, chain: chain !== null && chain !== void 0 ? chain : null },
625
+ response: Object.assign({ error: errorMessage, phase, chain: chain !== null && chain !== void 0 ? chain : null }, (decodedError ? { decodedError } : {})),
562
626
  level: 'ERROR',
563
627
  }),
564
628
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03]: (sourceChain, elapsedMs, phase = 'inbound') => ({
@@ -658,6 +722,66 @@ const RAW_HOOKS_MULTICHAIN = {
658
722
  response: { n, total },
659
723
  level: 'INFO',
660
724
  }),
725
+ // Cascade pre-flight balance check. Mirrors SEND_TX_203_03 from the
726
+ // single-route bucket but lives in the cascade 0xx range so cascade
727
+ // streams remain self-consistent. `runPreflight` switches between
728
+ // 203-xx and 003-xx based on pathTag === 'CASCADE'.
729
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
730
+ var _a, _b, _c;
731
+ const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
732
+ const availableStr = kind === 'PRC20' ? `${available} units` : formatPC(available);
733
+ const requiredStr = kind === 'PRC20' ? `${required} units` : formatPC(required);
734
+ return {
735
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03,
736
+ title: 'Cascade Pre-flight Balance Check',
737
+ message: `UEA balance: ${availableStr}; required: ${requiredStr}; ` +
738
+ `${sufficient ? 'sufficient' : 'INSUFFICIENT'} (${pathTag})`,
739
+ response: {
740
+ required,
741
+ available,
742
+ sufficient,
743
+ ueaAddress,
744
+ pathTag,
745
+ kind,
746
+ burnToken: (_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : null,
747
+ segmentIndex: (_c = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _c !== void 0 ? _c : null,
748
+ },
749
+ level: sufficient ? 'INFO' : 'ERROR',
750
+ };
751
+ },
752
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
753
+ var _a, _b, _c, _d;
754
+ const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
755
+ const shortfallStr = kind === 'PRC20' ? `${shortfall} units` : formatPC(shortfall);
756
+ const remediation = kind === 'PRC20'
757
+ ? `Bridge the burn token (${(_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : 'PRC-20'}) to UEA ${ueaAddress} before retrying.`
758
+ : `Bridge >=${shortfallStr} to UEA ${ueaAddress} before retrying.`;
759
+ return {
760
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04,
761
+ title: 'Cascade Insufficient UEA Balance',
762
+ message: `Shortfall ${shortfallStr} on ${pathTag}. ${remediation}`,
763
+ response: {
764
+ required,
765
+ available,
766
+ shortfall,
767
+ ueaAddress,
768
+ pathTag,
769
+ kind,
770
+ burnToken: (_c = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _c !== void 0 ? _c : null,
771
+ segmentIndex: (_d = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _d !== void 0 ? _d : null,
772
+ },
773
+ level: 'ERROR',
774
+ };
775
+ },
776
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_05]: (quoted, threshold, gasToken, pathTag) => ({
777
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_05,
778
+ title: 'Cascade SVM Native-Value Warn Threshold',
779
+ message: `Buffered pool quote ${formatPC(quoted)} exceeds warn threshold ${formatPC(threshold)} ` +
780
+ `for ${gasToken} (${pathTag}). Pool may be skewed or quote is unusually large. ` +
781
+ `No action taken — pre-flight will determine if balance covers it.`,
782
+ response: { quoted, threshold, gasToken, pathTag },
783
+ level: 'INFO',
784
+ }),
661
785
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_01]: (hopCount) => ({
662
786
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_01,
663
787
  title: 'All Multichain Transactions Successful',
@@ -46,6 +46,9 @@ export declare enum PROGRESS_HOOK {
46
46
  SEND_TX_202_02 = "SEND-TX-202-02",
47
47
  SEND_TX_203_01 = "SEND-TX-203-01",
48
48
  SEND_TX_203_02 = "SEND-TX-203-02",
49
+ SEND_TX_203_03 = "SEND-TX-203-03",
50
+ SEND_TX_203_04 = "SEND-TX-203-04",
51
+ SEND_TX_203_05 = "SEND-TX-203-05",
49
52
  SEND_TX_204_01 = "SEND-TX-204-01",
50
53
  SEND_TX_204_02 = "SEND-TX-204-02",
51
54
  SEND_TX_204_03 = "SEND-TX-204-03",
@@ -81,6 +84,9 @@ export declare enum PROGRESS_HOOK {
81
84
  SEND_TX_001 = "SEND-TX-001",
82
85
  SEND_TX_002_01 = "SEND-TX-002-01",
83
86
  SEND_TX_002_99_99 = "SEND-TX-002-99-99",
87
+ SEND_TX_003_03 = "SEND-TX-003-03",// Cascade pre-flight balance check (INFO when sufficient, ERROR when insufficient)
88
+ SEND_TX_003_04 = "SEND-TX-003-04",// Cascade pre-flight FAILED (ERROR, terminal precursor before 999-02)
89
+ SEND_TX_003_05 = "SEND-TX-003-05",// Cascade SVM warn-threshold tripped (INFO, no action)
84
90
  SEND_TX_999_01 = "SEND-TX-999-01",
85
91
  SEND_TX_999_02 = "SEND-TX-999-02",
86
92
  SEND_TX_999_03 = "SEND-TX-999-03",
@@ -92,8 +98,8 @@ export declare enum PROGRESS_HOOK {
92
98
  UEA_MIG_9903 = "UEA-MIG-9903"
93
99
  }
94
100
  export type PROGRESS_HOOK_R1 = PROGRESS_HOOK.SEND_TX_101 | PROGRESS_HOOK.SEND_TX_102_01 | PROGRESS_HOOK.SEND_TX_103_01 | PROGRESS_HOOK.SEND_TX_103_02 | PROGRESS_HOOK.SEND_TX_103_03 | PROGRESS_HOOK.SEND_TX_103_03_01 | PROGRESS_HOOK.SEND_TX_103_03_02 | PROGRESS_HOOK.SEND_TX_103_03_03 | PROGRESS_HOOK.SEND_TX_103_03_04 | PROGRESS_HOOK.SEND_TX_104_01 | PROGRESS_HOOK.SEND_TX_104_02 | PROGRESS_HOOK.SEND_TX_104_03 | PROGRESS_HOOK.SEND_TX_104_04 | PROGRESS_HOOK.SEND_TX_105_01 | PROGRESS_HOOK.SEND_TX_105_02 | PROGRESS_HOOK.SEND_TX_106_01 | PROGRESS_HOOK.SEND_TX_106_02 | PROGRESS_HOOK.SEND_TX_106_03 | PROGRESS_HOOK.SEND_TX_106_03_01 | PROGRESS_HOOK.SEND_TX_106_03_02 | PROGRESS_HOOK.SEND_TX_106_04 | PROGRESS_HOOK.SEND_TX_106_05 | PROGRESS_HOOK.SEND_TX_106_06 | PROGRESS_HOOK.SEND_TX_107 | PROGRESS_HOOK.SEND_TX_199_01 | PROGRESS_HOOK.SEND_TX_199_02;
95
- export type PROGRESS_HOOK_R2 = PROGRESS_HOOK.SEND_TX_201 | PROGRESS_HOOK.SEND_TX_202_01 | PROGRESS_HOOK.SEND_TX_202_02 | PROGRESS_HOOK.SEND_TX_203_01 | PROGRESS_HOOK.SEND_TX_203_02 | PROGRESS_HOOK.SEND_TX_204_01 | PROGRESS_HOOK.SEND_TX_204_02 | PROGRESS_HOOK.SEND_TX_204_03 | PROGRESS_HOOK.SEND_TX_204_04 | PROGRESS_HOOK.SEND_TX_207 | PROGRESS_HOOK.SEND_TX_209_01 | PROGRESS_HOOK.SEND_TX_209_02 | PROGRESS_HOOK.SEND_TX_299_01 | PROGRESS_HOOK.SEND_TX_299_02 | PROGRESS_HOOK.SEND_TX_299_03 | PROGRESS_HOOK.SEND_TX_299_99;
101
+ export type PROGRESS_HOOK_R2 = PROGRESS_HOOK.SEND_TX_201 | PROGRESS_HOOK.SEND_TX_202_01 | PROGRESS_HOOK.SEND_TX_202_02 | PROGRESS_HOOK.SEND_TX_203_01 | PROGRESS_HOOK.SEND_TX_203_02 | PROGRESS_HOOK.SEND_TX_203_03 | PROGRESS_HOOK.SEND_TX_203_04 | PROGRESS_HOOK.SEND_TX_203_05 | PROGRESS_HOOK.SEND_TX_204_01 | PROGRESS_HOOK.SEND_TX_204_02 | PROGRESS_HOOK.SEND_TX_204_03 | PROGRESS_HOOK.SEND_TX_204_04 | PROGRESS_HOOK.SEND_TX_207 | PROGRESS_HOOK.SEND_TX_209_01 | PROGRESS_HOOK.SEND_TX_209_02 | PROGRESS_HOOK.SEND_TX_299_01 | PROGRESS_HOOK.SEND_TX_299_02 | PROGRESS_HOOK.SEND_TX_299_03 | PROGRESS_HOOK.SEND_TX_299_99;
96
102
  export type PROGRESS_HOOK_R3 = PROGRESS_HOOK.SEND_TX_199_99_99 | PROGRESS_HOOK.SEND_TX_301 | PROGRESS_HOOK.SEND_TX_302_01 | PROGRESS_HOOK.SEND_TX_302_02 | PROGRESS_HOOK.SEND_TX_303_01 | PROGRESS_HOOK.SEND_TX_303_02 | PROGRESS_HOOK.SEND_TX_303_03_01 | PROGRESS_HOOK.SEND_TX_303_03_02 | PROGRESS_HOOK.SEND_TX_303_03_03 | PROGRESS_HOOK.SEND_TX_304_01 | PROGRESS_HOOK.SEND_TX_304_02 | PROGRESS_HOOK.SEND_TX_304_03 | PROGRESS_HOOK.SEND_TX_304_04 | PROGRESS_HOOK.SEND_TX_307 | PROGRESS_HOOK.SEND_TX_309_01 | PROGRESS_HOOK.SEND_TX_309_02 | PROGRESS_HOOK.SEND_TX_309_03 | PROGRESS_HOOK.SEND_TX_310_01 | PROGRESS_HOOK.SEND_TX_310_02 | PROGRESS_HOOK.SEND_TX_399_01 | PROGRESS_HOOK.SEND_TX_399_02 | PROGRESS_HOOK.SEND_TX_399_03;
97
- export type PROGRESS_HOOK_MULTICHAIN = PROGRESS_HOOK.SEND_TX_001 | PROGRESS_HOOK.SEND_TX_002_01 | PROGRESS_HOOK.SEND_TX_002_99_99 | PROGRESS_HOOK.SEND_TX_999_01 | PROGRESS_HOOK.SEND_TX_999_02 | PROGRESS_HOOK.SEND_TX_999_03;
103
+ export type PROGRESS_HOOK_MULTICHAIN = PROGRESS_HOOK.SEND_TX_001 | PROGRESS_HOOK.SEND_TX_002_01 | PROGRESS_HOOK.SEND_TX_002_99_99 | PROGRESS_HOOK.SEND_TX_003_03 | PROGRESS_HOOK.SEND_TX_003_04 | PROGRESS_HOOK.SEND_TX_003_05 | PROGRESS_HOOK.SEND_TX_999_01 | PROGRESS_HOOK.SEND_TX_999_02 | PROGRESS_HOOK.SEND_TX_999_03;
98
104
  export type PROGRESS_HOOK_MIG = PROGRESS_HOOK.UEA_MIG_01 | PROGRESS_HOOK.UEA_MIG_02 | PROGRESS_HOOK.UEA_MIG_03 | PROGRESS_HOOK.UEA_MIG_9901 | PROGRESS_HOOK.UEA_MIG_9902 | PROGRESS_HOOK.UEA_MIG_9903;
99
105
  export {};
@@ -37,6 +37,13 @@ var PROGRESS_HOOK;
37
37
  PROGRESS_HOOK["SEND_TX_202_02"] = "SEND-TX-202-02";
38
38
  PROGRESS_HOOK["SEND_TX_203_01"] = "SEND-TX-203-01";
39
39
  PROGRESS_HOOK["SEND_TX_203_02"] = "SEND-TX-203-02";
40
+ // Pre-flight balance check (203-03 INFO when sufficient or burn-token check passes;
41
+ // 203-04 ERROR terminal precursor on shortfall; 203-05 INFO SVM warn-threshold tripped).
42
+ // 203 bucket choice is temporal (sits between 203-02 CEA-resolved and 204-01 sign),
43
+ // not strictly semantic — UEA balance is on Push Chain, not the destination CEA.
44
+ PROGRESS_HOOK["SEND_TX_203_03"] = "SEND-TX-203-03";
45
+ PROGRESS_HOOK["SEND_TX_203_04"] = "SEND-TX-203-04";
46
+ PROGRESS_HOOK["SEND_TX_203_05"] = "SEND-TX-203-05";
40
47
  PROGRESS_HOOK["SEND_TX_204_01"] = "SEND-TX-204-01";
41
48
  PROGRESS_HOOK["SEND_TX_204_02"] = "SEND-TX-204-02";
42
49
  PROGRESS_HOOK["SEND_TX_204_03"] = "SEND-TX-204-03";
@@ -74,6 +81,14 @@ var PROGRESS_HOOK;
74
81
  PROGRESS_HOOK["SEND_TX_001"] = "SEND-TX-001";
75
82
  PROGRESS_HOOK["SEND_TX_002_01"] = "SEND-TX-002-01";
76
83
  PROGRESS_HOOK["SEND_TX_002_99_99"] = "SEND-TX-002-99-99";
84
+ // Cascade-scoped pre-flight hooks. Mirror the single-route 203-03/04/05
85
+ // semantics but live in the 0xx bucket so cascade hook streams stay
86
+ // self-consistent (rest of cascade uses 001 / 002-xx / 999-xx). The
87
+ // runPreflight helper switches between 203-xx and 003-xx based on
88
+ // pathTag === 'CASCADE'.
89
+ PROGRESS_HOOK["SEND_TX_003_03"] = "SEND-TX-003-03";
90
+ PROGRESS_HOOK["SEND_TX_003_04"] = "SEND-TX-003-04";
91
+ PROGRESS_HOOK["SEND_TX_003_05"] = "SEND-TX-003-05";
77
92
  PROGRESS_HOOK["SEND_TX_999_01"] = "SEND-TX-999-01";
78
93
  PROGRESS_HOOK["SEND_TX_999_02"] = "SEND-TX-999-02";
79
94
  PROGRESS_HOOK["SEND_TX_999_03"] = "SEND-TX-999-03";
@@ -94,7 +94,7 @@ export declare function deriveSvmCeaPda(ueaAddress: `0x${string}`, targetChain:
94
94
  *
95
95
  * @param account - UniversalAccount with chain and address.
96
96
  * @param options.chain - Target external chain for CEA derivation. If omitted, returns UEA.
97
- * @param options.skipNetworkCheck - If true, skip deployment check and return deployed: false.
97
+ * @param options.skipNetworkCheck - If true, skip deployment check and return deployed: null.
98
98
  * @returns The derived executor account address and deployment status.
99
99
  */
100
100
  export declare function deriveExecutorAccount(account: UniversalAccount, options?: {
@@ -471,7 +471,7 @@ function deriveSvmCeaPda(ueaAddress, targetChain, skipNetworkCheck) {
471
471
  *
472
472
  * @param account - UniversalAccount with chain and address.
473
473
  * @param options.chain - Target external chain for CEA derivation. If omitted, returns UEA.
474
- * @param options.skipNetworkCheck - If true, skip deployment check and return deployed: false.
474
+ * @param options.skipNetworkCheck - If true, skip deployment check and return deployed: null.
475
475
  * @returns The derived executor account address and deployment status.
476
476
  */
477
477
  function deriveExecutorAccount(account, options) {
@@ -135,6 +135,21 @@ function resolveChildInboundsFromLogs(pushClient, sourceChainCaip, externalTxHas
135
135
  }
136
136
  catch (err) {
137
137
  diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.push(`getUniversalTxByIdV2(${utxIdHex}) failed: ${err instanceof Error ? err.message : String(err)}`);
138
+ // Cosmos lookup failed (commonly NotFound while the indexer is still
139
+ // catching up). The utxId is deterministically derived from the source
140
+ // log, so surface it as notFound rather than dropping the entry —
141
+ // otherwise callers like inbound-tracker repeatedly re-run the full
142
+ // detector pass instead of advancing to lightweight status polling.
143
+ out.push({
144
+ universalTxId: utxIdHex,
145
+ sourceLogIndex: log.logIndex,
146
+ sourceEventName: log.eventName,
147
+ status: 0,
148
+ statusName: STATUS_NAMES[0],
149
+ pcTxHashes: [],
150
+ outboundHashes: [],
151
+ notFound: true,
152
+ });
138
153
  }
139
154
  }
140
155
  return out;