@pushchain/core 5.1.18 → 6.0.1

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 (57) hide show
  1. package/package.json +1 -1
  2. package/src/lib/constants/abi/cea.evm.d.ts +52 -0
  3. package/src/lib/constants/abi/cea.evm.js +66 -1
  4. package/src/lib/constants/abi/prc20.evm.d.ts +117 -11
  5. package/src/lib/constants/abi/prc20.evm.js +38 -11
  6. package/src/lib/constants/abi/uea.evm.js +41 -0
  7. package/src/lib/constants/abi/universalGatewayPC.evm.d.ts +118 -2
  8. package/src/lib/constants/abi/universalGatewayPC.evm.js +41 -2
  9. package/src/lib/constants/abi/universalGatewayV0.json +1 -1
  10. package/src/lib/constants/chain.d.ts +2 -0
  11. package/src/lib/constants/chain.js +18 -14
  12. package/src/lib/constants/index.d.ts +1 -1
  13. package/src/lib/constants/tokens.d.ts +10 -1
  14. package/src/lib/constants/tokens.js +5 -2
  15. package/src/lib/formatters.d.ts +6 -0
  16. package/src/lib/formatters.js +14 -0
  17. package/src/lib/index.d.ts +2 -0
  18. package/src/lib/index.js +7 -1
  19. package/src/lib/orchestrator/internals/cascade.d.ts +3 -1
  20. package/src/lib/orchestrator/internals/cascade.js +189 -103
  21. package/src/lib/orchestrator/internals/errors.js +1 -1
  22. package/src/lib/orchestrator/internals/execute-funds-only.js +3 -2
  23. package/src/lib/orchestrator/internals/execute-funds-payload.js +2 -1
  24. package/src/lib/orchestrator/internals/execute-standard.js +4 -4
  25. package/src/lib/orchestrator/internals/gas-calculator.d.ts +1 -0
  26. package/src/lib/orchestrator/internals/gas-calculator.js +13 -11
  27. package/src/lib/orchestrator/internals/helpers.js +2 -0
  28. package/src/lib/orchestrator/internals/inbound-tracker.js +4 -2
  29. package/src/lib/orchestrator/internals/outbound-sync.js +73 -60
  30. package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +1 -1
  31. package/src/lib/orchestrator/internals/pc-usd-oracle.js +4 -3
  32. package/src/lib/orchestrator/internals/preflight.d.ts +8 -5
  33. package/src/lib/orchestrator/internals/preflight.js +35 -21
  34. package/src/lib/orchestrator/internals/push-chain-tx.js +5 -1
  35. package/src/lib/orchestrator/internals/route-handlers.js +175 -202
  36. package/src/lib/orchestrator/internals/signing.js +7 -2
  37. package/src/lib/orchestrator/internals/svm-helpers.js +3 -3
  38. package/src/lib/orchestrator/internals/svm-rent.d.ts +42 -9
  39. package/src/lib/orchestrator/internals/svm-rent.js +157 -14
  40. package/src/lib/orchestrator/internals/tx-transformer.js +5 -2
  41. package/src/lib/orchestrator/max-pc-for-gas.d.ts +60 -0
  42. package/src/lib/orchestrator/max-pc-for-gas.js +66 -0
  43. package/src/lib/orchestrator/orchestrator.d.ts +6 -6
  44. package/src/lib/orchestrator/orchestrator.js +10 -3
  45. package/src/lib/orchestrator/orchestrator.types.d.ts +48 -10
  46. package/src/lib/orchestrator/payload-builders.d.ts +7 -6
  47. package/src/lib/orchestrator/payload-builders.js +19 -7
  48. package/src/lib/progress-hook/progress-hook.js +59 -27
  49. package/src/lib/progress-hook/progress-hook.types.d.ts +3 -3
  50. package/src/lib/progress-hook/progress-hook.types.js +4 -2
  51. package/src/lib/push-chain/push-chain.d.ts +10 -4
  52. package/src/lib/push-chain/push-chain.js +2 -2
  53. package/src/lib/universal-tx-detector/events.d.ts +3 -1
  54. package/src/lib/universal-tx-detector/events.js +3 -1
  55. package/src/lib/universal-tx-detector/svm-events.d.ts +1 -1
  56. package/src/lib/universal-tx-detector/svm-events.js +1 -1
  57. package/src/lib/utils.js +1 -1
@@ -31,6 +31,14 @@ export type UniversalTo = `0x${string}` | ChainTarget;
31
31
  * Transaction route identifiers
32
32
  */
33
33
  export type TransactionRouteType = 'UOA_TO_PUSH' | 'UOA_TO_CEA' | 'CEA_TO_PUSH' | 'CEA_TO_CEA';
34
+ export interface TransactionExecutionOptions {
35
+ /**
36
+ * Enforce the SDK pre-flight gas/balance check.
37
+ * - false/omitted: emit a warning on shortfall and continue
38
+ * - true: emit the failure hook, throw InsufficientUEABalanceError, and stop
39
+ */
40
+ enforceGasCheck?: boolean;
41
+ }
34
42
  export type ExecuteParams = {
35
43
  /**
36
44
  * The target contract or account on Push Chain.
@@ -50,6 +58,12 @@ export type ExecuteParams = {
50
58
  * @reason Prevents runaway gas consumption and lets users enforce limits.
51
59
  */
52
60
  gasLimit?: bigint;
61
+ /**
62
+ * Optional cap on native PC used for outbound gas swap.
63
+ * Applies only to Push -> external-chain outbound legs. Omit or set 0n for
64
+ * uncapped legacy behavior.
65
+ */
66
+ maxPCForGas?: bigint;
53
67
  /**
54
68
  * Optional override for the EIP-1559 max fee per gas (in wei).
55
69
  * @reason Gives callers direct control over total gas price to speed up or save cost.
@@ -74,6 +88,10 @@ export type ExecuteParams = {
74
88
  * Optional for signature expiry
75
89
  */
76
90
  deadline?: bigint;
91
+ /**
92
+ * Optional transaction behavior switches.
93
+ */
94
+ options?: TransactionExecutionOptions;
77
95
  /**
78
96
  * Optional: pay gas in a specific token. If not provided, use `token` (bridge token) when present; otherwise, native token.
79
97
  */
@@ -426,25 +444,26 @@ export interface SvmExecutePayloadFields {
426
444
  * Request structure for sendUniversalTxOutbound on Push Chain
427
445
  * Used for Routes 2, 3, 4 (outbound from Push)
428
446
  *
429
- * NOTE: The `target` field is a LEGACY parameter for contract compatibility.
430
- * The deployed UniversalGatewayPC contract still expects this field, but it will
431
- * be removed in future contract upgrades. Pass any non-zero address (e.g., CEA address).
432
- * The actual destination is determined by the relay from the token's SOURCE_CHAIN_NAMESPACE.
447
+ * NOTE: The `recipient` field is raw recipient bytes for the destination chain.
448
+ * For EVM CEA funds-parking, use the zero recipient when `payload` is empty.
433
449
  */
434
450
  export interface UniversalOutboundTxRequest {
435
451
  /**
436
- * LEGACY/DUMMY: Raw destination address bytes for contract compatibility.
437
- * Pass any non-zero address - this value is NOT used by the relay to determine
438
- * the actual transaction destination. Will be removed in future contract upgrades.
452
+ * Raw destination recipient bytes. EVM routes usually pass a 20-byte address;
453
+ * SVM routes pass a 32-byte program/account address.
439
454
  */
440
- target: `0x${string}`;
455
+ recipient: `0x${string}`;
441
456
  /** PRC20 token address on Push Chain to burn */
442
457
  token: `0x${string}`;
443
458
  /** Amount to burn (0 for no-burn, use existing CEA balance) */
444
459
  amount: bigint;
445
- /** Gas limit for fee quote (0 = default BASE_GAS_LIMIT) */
460
+ /** Gas limit for fee quote (0 = per-chain default resolved by UniversalCore) */
446
461
  gasLimit: bigint;
447
- /** Raw ABI-encoded Multicall[] (no selector prefix) */
462
+ /** Gas price override for destination-chain gas (0 = UniversalCore default) */
463
+ gasPrice: bigint;
464
+ /** Max native PC that may be used for gas swap (0 = uncapped legacy behavior) */
465
+ maxPCForGas: bigint;
466
+ /** Destination execution payload; empty only for explicit funds parking */
448
467
  payload: `0x${string}`;
449
468
  /** Address to receive funds on revert */
450
469
  revertRecipient: `0x${string}`;
@@ -488,8 +507,12 @@ export interface HopDescriptor {
488
507
  gasToken?: `0x${string}`;
489
508
  /** Gas fee amount in gas token */
490
509
  gasFee?: bigint;
510
+ /** Destination-chain gas price quoted by UniversalCore */
511
+ gasPrice?: bigint;
491
512
  /** Gas limit for outbound relay */
492
513
  gasLimit: bigint;
514
+ /** Max native PC used for outbound gas swap (0 = uncapped) */
515
+ maxPCForGas: bigint;
493
516
  /** UEA address */
494
517
  ueaAddress: `0x${string}`;
495
518
  /** Address to receive funds on revert */
@@ -538,8 +561,12 @@ export interface CascadeSegment {
538
561
  gasToken?: `0x${string}`;
539
562
  /** Total gas fee for this segment */
540
563
  gasFee?: bigint;
564
+ /** Destination-chain gas price quoted by UniversalCore */
565
+ gasPrice?: bigint;
541
566
  /** Gas limit for this segment */
542
567
  gasLimit?: bigint;
568
+ /** Max native PC used for outbound gas swap (0 = uncapped) */
569
+ maxPCForGas?: bigint;
543
570
  /**
544
571
  * SDK 5.2 gas-abstraction sizing decision for this segment. When the
545
572
  * segment merges multiple hops, the strictest (highest category) sizing
@@ -647,6 +674,10 @@ export interface CascadeTrackOptions {
647
674
  */
648
675
  eventHook?: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void;
649
676
  }
677
+ export interface CascadeExecutionOptions {
678
+ /** Per-call progress callback. */
679
+ progressHook?: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void;
680
+ }
650
681
  /**
651
682
  * Progress event emitted during cascade tracking
652
683
  */
@@ -756,6 +787,13 @@ export interface WaitForOutboundOptions {
756
787
  * has multiple outbound operations to different chains.
757
788
  */
758
789
  _expectedDestinationChain?: string;
790
+ /**
791
+ * @internal Zero-based index among outbound entries that match
792
+ * `_expectedDestinationChain`. Used when a composed cascade emits multiple
793
+ * outbound operations to the same chain and a later hop must track the later
794
+ * observed tx rather than the first one.
795
+ */
796
+ _outboundIndex?: number;
759
797
  }
760
798
  /**
761
799
  * UEA deployment and version status.
@@ -70,18 +70,19 @@ export declare function buildSendUniversalTxToUEA(ceaAddress: `0x${string}`, tok
70
70
  /**
71
71
  * Build UniversalOutboundTxRequest for Push Chain outbound
72
72
  *
73
- * @param target - LEGACY/DUMMY: Any non-zero address for contract compatibility.
74
- * This value is NOT used by the relay to determine the actual destination.
75
- * The relay determines the destination from the PRC-20 token's SOURCE_CHAIN_NAMESPACE.
76
- * Will be removed in future contract upgrades.
73
+ * @param recipient - Raw recipient bytes for the destination chain. For EVM CEA
74
+ * funds-parking, use the zero recipient when payload is empty.
77
75
  * @param prc20Token - PRC20 token address to burn (or address(0) for native)
78
76
  * @param amount - Amount to burn
79
77
  * @param gasLimit - Gas limit for fee calculation
80
- * @param payload - CEA multicall payload
78
+ * @param payload - Destination execution payload
81
79
  * @param revertRecipient - Address to receive funds on revert
80
+ * @param maxPCForGas - Max native PC used for gas swap (0 = uncapped)
81
+ * @param gasPrice - Destination-chain gas price override (0 = UniversalCore default)
82
82
  * @returns UniversalOutboundTxRequest object
83
83
  */
84
- export declare function buildOutboundRequest(target: `0x${string}`, prc20Token: `0x${string}`, amount: bigint, gasLimit: bigint, payload: `0x${string}`, revertRecipient: `0x${string}`): UniversalOutboundTxRequest;
84
+ export declare function buildOutboundRequest(recipient: `0x${string}`, prc20Token: `0x${string}`, amount: bigint, gasLimit: bigint, payload: `0x${string}`, revertRecipient: `0x${string}`, maxPCForGas?: bigint, gasPrice?: bigint): UniversalOutboundTxRequest;
85
+ export declare function assertCeaFundsParkingInvariant(recipient: `0x${string}`, payload: `0x${string}`): void;
85
86
  /**
86
87
  * Build ERC20 transfer multicall
87
88
  *
@@ -6,6 +6,7 @@ exports.buildCeaMulticallPayload = buildCeaMulticallPayload;
6
6
  exports.buildInboundUniversalPayload = buildInboundUniversalPayload;
7
7
  exports.buildSendUniversalTxToUEA = buildSendUniversalTxToUEA;
8
8
  exports.buildOutboundRequest = buildOutboundRequest;
9
+ exports.assertCeaFundsParkingInvariant = assertCeaFundsParkingInvariant;
9
10
  exports.buildErc20Transfer = buildErc20Transfer;
10
11
  exports.buildErc20WithdrawalMulticall = buildErc20WithdrawalMulticall;
11
12
  exports.buildMigrationPayload = buildMigrationPayload;
@@ -225,27 +226,38 @@ function buildSendUniversalTxToUEA(ceaAddress, token, amount, payload, revertRec
225
226
  /**
226
227
  * Build UniversalOutboundTxRequest for Push Chain outbound
227
228
  *
228
- * @param target - LEGACY/DUMMY: Any non-zero address for contract compatibility.
229
- * This value is NOT used by the relay to determine the actual destination.
230
- * The relay determines the destination from the PRC-20 token's SOURCE_CHAIN_NAMESPACE.
231
- * Will be removed in future contract upgrades.
229
+ * @param recipient - Raw recipient bytes for the destination chain. For EVM CEA
230
+ * funds-parking, use the zero recipient when payload is empty.
232
231
  * @param prc20Token - PRC20 token address to burn (or address(0) for native)
233
232
  * @param amount - Amount to burn
234
233
  * @param gasLimit - Gas limit for fee calculation
235
- * @param payload - CEA multicall payload
234
+ * @param payload - Destination execution payload
236
235
  * @param revertRecipient - Address to receive funds on revert
236
+ * @param maxPCForGas - Max native PC used for gas swap (0 = uncapped)
237
+ * @param gasPrice - Destination-chain gas price override (0 = UniversalCore default)
237
238
  * @returns UniversalOutboundTxRequest object
238
239
  */
239
- function buildOutboundRequest(target, prc20Token, amount, gasLimit, payload, revertRecipient) {
240
+ function buildOutboundRequest(recipient, prc20Token, amount, gasLimit, payload, revertRecipient, maxPCForGas = BigInt(0), gasPrice = BigInt(0)) {
240
241
  return {
241
- target,
242
+ recipient,
242
243
  token: prc20Token,
243
244
  amount,
244
245
  gasLimit,
246
+ gasPrice,
247
+ maxPCForGas,
245
248
  payload,
246
249
  revertRecipient,
247
250
  };
248
251
  }
252
+ function assertCeaFundsParkingInvariant(recipient, payload) {
253
+ if (payload !== '0x')
254
+ return;
255
+ if (recipient === '0x')
256
+ return;
257
+ if (recipient.toLowerCase() === selectors_1.ZERO_ADDRESS.toLowerCase())
258
+ return;
259
+ throw new Error('Empty CEA payloads must use the zero recipient to park funds');
260
+ }
249
261
  /**
250
262
  * Build ERC20 transfer multicall
251
263
  *
@@ -23,6 +23,18 @@ const friendlyChain = (chainOrNs) => {
23
23
  const key = utils_1.Utils.chains.getChainName(asString);
24
24
  return key ? toTitleCase(key) : asString;
25
25
  };
26
+ function preflightLevel(sufficient, enforceGasCheck) {
27
+ if (sufficient)
28
+ return 'INFO';
29
+ return enforceGasCheck === false ? 'WARNING' : 'ERROR';
30
+ }
31
+ function preflightSuffix(sufficient, pathTag, enforceGasCheck) {
32
+ if (sufficient)
33
+ return `sufficient (${pathTag})`;
34
+ return enforceGasCheck === false
35
+ ? `INSUFFICIENT (${pathTag}); warning only, proceeding`
36
+ : `INSUFFICIENT (${pathTag})`;
37
+ }
26
38
  /**
27
39
  * Classify a sign-time error as either a true wallet user-decline
28
40
  * (viem `UserRejectedRequestError`, ethers `ACTION_REJECTED`, EIP-1193 4001,
@@ -251,13 +263,16 @@ const RAW_HOOKS_R1 = {
251
263
  level: 'SUCCESS',
252
264
  };
253
265
  },
254
- [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02]: (errMessage, decodedError) => ({
255
- id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02,
256
- title: 'Push Chain Tx Failed',
257
- message: errMessage,
258
- response: Object.assign({ error: errMessage }, (decodedError ? { decodedError } : {})),
259
- level: 'ERROR',
260
- }),
266
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02]: (errMessage, decodedError) => {
267
+ const normalizedErrMessage = (0, formatters_1.normalizePcInsufficientFundsError)(errMessage);
268
+ return {
269
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02,
270
+ title: 'Push Chain Tx Failed',
271
+ message: normalizedErrMessage,
272
+ response: Object.assign({ error: normalizedErrMessage }, (decodedError ? { decodedError } : {})),
273
+ level: 'ERROR',
274
+ };
275
+ },
261
276
  };
262
277
  // =============================================================================
263
278
  // Route 2 — UEA → UGPC → CEA on target chain (201–299, signature-only)
@@ -304,15 +319,16 @@ const RAW_HOOKS_R2 = {
304
319
  level: 'SUCCESS',
305
320
  }),
306
321
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
307
- var _a, _b, _c;
322
+ var _a, _b, _c, _d;
308
323
  const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
309
324
  const availableStr = kind === 'PRC20' ? `${available} units` : (0, formatters_1.formatPc)(available, 4);
310
325
  const requiredStr = kind === 'PRC20' ? `${required} units` : (0, formatters_1.formatPc)(required, 4);
326
+ const enforceGasCheck = extra === null || extra === void 0 ? void 0 : extra.enforceGasCheck;
311
327
  return {
312
328
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03,
313
329
  title: 'Pre-flight Balance Check',
314
330
  message: `UEA balance: ${availableStr}; required: ${requiredStr}; ` +
315
- `${sufficient ? 'sufficient' : 'INSUFFICIENT'} (${pathTag})`,
331
+ preflightSuffix(sufficient, pathTag, enforceGasCheck),
316
332
  response: {
317
333
  required,
318
334
  available,
@@ -322,8 +338,11 @@ const RAW_HOOKS_R2 = {
322
338
  kind,
323
339
  burnToken: (_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : null,
324
340
  segmentIndex: (_c = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _c !== void 0 ? _c : null,
341
+ enforceGasCheck: enforceGasCheck !== null && enforceGasCheck !== void 0 ? enforceGasCheck : null,
342
+ warningOnly: !sufficient && enforceGasCheck === false,
343
+ shortfall: (_d = extra === null || extra === void 0 ? void 0 : extra.shortfall) !== null && _d !== void 0 ? _d : null,
325
344
  },
326
- level: sufficient ? 'INFO' : 'ERROR',
345
+ level: preflightLevel(sufficient, enforceGasCheck),
327
346
  };
328
347
  },
329
348
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
@@ -518,15 +537,16 @@ const RAW_HOOKS_R3 = {
518
537
  }),
519
538
  // R3 single-route pre-flight balance check. Same payload shape as 203-03/04/05.
520
539
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_04]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
521
- var _a, _b, _c;
540
+ var _a, _b, _c, _d;
522
541
  const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
523
542
  const availableStr = kind === 'PRC20' ? `${available} units` : (0, formatters_1.formatPc)(available, 4);
524
543
  const requiredStr = kind === 'PRC20' ? `${required} units` : (0, formatters_1.formatPc)(required, 4);
544
+ const enforceGasCheck = extra === null || extra === void 0 ? void 0 : extra.enforceGasCheck;
525
545
  return {
526
546
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_04,
527
547
  title: 'Pre-flight Balance Check',
528
548
  message: `UEA balance: ${availableStr}; required: ${requiredStr}; ` +
529
- `${sufficient ? 'sufficient' : 'INSUFFICIENT'} (${pathTag})`,
549
+ preflightSuffix(sufficient, pathTag, enforceGasCheck),
530
550
  response: {
531
551
  required,
532
552
  available,
@@ -536,8 +556,11 @@ const RAW_HOOKS_R3 = {
536
556
  kind,
537
557
  burnToken: (_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : null,
538
558
  segmentIndex: (_c = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _c !== void 0 ? _c : null,
559
+ enforceGasCheck: enforceGasCheck !== null && enforceGasCheck !== void 0 ? enforceGasCheck : null,
560
+ warningOnly: !sufficient && enforceGasCheck === false,
561
+ shortfall: (_d = extra === null || extra === void 0 ? void 0 : extra.shortfall) !== null && _d !== void 0 ? _d : null,
539
562
  },
540
- level: sufficient ? 'INFO' : 'ERROR',
563
+ level: preflightLevel(sufficient, enforceGasCheck),
541
564
  };
542
565
  },
543
566
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_05]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
@@ -664,17 +687,22 @@ const RAW_HOOKS_R3 = {
664
687
  // Phase is passed by the emission site so the title matches the leg that
665
688
  // actually failed. Default stays 'inbound' for callers that don't specify
666
689
  // (backwards-compat with fixtures + response-builder's inbound block).
667
- [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02]: (errorMessage, phase = 'inbound', chain, decodedError) => ({
668
- id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02,
669
- title: phase === 'outbound'
670
- ? `${friendlyChain(chain)} Tx Failed`
671
- : phase === 'push'
672
- ? 'Push Chain Tx Failed'
673
- : 'Push Chain Inbound Tx Failed',
674
- message: errorMessage,
675
- response: Object.assign({ error: errorMessage, phase, chain: chain !== null && chain !== void 0 ? chain : null }, (decodedError ? { decodedError } : {})),
676
- level: 'ERROR',
677
- }),
690
+ [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02]: (errorMessage, phase = 'inbound', chain, decodedError) => {
691
+ const normalizedErrorMessage = phase === 'push'
692
+ ? (0, formatters_1.normalizePcInsufficientFundsError)(errorMessage)
693
+ : errorMessage;
694
+ return {
695
+ id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02,
696
+ title: phase === 'outbound'
697
+ ? `${friendlyChain(chain)} Tx Failed`
698
+ : phase === 'push'
699
+ ? 'Push Chain Tx Failed'
700
+ : 'Push Chain Inbound Tx Failed',
701
+ message: normalizedErrorMessage,
702
+ response: Object.assign({ error: normalizedErrorMessage, phase, chain: chain !== null && chain !== void 0 ? chain : null }, (decodedError ? { decodedError } : {})),
703
+ level: 'ERROR',
704
+ };
705
+ },
678
706
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03]: (sourceChain, elapsedMs, phase = 'inbound') => ({
679
707
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03,
680
708
  title: phase === 'outbound'
@@ -777,15 +805,16 @@ const RAW_HOOKS_MULTICHAIN = {
777
805
  // streams remain self-consistent. `runPreflight` switches between
778
806
  // 203-xx and 003-xx based on pathTag === 'CASCADE'.
779
807
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
780
- var _a, _b, _c;
808
+ var _a, _b, _c, _d;
781
809
  const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
782
810
  const availableStr = kind === 'PRC20' ? `${available} units` : (0, formatters_1.formatPc)(available, 4);
783
811
  const requiredStr = kind === 'PRC20' ? `${required} units` : (0, formatters_1.formatPc)(required, 4);
812
+ const enforceGasCheck = extra === null || extra === void 0 ? void 0 : extra.enforceGasCheck;
784
813
  return {
785
814
  id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03,
786
815
  title: 'Cascade Pre-flight Balance Check',
787
816
  message: `UEA balance: ${availableStr}; required: ${requiredStr}; ` +
788
- `${sufficient ? 'sufficient' : 'INSUFFICIENT'} (${pathTag})`,
817
+ preflightSuffix(sufficient, pathTag, enforceGasCheck),
789
818
  response: {
790
819
  required,
791
820
  available,
@@ -795,8 +824,11 @@ const RAW_HOOKS_MULTICHAIN = {
795
824
  kind,
796
825
  burnToken: (_b = extra === null || extra === void 0 ? void 0 : extra.burnToken) !== null && _b !== void 0 ? _b : null,
797
826
  segmentIndex: (_c = extra === null || extra === void 0 ? void 0 : extra.segmentIndex) !== null && _c !== void 0 ? _c : null,
827
+ enforceGasCheck: enforceGasCheck !== null && enforceGasCheck !== void 0 ? enforceGasCheck : null,
828
+ warningOnly: !sufficient && enforceGasCheck === false,
829
+ shortfall: (_d = extra === null || extra === void 0 ? void 0 : extra.shortfall) !== null && _d !== void 0 ? _d : null,
798
830
  },
799
- level: sufficient ? 'INFO' : 'ERROR',
831
+ level: preflightLevel(sufficient, enforceGasCheck),
800
832
  };
801
833
  },
802
834
  [progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
@@ -7,7 +7,7 @@ export type ProgressEvent = {
7
7
  id: string;
8
8
  title: string;
9
9
  message: string;
10
- level: 'INFO' | 'SUCCESS' | 'ERROR';
10
+ level: 'INFO' | 'SUCCESS' | 'WARNING' | 'ERROR';
11
11
  response: object | null;
12
12
  timestamp: string;
13
13
  };
@@ -68,7 +68,7 @@ export declare enum PROGRESS_HOOK {
68
68
  SEND_TX_303_03_01 = "SEND-TX-303-03-01",// Sizer: Case A (< $1, padded)
69
69
  SEND_TX_303_03_02 = "SEND-TX-303-03-02",// Sizer: Case B ($1–$10, happy path)
70
70
  SEND_TX_303_03_03 = "SEND-TX-303-03-03",// Sizer: Case C (> $10, split + overflow bridge)
71
- SEND_TX_303_04 = "SEND-TX-303-04",// R3 pre-flight balance check (INFO when sufficient, ERROR when insufficient)
71
+ SEND_TX_303_04 = "SEND-TX-303-04",// R3 pre-flight balance check (INFO/WARNING/ERROR per enforceGasCheck)
72
72
  SEND_TX_303_05 = "SEND-TX-303-05",// R3 pre-flight FAILED (ERROR, terminal precursor before 399-02)
73
73
  SEND_TX_303_06 = "SEND-TX-303-06",// R3 SVM warn-threshold tripped (INFO, no action)
74
74
  SEND_TX_304_01 = "SEND-TX-304-01",
@@ -87,7 +87,7 @@ export declare enum PROGRESS_HOOK {
87
87
  SEND_TX_001 = "SEND-TX-001",
88
88
  SEND_TX_002_01 = "SEND-TX-002-01",
89
89
  SEND_TX_002_99_99 = "SEND-TX-002-99-99",
90
- SEND_TX_003_03 = "SEND-TX-003-03",// Cascade pre-flight balance check (INFO when sufficient, ERROR when insufficient)
90
+ SEND_TX_003_03 = "SEND-TX-003-03",// Cascade pre-flight balance check (INFO/WARNING/ERROR per enforceGasCheck)
91
91
  SEND_TX_003_04 = "SEND-TX-003-04",// Cascade pre-flight FAILED (ERROR, terminal precursor before 999-02)
92
92
  SEND_TX_003_05 = "SEND-TX-003-05",// Cascade SVM warn-threshold tripped (INFO, no action)
93
93
  SEND_TX_999_01 = "SEND-TX-999-01",
@@ -37,8 +37,10 @@ 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).
40
+ // Pre-flight balance check (203-03 INFO when sufficient, WARNING when
41
+ // short but enforceGasCheck=false, ERROR when enforceGasCheck=true;
42
+ // 203-04 ERROR terminal precursor on enforced shortfall;
43
+ // 203-05 INFO SVM warn-threshold tripped).
42
44
  // 203 bucket choice is temporal (sits between 203-02 CEA-resolved and 204-01 sign),
43
45
  // not strictly semantic — UEA balance is on Push Chain, not the destination CEA.
44
46
  PROGRESS_HOOK["SEND_TX_203_03"] = "SEND-TX-203-03";
@@ -6,7 +6,7 @@ import { TypedData, TypedDataDomain } from 'viem';
6
6
  import { ProgressEvent } from '../progress-hook/progress-hook.types';
7
7
  import type { AccountStatus } from '../orchestrator/orchestrator.types';
8
8
  import { MoveableToken, PayableToken, ConversionQuote, MoveableTokenAccessor, PayableTokenAccessor } from '../constants/tokens';
9
- import type { PreparedUniversalTx, CascadedTxResponse } from '../orchestrator/orchestrator.types';
9
+ import type { PreparedUniversalTx, CascadedTxResponse, CascadeExecutionOptions } from '../orchestrator/orchestrator.types';
10
10
  /**
11
11
  * @class PushChain
12
12
  *
@@ -67,11 +67,19 @@ export declare class PushChain {
67
67
  * to: { address: '0x...', chain: CHAIN.BNB_TESTNET },
68
68
  * value: parseEther('0.001')
69
69
  * });
70
+ *
71
+ * @param options.enforceGasCheck - Defaults to false. When true, the
72
+ * SDK stops on pre-flight gas/balance shortfall instead of warning
73
+ * and proceeding.
70
74
  */
71
75
  sendTransaction: Orchestrator['execute'];
72
76
  /**
73
77
  * Prepare a universal transaction without executing it.
74
78
  * Returns a PreparedUniversalTx that can be passed to executeTransactions.
79
+ *
80
+ * @param options.enforceGasCheck - Defaults to false. When true, the
81
+ * prepared transaction carries strict pre-flight gas/balance enforcement
82
+ * into executeTransactions.
75
83
  */
76
84
  prepareTransaction: Orchestrator['prepareTransaction'];
77
85
  /**
@@ -86,9 +94,7 @@ export declare class PushChain {
86
94
  * if it matches the init-time hook. Note: concurrent calls on the
87
95
  * same instance share the hook channel during the broadcast phase.
88
96
  */
89
- executeTransactions: (txs: PreparedUniversalTx[], options?: {
90
- progressHook?: (event: ProgressEvent) => void;
91
- }) => Promise<CascadedTxResponse>;
97
+ executeTransactions: (txs: PreparedUniversalTx[], options?: CascadeExecutionOptions) => Promise<CascadedTxResponse>;
92
98
  /**
93
99
  * Tracks a transaction by hash on Push Chain
94
100
  */
@@ -81,8 +81,8 @@ class PushChain {
81
81
  }
82
82
  return orchestrator.execute.bind(orchestrator)(...args);
83
83
  },
84
- prepareTransaction: (params) => {
85
- return orchestrator.prepareTransaction.bind(orchestrator)(params);
84
+ prepareTransaction: (params, options) => {
85
+ return orchestrator.prepareTransaction.bind(orchestrator)(params, options);
86
86
  },
87
87
  executeTransactions: (txs, options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
88
88
  if (this.isReadMode) {
@@ -2,8 +2,10 @@
2
2
  * Event ABI fragments used by the universal-tx detector.
3
3
  *
4
4
  * Sourced from push-chain-gateway-contracts and push-chain-core-contracts:
5
- * - UniversalTx, UniversalTxExecuted, RevertUniversalTx, FundsRescued
5
+ * - UniversalTx, RevertUniversalTx, FundsRescued
6
6
  * → contracts/evm-gateway/src/interfaces/IUniversalGateway.sol
7
+ * - UniversalTxExecuted
8
+ * → push-chain-core-contracts/src/Interfaces/ICEA.sol
7
9
  * - UniversalTxFinalized, UniversalTxReverted, FundsRescued (vault)
8
10
  * → contracts/evm-gateway/src/interfaces/IVault.sol
9
11
  * - UniversalTxOutbound
@@ -3,8 +3,10 @@
3
3
  * Event ABI fragments used by the universal-tx detector.
4
4
  *
5
5
  * Sourced from push-chain-gateway-contracts and push-chain-core-contracts:
6
- * - UniversalTx, UniversalTxExecuted, RevertUniversalTx, FundsRescued
6
+ * - UniversalTx, RevertUniversalTx, FundsRescued
7
7
  * → contracts/evm-gateway/src/interfaces/IUniversalGateway.sol
8
+ * - UniversalTxExecuted
9
+ * → push-chain-core-contracts/src/Interfaces/ICEA.sol
8
10
  * - UniversalTxFinalized, UniversalTxReverted, FundsRescued (vault)
9
11
  * → contracts/evm-gateway/src/interfaces/IVault.sol
10
12
  * - UniversalTxOutbound
@@ -10,7 +10,7 @@
10
10
  /**
11
11
  * Mapping: 8-byte discriminator (lowercase hex, no 0x) → Anchor event name.
12
12
  * Only events with EVM classifier parity are listed; the keeper-agnostic
13
- * ones (BlockUsdCapUpdated, ProtocolFeeCollected, etc.) are intentionally
13
+ * ones (BlockUsdCapUpdated, inbound-fee events, etc.) are intentionally
14
14
  * skipped — they wouldn't classify to any UniversalTxKind anyway.
15
15
  */
16
16
  export declare const SVM_EVENT_DISCRIMINATORS: Record<string, string>;
@@ -15,7 +15,7 @@ const toHex = (bytes) => bytes.map((b) => b.toString(16).padStart(2, '0')).join(
15
15
  /**
16
16
  * Mapping: 8-byte discriminator (lowercase hex, no 0x) → Anchor event name.
17
17
  * Only events with EVM classifier parity are listed; the keeper-agnostic
18
- * ones (BlockUsdCapUpdated, ProtocolFeeCollected, etc.) are intentionally
18
+ * ones (BlockUsdCapUpdated, inbound-fee events, etc.) are intentionally
19
19
  * skipped — they wouldn't classify to any UniversalTxKind anyway.
20
20
  */
21
21
  exports.SVM_EVENT_DISCRIMINATORS = {
package/src/lib/utils.js CHANGED
@@ -711,7 +711,7 @@ Utils.tokens = {
711
711
  else if (isBaseFamily)
712
712
  key = 'USDC_BASE';
713
713
  else if (isBnbFamily)
714
- key = 'USDC_BNB';
714
+ key = 'USDC_BSC';
715
715
  else if (isSolFamily)
716
716
  key = 'USDC_SOL';
717
717
  else