@pushchain/core 5.1.15 → 5.1.17

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.
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ /**
3
+ * Decoder for revert-error messages surfaced by Cosmos `tx.rawLog`.
4
+ *
5
+ * Two extraction paths:
6
+ * 1. 4-byte custom selector (e.g. `0xacfdb444:` or `0xf4d678b8000000…`) —
7
+ * looked up against `KNOWN_ERROR_SELECTORS` for a friendly name + hint.
8
+ * 2. `Error(string)` ABI-encoded revert (`0x08c379a0` selector + offset +
9
+ * length + data) — decoded into the original UTF-8 string.
10
+ *
11
+ * Unknown selectors fall through with `kind: 'unknown'` so callers can log
12
+ * them at INFO and grow the table from real reverts.
13
+ *
14
+ * The selector→name mappings below are EMPIRICAL: they were observed in
15
+ * production e2e logs and SDK test fixtures. `keccak256` of the obvious
16
+ * parameterless signatures (e.g. `keccak256("InsufficientBalance()")` =
17
+ * `0x01e1e567`) does NOT reproduce the listed selectors, so the deployed-
18
+ * source mapping is still unverified. Names and hints are worded as
19
+ * "likely cause" until the bytecode-source trace lands.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.ERROR_STRING_SELECTOR = exports.KNOWN_ERROR_SELECTORS = void 0;
23
+ exports.decodeRevert = decodeRevert;
24
+ exports.KNOWN_ERROR_SELECTORS = {
25
+ '0xacfdb444': {
26
+ name: 'ExecutionFailed',
27
+ hint: 'Likely cause: subcall reverted (target contract or internal gas-swap precompile). ' +
28
+ 'Check that the target accepts native value (has receive/fallback) and that calldata matches a valid signature. ' +
29
+ 'Note: this selector also fires from internal SDK paths (e.g. fresh-wallet gas-swap) — see route2-fresh-wallet-gas-bug.spec.ts.',
30
+ provenance: 'Production e2e: e2e-2026-04-09T13-58-42-237Z.log:103 (R2 EVM target revert)',
31
+ },
32
+ '0x179a867c': {
33
+ name: 'ExpiredDeadline',
34
+ hint: 'Likely cause: transaction deadline passed before relay. Retry — the SDK will set a new deadline.',
35
+ provenance: 'Production e2e (associated with deadline-related reverts)',
36
+ },
37
+ '0xf4d678b8': {
38
+ name: 'InsufficientBalance',
39
+ hint: 'Likely cause: UEA does not hold enough of the burn token (PRC-20 mapped from the outbound `funds.token`). ' +
40
+ 'For Solana SPL outbounds, ensure UEA holds the corresponding pUSDT.sol / pUSDC.sol mint before retrying. ' +
41
+ 'Same selector may also surface from other balance-check reverters; verify burn-token balance first.',
42
+ provenance: 'Production e2e: e2e-2026-04-16T16-27-58-082Z.log:342 (R2 SPL fresh-UEA, no pUSDT.sol)',
43
+ },
44
+ '0x66f9d09e': {
45
+ name: 'GasLimitBelowBase',
46
+ hint: 'Likely cause: provided gasLimit is below the chain minimum. Omit `gasLimit` to use the per-chain default.',
47
+ provenance: 'Observed in dev (selector source unverified — see plan §9 #5)',
48
+ },
49
+ };
50
+ /** Selector for `Error(string)` (Solidity `require(false, "msg")`). */
51
+ exports.ERROR_STRING_SELECTOR = '0x08c379a0';
52
+ /** Hard cap on the decoded string length; protects against malformed data. */
53
+ const MAX_DECODED_STRING_LEN = 1024;
54
+ /**
55
+ * Extracts the first hex blob after `ret ` from a Cosmos tx error message,
56
+ * pulls the 4-byte selector, and looks it up. Returns `null` when no blob
57
+ * is found.
58
+ *
59
+ * **Assumption**: today's Cosmos `tx.rawLog` format contains a single
60
+ * `ret 0x…:` substring per failed message. If a future log format includes
61
+ * nested call traces with multiple `ret` substrings, this regex will pick
62
+ * the first selector — which may not be the most relevant one. Revisit
63
+ * if multi-revert log formats appear in production.
64
+ */
65
+ function decodeRevert(errorMsg) {
66
+ if (!errorMsg)
67
+ return null;
68
+ const m = errorMsg.match(/ret (0x[0-9a-fA-F]+)/);
69
+ if (!m)
70
+ return null;
71
+ const blob = m[1].toLowerCase();
72
+ if (blob.length < 10)
73
+ return null;
74
+ const sel = blob.slice(0, 10);
75
+ const entry = exports.KNOWN_ERROR_SELECTORS[sel];
76
+ if (entry) {
77
+ return {
78
+ kind: 'custom',
79
+ selector: sel,
80
+ name: entry.name,
81
+ hint: entry.hint,
82
+ provenance: entry.provenance,
83
+ };
84
+ }
85
+ if (sel === exports.ERROR_STRING_SELECTOR) {
86
+ try {
87
+ const data = blob.slice(10);
88
+ // Error(string) ABI: offset(32 bytes) + length(32 bytes) + data
89
+ // Skip the 32-byte offset (always 0x20).
90
+ const lengthHex = data.slice(64, 128);
91
+ if (lengthHex.length === 64) {
92
+ const length = parseInt(lengthHex, 16);
93
+ if (Number.isFinite(length) &&
94
+ length > 0 &&
95
+ length < MAX_DECODED_STRING_LEN) {
96
+ const strHex = data.slice(128, 128 + length * 2);
97
+ if (strHex.length === length * 2) {
98
+ const decoded = Buffer.from(strHex, 'hex').toString('utf8');
99
+ return { kind: 'string', selector: sel, decoded };
100
+ }
101
+ }
102
+ }
103
+ }
104
+ catch (_a) {
105
+ /* fall through to unknown */
106
+ }
107
+ }
108
+ return { kind: 'unknown', selector: sel };
109
+ }
110
+ //# sourceMappingURL=error-decoder.js.map
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Typed errors for orchestrator pre-flight checks.
3
+ *
4
+ * `PushChainExecutionError` lives here (instead of push-chain-tx.ts) so the
5
+ * pre-flight `InsufficientUEABalanceError` can extend it without creating a
6
+ * circular import (preflight.ts → errors.ts → push-chain-tx.ts → context.ts
7
+ * → … → route-handlers.ts → preflight.ts). push-chain-tx.ts re-exports it
8
+ * for backward-compat with existing `instanceof PushChainExecutionError`
9
+ * callers.
10
+ */
11
+ /**
12
+ * Structured decoded-error payload attached to terminal failure hooks
13
+ * (199-02 / 299-02 / 399-02). Mirrors the optional formatter parameter
14
+ * shape so the orchestrator's outer catch can lift it off the thrown
15
+ * error and pass it straight through.
16
+ */
17
+ export interface DecodedErrorPayload {
18
+ name?: string;
19
+ hint?: string;
20
+ selector?: string;
21
+ decoded?: string;
22
+ }
23
+ /**
24
+ * Typed error for Route 1 Push Chain tx failures. Thrown by
25
+ * `extractPcTxAndTransform` when the final pcTx commits with `status === 'FAILED'`,
26
+ * and surfaced as `SEND_TX_199_02` on the live stream. The readonly `code`
27
+ * discriminator lets callers classify via `instanceof PushChainExecutionError`
28
+ * instead of sniffing error messages.
29
+ *
30
+ * Carries the origin-chain gateway tx hash. There is no successful Push Chain
31
+ * tx to reference on this path — by definition the pcTx committed `FAILED`.
32
+ *
33
+ * `decodedError`: optional structured payload that flows through to terminal
34
+ * failure hook payloads (199-02 / 299-02 / 399-02 / 999-02). Set by the
35
+ * decoder wire-in (push-chain-tx.ts) and by InsufficientUEABalanceError so
36
+ * consumers don't have to parse the message string.
37
+ */
38
+ export declare class PushChainExecutionError extends Error {
39
+ readonly code: "PUSH_CHAIN_EXECUTION_FAILED";
40
+ readonly gatewayTxHash?: string;
41
+ readonly decodedError?: DecodedErrorPayload;
42
+ constructor(message: string, opts?: {
43
+ gatewayTxHash?: string;
44
+ decodedError?: DecodedErrorPayload;
45
+ });
46
+ }
47
+ export type PreflightPathTag = 'R2_EVM' | 'R2_SVM' | 'R3_EVM' | 'R3_SVM' | 'CASCADE';
48
+ export type PreflightShortfallReason = 'NATIVE' | 'PRC20';
49
+ export interface InsufficientUEABalanceErrorOpts {
50
+ required: bigint;
51
+ available: bigint;
52
+ shortfall: bigint;
53
+ ueaAddress: `0x${string}`;
54
+ pathTag: PreflightPathTag;
55
+ /** 'NATIVE' = UPC shortfall; 'PRC20' = burn-token shortfall. */
56
+ reason?: PreflightShortfallReason;
57
+ /** Burn token address (only set when reason === 'PRC20'). */
58
+ burnToken?: `0x${string}`;
59
+ /** Cascade-only: zero-based index of the failing segment. */
60
+ segmentIndex?: number;
61
+ }
62
+ /**
63
+ * Thrown by `runPreflight` when the UEA cannot cover the required outbound
64
+ * cost. No cosmos tx is submitted on this path — the existing silent-clamp
65
+ * behaviour was previously submitting under-funded swaps that reverted
66
+ * inside Uniswap with `Error("STF")`.
67
+ */
68
+ export declare class InsufficientUEABalanceError extends PushChainExecutionError {
69
+ readonly required: bigint;
70
+ readonly available: bigint;
71
+ readonly shortfall: bigint;
72
+ readonly ueaAddress: `0x${string}`;
73
+ readonly pathTag: PreflightPathTag;
74
+ readonly reason: PreflightShortfallReason;
75
+ readonly burnToken?: `0x${string}`;
76
+ readonly segmentIndex?: number;
77
+ constructor(opts: InsufficientUEABalanceErrorOpts);
78
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * Typed errors for orchestrator pre-flight checks.
4
+ *
5
+ * `PushChainExecutionError` lives here (instead of push-chain-tx.ts) so the
6
+ * pre-flight `InsufficientUEABalanceError` can extend it without creating a
7
+ * circular import (preflight.ts → errors.ts → push-chain-tx.ts → context.ts
8
+ * → … → route-handlers.ts → preflight.ts). push-chain-tx.ts re-exports it
9
+ * for backward-compat with existing `instanceof PushChainExecutionError`
10
+ * callers.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.InsufficientUEABalanceError = exports.PushChainExecutionError = void 0;
14
+ /**
15
+ * Typed error for Route 1 Push Chain tx failures. Thrown by
16
+ * `extractPcTxAndTransform` when the final pcTx commits with `status === 'FAILED'`,
17
+ * and surfaced as `SEND_TX_199_02` on the live stream. The readonly `code`
18
+ * discriminator lets callers classify via `instanceof PushChainExecutionError`
19
+ * instead of sniffing error messages.
20
+ *
21
+ * Carries the origin-chain gateway tx hash. There is no successful Push Chain
22
+ * tx to reference on this path — by definition the pcTx committed `FAILED`.
23
+ *
24
+ * `decodedError`: optional structured payload that flows through to terminal
25
+ * failure hook payloads (199-02 / 299-02 / 399-02 / 999-02). Set by the
26
+ * decoder wire-in (push-chain-tx.ts) and by InsufficientUEABalanceError so
27
+ * consumers don't have to parse the message string.
28
+ */
29
+ class PushChainExecutionError extends Error {
30
+ constructor(message, opts = {}) {
31
+ super(message);
32
+ this.code = 'PUSH_CHAIN_EXECUTION_FAILED';
33
+ this.name = 'PushChainExecutionError';
34
+ this.gatewayTxHash = opts.gatewayTxHash;
35
+ this.decodedError = opts.decodedError;
36
+ }
37
+ }
38
+ exports.PushChainExecutionError = PushChainExecutionError;
39
+ /**
40
+ * Thrown by `runPreflight` when the UEA cannot cover the required outbound
41
+ * cost. No cosmos tx is submitted on this path — the existing silent-clamp
42
+ * behaviour was previously submitting under-funded swaps that reverted
43
+ * inside Uniswap with `Error("STF")`.
44
+ */
45
+ class InsufficientUEABalanceError extends PushChainExecutionError {
46
+ constructor(opts) {
47
+ var _a;
48
+ const reason = (_a = opts.reason) !== null && _a !== void 0 ? _a : 'NATIVE';
49
+ const segLabel = opts.segmentIndex !== undefined ? `:seg${opts.segmentIndex}` : '';
50
+ const tokenSuffix = reason === 'PRC20' && opts.burnToken
51
+ ? ` of token ${opts.burnToken}`
52
+ : '';
53
+ const currencyLabel = reason === 'PRC20' ? 'units' : 'wei UPC';
54
+ const remediation = reason === 'PRC20'
55
+ ? `Bridge the burn token to UEA on Push Chain before retrying.`
56
+ : `Bridge >=${opts.shortfall} wei UPC to the UEA on Push Chain before retrying.`;
57
+ const message = `InsufficientUEABalance [${opts.pathTag}${segLabel}:${reason}]: ` +
58
+ `UEA ${opts.ueaAddress} has ${opts.available} ${currencyLabel}${tokenSuffix}; ` +
59
+ `outbound requires ${opts.required} ${currencyLabel}; shortfall ${opts.shortfall} ${currencyLabel}. ` +
60
+ remediation;
61
+ // Lift the structured info into the parent's decodedError so the
62
+ // orchestrator's outer catch can pass it straight through to the
63
+ // terminal failure hook payload (299-02 / 399-02 / 999-02) without
64
+ // parsing the message string.
65
+ super(message, {
66
+ decodedError: {
67
+ name: 'InsufficientUEABalance',
68
+ hint: remediation,
69
+ },
70
+ });
71
+ this.name = 'InsufficientUEABalanceError';
72
+ this.required = opts.required;
73
+ this.available = opts.available;
74
+ this.shortfall = opts.shortfall;
75
+ this.ueaAddress = opts.ueaAddress;
76
+ this.pathTag = opts.pathTag;
77
+ this.reason = reason;
78
+ this.burnToken = opts.burnToken;
79
+ this.segmentIndex = opts.segmentIndex;
80
+ }
81
+ }
82
+ exports.InsufficientUEABalanceError = InsufficientUEABalanceError;
83
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Shared pre-flight balance check for all six outbound paths
3
+ * (R2 EVM, R2 SVM, R3 EVM, R3 SVM, Cascade EVM, Cascade SVM).
4
+ *
5
+ * Today the route handlers silently clamp `nativeValueForGas` down to a
6
+ * value the UEA cannot fully cover, then submit anyway. The under-funded
7
+ * swap reverts inside Uniswap V3's `TransferHelper.safeTransferFrom`
8
+ * with `Error("STF")`, fees are burned, and the user sees an opaque
9
+ * library string with no balance signal.
10
+ *
11
+ * `runPreflight` replaces that branch: it checks the **pre-clamp**
12
+ * buffered pool quote against UEA balance (and optionally a PRC-20 burn
13
+ * balance) and either:
14
+ * - emits `SEND-TX-203-03` (INFO, sufficient) and lets the caller proceed; or
15
+ * - emits `SEND-TX-203-03` (ERROR, insufficient) + `SEND-TX-203-04` and
16
+ * throws `InsufficientUEABalanceError`.
17
+ *
18
+ * The helper is intentionally not "pure" — it emits hooks and may throw.
19
+ * Callers fetch all balances (so the helper itself does no I/O).
20
+ */
21
+ import type { OrchestratorContext } from './context';
22
+ import { type PreflightPathTag } from './errors';
23
+ export interface RunPreflightOpts {
24
+ ctx: OrchestratorContext;
25
+ ueaAddress: `0x${string}`;
26
+ /** Effective UEA balance in wei UPC (already includes fresh-wallet prediction). */
27
+ ueaBalance: bigint;
28
+ /** Buffered pool quote (pre-clamp) — what the SDK would actually attempt. */
29
+ requiredValue: bigint;
30
+ /** Reserve covering outer-tx gas + approve(s). */
31
+ gasReserve: bigint;
32
+ pathTag: PreflightPathTag;
33
+ /** Optional: PRC-20 burn token + amount + on-chain UEA balance. */
34
+ burnToken?: `0x${string}`;
35
+ burnAmount?: bigint;
36
+ prc20Balance?: bigint;
37
+ /** Cascade-only: identifies which segment failed. */
38
+ segmentIndex?: number;
39
+ /**
40
+ * Per-call opt-out (`params.options.allowUnderfundedSwap`). When `true`,
41
+ * pre-flight logs the shortfall but does NOT fire 203-04 or throw —
42
+ * caller can fall back to the legacy clamp-and-refund branch.
43
+ */
44
+ allowUnderfundedSwap?: boolean;
45
+ }
46
+ export type PreflightResult = {
47
+ ok: true;
48
+ /** What `nativeValueForGas` should be (== requiredValue when sufficient). */
49
+ adjustedValue: bigint;
50
+ } | {
51
+ ok: false;
52
+ /** Set when allowUnderfundedSwap=true: the legacy clamped value. */
53
+ legacyClampedValue: bigint;
54
+ };
55
+ /**
56
+ * Pre-flight check. PRC-20 balance is checked before the native check —
57
+ * a missing burn token fails before the gas-balance check, so the user
58
+ * sees the actionable PRC-20 shortfall instead of a stale UPC error.
59
+ *
60
+ * Returns a result object instead of throwing for the legacy opt-out
61
+ * path. The throw happens here (not in the caller) for the default
62
+ * `allowUnderfundedSwap=false` case so all 6 paths share one throw site.
63
+ */
64
+ export declare function runPreflight(opts: RunPreflightOpts): PreflightResult;
65
+ /**
66
+ * SVM-only telemetry threshold. Buffered pool quotes above this value
67
+ * fire `SEND-TX-203-05` (R2 single-route), `SEND-TX-303-06` (R3
68
+ * single-route), or `SEND-TX-003-05` (cascade). The threshold is for
69
+ * visibility, not truncation — pre-flight handles drain protection.
70
+ * v2 may add a hard cap once telemetry justifies a number.
71
+ */
72
+ export declare const SVM_NATIVE_VALUE_WARN_THRESHOLD: bigint;
73
+ /**
74
+ * Fire the SVM warn-threshold hook + log line if the buffered quote
75
+ * exceeds the threshold. Non-blocking; `nativeValueForGas` is not
76
+ * truncated by the caller. The hook ID switches between buckets so
77
+ * each stream stays self-consistent within its convention (R2 → 203,
78
+ * R3 → 303, cascade → 003).
79
+ */
80
+ export declare function maybeFireSvmWarnThreshold(ctx: OrchestratorContext, bufferedQuote: bigint, gasToken: `0x${string}`, pathTag: PreflightPathTag): void;
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ /**
3
+ * Shared pre-flight balance check for all six outbound paths
4
+ * (R2 EVM, R2 SVM, R3 EVM, R3 SVM, Cascade EVM, Cascade SVM).
5
+ *
6
+ * Today the route handlers silently clamp `nativeValueForGas` down to a
7
+ * value the UEA cannot fully cover, then submit anyway. The under-funded
8
+ * swap reverts inside Uniswap V3's `TransferHelper.safeTransferFrom`
9
+ * with `Error("STF")`, fees are burned, and the user sees an opaque
10
+ * library string with no balance signal.
11
+ *
12
+ * `runPreflight` replaces that branch: it checks the **pre-clamp**
13
+ * buffered pool quote against UEA balance (and optionally a PRC-20 burn
14
+ * balance) and either:
15
+ * - emits `SEND-TX-203-03` (INFO, sufficient) and lets the caller proceed; or
16
+ * - emits `SEND-TX-203-03` (ERROR, insufficient) + `SEND-TX-203-04` and
17
+ * throws `InsufficientUEABalanceError`.
18
+ *
19
+ * The helper is intentionally not "pure" — it emits hooks and may throw.
20
+ * Callers fetch all balances (so the helper itself does no I/O).
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.SVM_NATIVE_VALUE_WARN_THRESHOLD = void 0;
24
+ exports.runPreflight = runPreflight;
25
+ exports.maybeFireSvmWarnThreshold = maybeFireSvmWarnThreshold;
26
+ const context_1 = require("./context");
27
+ const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
28
+ const errors_1 = require("./errors");
29
+ /**
30
+ * Internal: compute the legacy clamp value (matches the pre-existing
31
+ * branches in route-handlers.ts:643-659 / :968-980 / :1396-1412).
32
+ * Returned only when `allowUnderfundedSwap=true`.
33
+ */
34
+ function legacyClamp(ueaBalance, requiredValue, gasReserve) {
35
+ if (ueaBalance >= requiredValue + gasReserve)
36
+ return requiredValue;
37
+ if (ueaBalance > gasReserve)
38
+ return ueaBalance - gasReserve;
39
+ if (ueaBalance > BigInt(0))
40
+ return ueaBalance < requiredValue ? ueaBalance : requiredValue;
41
+ return BigInt(0);
42
+ }
43
+ /**
44
+ * Pre-flight check. PRC-20 balance is checked before the native check —
45
+ * a missing burn token fails before the gas-balance check, so the user
46
+ * sees the actionable PRC-20 shortfall instead of a stale UPC error.
47
+ *
48
+ * Returns a result object instead of throwing for the legacy opt-out
49
+ * path. The throw happens here (not in the caller) for the default
50
+ * `allowUnderfundedSwap=false` case so all 6 paths share one throw site.
51
+ */
52
+ function runPreflight(opts) {
53
+ const { ctx, ueaAddress, ueaBalance, requiredValue, gasReserve, pathTag, burnToken, burnAmount, prc20Balance, segmentIndex, allowUnderfundedSwap, } = opts;
54
+ // Each route bucket gets its own preflight IDs so hook streams stay
55
+ // self-consistent within their convention (R2 → 203-xx, R3 → 303-xx,
56
+ // cascade → 003-xx). The three hook formatters share an identical
57
+ // signature, so the runtime branching is just an ID swap at each fire site.
58
+ const isCascade = pathTag === 'CASCADE';
59
+ const isR3 = pathTag === 'R3_EVM' || pathTag === 'R3_SVM';
60
+ const HOOK_PRE_INFO = isCascade
61
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03
62
+ : isR3
63
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_04
64
+ : progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03;
65
+ const HOOK_PRE_FAIL = isCascade
66
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04
67
+ : isR3
68
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_05
69
+ : progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_04;
70
+ // 1. PRC-20 burn-balance check (skipped when burnAmount = 0 — R3 paths
71
+ // structurally hold zero of the source-chain native PRC-20; see plan §9 #4).
72
+ if (burnAmount && burnAmount > BigInt(0) && burnToken) {
73
+ const onHand = prc20Balance !== null && prc20Balance !== void 0 ? prc20Balance : BigInt(0);
74
+ const sufficient = onHand >= burnAmount;
75
+ (0, context_1.fireProgressHook)(ctx, HOOK_PRE_INFO, burnAmount, onHand, sufficient, ueaAddress, pathTag, { kind: 'PRC20', burnToken, segmentIndex });
76
+ if (!sufficient) {
77
+ const shortfall = burnAmount - onHand;
78
+ if (allowUnderfundedSwap) {
79
+ (0, context_1.printLog)(ctx, `[preflight ${pathTag}] PRC-20 shortfall ${shortfall} of ${burnToken}; ` +
80
+ `allowUnderfundedSwap=true — proceeding with legacy clamp behaviour, ` +
81
+ `swap is expected to revert with InsufficientBalance(0xf4d678b8) on-chain.`);
82
+ return {
83
+ ok: false,
84
+ legacyClampedValue: legacyClamp(ueaBalance, requiredValue, gasReserve),
85
+ };
86
+ }
87
+ (0, context_1.fireProgressHook)(ctx, HOOK_PRE_FAIL, burnAmount, onHand, shortfall, ueaAddress, pathTag, { kind: 'PRC20', burnToken, segmentIndex });
88
+ throw new errors_1.InsufficientUEABalanceError({
89
+ required: burnAmount,
90
+ available: onHand,
91
+ shortfall,
92
+ ueaAddress,
93
+ pathTag,
94
+ reason: 'PRC20',
95
+ burnToken,
96
+ segmentIndex,
97
+ });
98
+ }
99
+ }
100
+ // 2. Native (UPC) balance check.
101
+ const totalRequired = requiredValue + gasReserve;
102
+ const sufficient = ueaBalance >= totalRequired;
103
+ (0, context_1.fireProgressHook)(ctx, HOOK_PRE_INFO, totalRequired, ueaBalance, sufficient, ueaAddress, pathTag, { kind: 'NATIVE', segmentIndex });
104
+ if (sufficient) {
105
+ return { ok: true, adjustedValue: requiredValue };
106
+ }
107
+ const shortfall = totalRequired - ueaBalance;
108
+ if (allowUnderfundedSwap) {
109
+ const clamped = legacyClamp(ueaBalance, requiredValue, gasReserve);
110
+ (0, context_1.printLog)(ctx, `[preflight ${pathTag}] UPC shortfall ${shortfall} wei; ` +
111
+ `allowUnderfundedSwap=true — proceeding with legacy clamped value ${clamped}, ` +
112
+ `swap may revert inside Uniswap with Error("STF") if the clamp under-funds the pool quote.`);
113
+ return { ok: false, legacyClampedValue: clamped };
114
+ }
115
+ (0, context_1.fireProgressHook)(ctx, HOOK_PRE_FAIL, totalRequired, ueaBalance, shortfall, ueaAddress, pathTag, { kind: 'NATIVE', segmentIndex });
116
+ throw new errors_1.InsufficientUEABalanceError({
117
+ required: totalRequired,
118
+ available: ueaBalance,
119
+ shortfall,
120
+ ueaAddress,
121
+ pathTag,
122
+ reason: 'NATIVE',
123
+ segmentIndex,
124
+ });
125
+ }
126
+ /**
127
+ * SVM-only telemetry threshold. Buffered pool quotes above this value
128
+ * fire `SEND-TX-203-05` (R2 single-route), `SEND-TX-303-06` (R3
129
+ * single-route), or `SEND-TX-003-05` (cascade). The threshold is for
130
+ * visibility, not truncation — pre-flight handles drain protection.
131
+ * v2 may add a hard cap once telemetry justifies a number.
132
+ */
133
+ exports.SVM_NATIVE_VALUE_WARN_THRESHOLD = BigInt(5000) * BigInt(1e18);
134
+ /**
135
+ * Fire the SVM warn-threshold hook + log line if the buffered quote
136
+ * exceeds the threshold. Non-blocking; `nativeValueForGas` is not
137
+ * truncated by the caller. The hook ID switches between buckets so
138
+ * each stream stays self-consistent within its convention (R2 → 203,
139
+ * R3 → 303, cascade → 003).
140
+ */
141
+ function maybeFireSvmWarnThreshold(ctx, bufferedQuote, gasToken, pathTag) {
142
+ if (bufferedQuote <= exports.SVM_NATIVE_VALUE_WARN_THRESHOLD)
143
+ return;
144
+ const HOOK_WARN = pathTag === 'CASCADE'
145
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_05
146
+ : pathTag === 'R3_EVM' || pathTag === 'R3_SVM'
147
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_06
148
+ : progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_05;
149
+ (0, context_1.fireProgressHook)(ctx, HOOK_WARN, bufferedQuote, exports.SVM_NATIVE_VALUE_WARN_THRESHOLD, gasToken, pathTag);
150
+ (0, context_1.printLog)(ctx, `[preflight ${pathTag}] SVM warn-threshold tripped: bufferedQuote=${bufferedQuote} > ` +
151
+ `${exports.SVM_NATIVE_VALUE_WARN_THRESHOLD} for gasToken=${gasToken} — pool may be skewed`);
152
+ }
153
+ //# sourceMappingURL=preflight.js.map
@@ -10,23 +10,8 @@ import { UniversalPayload } from '../../generated/v1/tx';
10
10
  import type { TxResponse } from '../../vm-client/vm-client.types';
11
11
  import type { ExecuteParams, UniversalTxResponse } from '../orchestrator.types';
12
12
  import type { OrchestratorContext } from './context';
13
- /**
14
- * Typed error for Route 1 Push Chain tx failures. Thrown by
15
- * `extractPcTxAndTransform` when the final pcTx commits with `status === 'FAILED'`,
16
- * and surfaced as `SEND_TX_199_02` on the live stream. The readonly `code`
17
- * discriminator lets callers classify via `instanceof PushChainExecutionError`
18
- * instead of sniffing error messages.
19
- *
20
- * Carries the origin-chain gateway tx hash. There is no successful Push Chain
21
- * tx to reference on this path — by definition the pcTx committed `FAILED`.
22
- */
23
- export declare class PushChainExecutionError extends Error {
24
- readonly code: "PUSH_CHAIN_EXECUTION_FAILED";
25
- readonly gatewayTxHash?: string;
26
- constructor(message: string, opts?: {
27
- gatewayTxHash?: string;
28
- });
29
- }
13
+ import { PushChainExecutionError } from './errors';
14
+ export { PushChainExecutionError };
30
15
  type TransformToResponseFn = (tx: TxResponse, eventBuffer: ProgressEvent[]) => Promise<UniversalTxResponse>;
31
16
  /**
32
17
  * Sends an EVM transaction directly on Push Chain.
@@ -55,4 +40,3 @@ export declare function sendUniversalTx(ctx: OrchestratorContext, isUEADeployed:
55
40
  * and transforms to UniversalTxResponse.
56
41
  */
57
42
  export declare function extractPcTxAndTransform(ctx: OrchestratorContext, pushChainUniversalTx: UniversalTx | undefined, gatewayTxHash: string, eventBuffer: ProgressEvent[], label: string, transformFn: TransformToResponseFn): Promise<UniversalTxResponse>;
58
- export {};