@pushchain/core 5.1.17 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/constants/abi/cea.evm.d.ts +52 -0
- package/src/lib/constants/abi/cea.evm.js +66 -1
- package/src/lib/constants/abi/prc20.evm.d.ts +117 -11
- package/src/lib/constants/abi/prc20.evm.js +38 -11
- package/src/lib/constants/abi/uea.evm.js +41 -0
- package/src/lib/constants/abi/universalGatewayPC.evm.d.ts +117 -1
- package/src/lib/constants/abi/universalGatewayPC.evm.js +40 -1
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +14 -14
- package/src/lib/constants/index.d.ts +1 -1
- package/src/lib/constants/index.js +2 -1
- package/src/lib/constants/selectors.d.ts +8 -0
- package/src/lib/constants/selectors.js +9 -1
- package/src/lib/constants/tokens.js +1 -0
- package/src/lib/formatters.d.ts +7 -0
- package/src/lib/formatters.js +46 -0
- package/src/lib/index.d.ts +2 -0
- package/src/lib/index.js +7 -1
- package/src/lib/orchestrator/internals/cascade.d.ts +8 -1
- package/src/lib/orchestrator/internals/cascade.js +593 -192
- package/src/lib/orchestrator/internals/error-decoder.d.ts +2 -6
- package/src/lib/orchestrator/internals/error-decoder.js +10 -10
- package/src/lib/orchestrator/internals/errors.d.ts +1 -1
- package/src/lib/orchestrator/internals/errors.js +8 -5
- package/src/lib/orchestrator/internals/execute-funds-only.js +3 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +2 -1
- package/src/lib/orchestrator/internals/execute-standard.js +11 -10
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +1 -0
- package/src/lib/orchestrator/internals/gas-calculator.js +91 -22
- package/src/lib/orchestrator/internals/helpers.d.ts +2 -1
- package/src/lib/orchestrator/internals/helpers.js +14 -11
- package/src/lib/orchestrator/internals/inbound-tracker.js +4 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +1 -0
- package/src/lib/orchestrator/internals/outbound-sync.js +140 -71
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +1 -1
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +4 -3
- package/src/lib/orchestrator/internals/preflight.d.ts +2 -16
- package/src/lib/orchestrator/internals/preflight.js +2 -36
- package/src/lib/orchestrator/internals/push-chain-tx.js +5 -1
- package/src/lib/orchestrator/internals/response-builder.js +23 -7
- package/src/lib/orchestrator/internals/route-handlers.js +182 -227
- package/src/lib/orchestrator/internals/signing.js +7 -2
- package/src/lib/orchestrator/internals/svm-helpers.js +3 -3
- package/src/lib/orchestrator/internals/svm-rent.d.ts +42 -9
- package/src/lib/orchestrator/internals/svm-rent.js +148 -14
- package/src/lib/orchestrator/internals/tx-transformer.js +5 -2
- package/src/lib/orchestrator/max-pc-for-gas.d.ts +60 -0
- package/src/lib/orchestrator/max-pc-for-gas.js +66 -0
- package/src/lib/orchestrator/orchestrator.d.ts +8 -1
- package/src/lib/orchestrator/orchestrator.js +40 -2
- package/src/lib/orchestrator/orchestrator.types.d.ts +35 -23
- package/src/lib/orchestrator/payload-builders.d.ts +7 -6
- package/src/lib/orchestrator/payload-builders.js +18 -6
- package/src/lib/progress-hook/progress-hook.js +39 -38
- package/src/lib/push-chain/push-chain.d.ts +11 -1
- package/src/lib/push-chain/push-chain.js +2 -2
- package/src/lib/universal-tx-detector/cascade.js +14 -4
- package/src/lib/universal-tx-detector/child-inbounds.js +9 -1
- package/src/lib/universal-tx-detector/detector.js +9 -3
- package/src/lib/universal-tx-detector/events.d.ts +3 -1
- package/src/lib/universal-tx-detector/events.js +3 -1
- package/src/lib/universal-tx-detector/normalize.d.ts +42 -0
- package/src/lib/universal-tx-detector/normalize.js +127 -0
- package/src/lib/universal-tx-detector/svm-events.d.ts +1 -1
- package/src/lib/universal-tx-detector/svm-events.js +1 -1
- package/src/lib/utils/external-tx-hash.d.ts +37 -0
- package/src/lib/utils/external-tx-hash.js +62 -0
|
@@ -50,6 +50,12 @@ export type ExecuteParams = {
|
|
|
50
50
|
* @reason Prevents runaway gas consumption and lets users enforce limits.
|
|
51
51
|
*/
|
|
52
52
|
gasLimit?: bigint;
|
|
53
|
+
/**
|
|
54
|
+
* Optional cap on native PC used for outbound gas swap.
|
|
55
|
+
* Applies only to Push -> external-chain outbound legs. Omit or set 0n for
|
|
56
|
+
* uncapped legacy behavior.
|
|
57
|
+
*/
|
|
58
|
+
maxPCForGas?: bigint;
|
|
53
59
|
/**
|
|
54
60
|
* Optional override for the EIP-1559 max fee per gas (in wei).
|
|
55
61
|
* @reason Gives callers direct control over total gas price to speed up or save cost.
|
|
@@ -397,20 +403,6 @@ export type UniversalExecuteParams = Omit<ExecuteParams, 'to'> & {
|
|
|
397
403
|
* Only applicable for Route 2 (UOA_TO_CEA) on EVM chains.
|
|
398
404
|
*/
|
|
399
405
|
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
|
-
};
|
|
414
406
|
};
|
|
415
407
|
/**
|
|
416
408
|
* Account metadata for SVM CPI execution (Solana Gateway pattern).
|
|
@@ -440,25 +432,26 @@ export interface SvmExecutePayloadFields {
|
|
|
440
432
|
* Request structure for sendUniversalTxOutbound on Push Chain
|
|
441
433
|
* Used for Routes 2, 3, 4 (outbound from Push)
|
|
442
434
|
*
|
|
443
|
-
* NOTE: The `target` field is
|
|
444
|
-
*
|
|
445
|
-
* be removed in future contract upgrades. Pass any non-zero address (e.g., CEA address).
|
|
446
|
-
* The actual destination is determined by the relay from the token's SOURCE_CHAIN_NAMESPACE.
|
|
435
|
+
* NOTE: The `target` field is raw recipient bytes for the destination chain.
|
|
436
|
+
* For EVM CEA funds-parking, use the zero recipient when `payload` is empty.
|
|
447
437
|
*/
|
|
448
438
|
export interface UniversalOutboundTxRequest {
|
|
449
439
|
/**
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
* the actual transaction destination. Will be removed in future contract upgrades.
|
|
440
|
+
* Raw destination recipient bytes. EVM routes usually pass a 20-byte address;
|
|
441
|
+
* SVM routes pass a 32-byte program/account address.
|
|
453
442
|
*/
|
|
454
443
|
target: `0x${string}`;
|
|
455
444
|
/** PRC20 token address on Push Chain to burn */
|
|
456
445
|
token: `0x${string}`;
|
|
457
446
|
/** Amount to burn (0 for no-burn, use existing CEA balance) */
|
|
458
447
|
amount: bigint;
|
|
459
|
-
/** Gas limit for fee quote (0 = default
|
|
448
|
+
/** Gas limit for fee quote (0 = per-chain default resolved by UniversalCore) */
|
|
460
449
|
gasLimit: bigint;
|
|
461
|
-
/**
|
|
450
|
+
/** Gas price override for destination-chain gas (0 = UniversalCore default) */
|
|
451
|
+
gasPrice: bigint;
|
|
452
|
+
/** Max native PC that may be used for gas swap (0 = uncapped legacy behavior) */
|
|
453
|
+
maxPCForGas: bigint;
|
|
454
|
+
/** Destination execution payload; empty only for explicit funds parking */
|
|
462
455
|
payload: `0x${string}`;
|
|
463
456
|
/** Address to receive funds on revert */
|
|
464
457
|
revertRecipient: `0x${string}`;
|
|
@@ -502,8 +495,12 @@ export interface HopDescriptor {
|
|
|
502
495
|
gasToken?: `0x${string}`;
|
|
503
496
|
/** Gas fee amount in gas token */
|
|
504
497
|
gasFee?: bigint;
|
|
498
|
+
/** Destination-chain gas price quoted by UniversalCore */
|
|
499
|
+
gasPrice?: bigint;
|
|
505
500
|
/** Gas limit for outbound relay */
|
|
506
501
|
gasLimit: bigint;
|
|
502
|
+
/** Max native PC used for outbound gas swap (0 = uncapped) */
|
|
503
|
+
maxPCForGas: bigint;
|
|
507
504
|
/** UEA address */
|
|
508
505
|
ueaAddress: `0x${string}`;
|
|
509
506
|
/** Address to receive funds on revert */
|
|
@@ -514,6 +511,10 @@ export interface HopDescriptor {
|
|
|
514
511
|
svmPayload?: `0x${string}`;
|
|
515
512
|
/** Whether this hop is a CEA migration (raw MIGRATION_SELECTOR payload) */
|
|
516
513
|
isMigration?: boolean;
|
|
514
|
+
/** Whether this Route 3 hop only seeds native PC into the UEA. @internal */
|
|
515
|
+
nativeSeedOnly?: boolean;
|
|
516
|
+
/** Native PC amount seeded by a value-only Route 3 hop. @internal */
|
|
517
|
+
nativeSeedAmount?: bigint;
|
|
517
518
|
/** SDK 5.2 gas-abstraction sizing decision for this hop. @internal */
|
|
518
519
|
sizing?: import('./internals/gas-usd-sizer').GasSizingDecision;
|
|
519
520
|
}
|
|
@@ -548,8 +549,12 @@ export interface CascadeSegment {
|
|
|
548
549
|
gasToken?: `0x${string}`;
|
|
549
550
|
/** Total gas fee for this segment */
|
|
550
551
|
gasFee?: bigint;
|
|
552
|
+
/** Destination-chain gas price quoted by UniversalCore */
|
|
553
|
+
gasPrice?: bigint;
|
|
551
554
|
/** Gas limit for this segment */
|
|
552
555
|
gasLimit?: bigint;
|
|
556
|
+
/** Max native PC used for outbound gas swap (0 = uncapped) */
|
|
557
|
+
maxPCForGas?: bigint;
|
|
553
558
|
/**
|
|
554
559
|
* SDK 5.2 gas-abstraction sizing decision for this segment. When the
|
|
555
560
|
* segment merges multiple hops, the strictest (highest category) sizing
|
|
@@ -766,6 +771,13 @@ export interface WaitForOutboundOptions {
|
|
|
766
771
|
* has multiple outbound operations to different chains.
|
|
767
772
|
*/
|
|
768
773
|
_expectedDestinationChain?: string;
|
|
774
|
+
/**
|
|
775
|
+
* @internal Zero-based index among outbound entries that match
|
|
776
|
+
* `_expectedDestinationChain`. Used when a composed cascade emits multiple
|
|
777
|
+
* outbound operations to the same chain and a later hop must track the later
|
|
778
|
+
* observed tx rather than the first one.
|
|
779
|
+
*/
|
|
780
|
+
_outboundIndex?: number;
|
|
769
781
|
}
|
|
770
782
|
/**
|
|
771
783
|
* 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 -
|
|
74
|
-
*
|
|
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 target - 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 -
|
|
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}
|
|
84
|
+
export declare function buildOutboundRequest(target: `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 -
|
|
229
|
-
*
|
|
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 target - 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 -
|
|
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(target, prc20Token, amount, gasLimit, payload, revertRecipient, maxPCForGas = BigInt(0), gasPrice = BigInt(0)) {
|
|
240
241
|
return {
|
|
241
242
|
target,
|
|
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
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.classifyDeclineError = classifyDeclineError;
|
|
4
|
+
const formatters_1 = require("../formatters");
|
|
4
5
|
const utils_1 = require("../utils");
|
|
5
6
|
const progress_hook_types_1 = require("./progress-hook.types");
|
|
6
7
|
// Helper to wrap a hook function with timestamp
|
|
@@ -22,14 +23,6 @@ const friendlyChain = (chainOrNs) => {
|
|
|
22
23
|
const key = utils_1.Utils.chains.getChainName(asString);
|
|
23
24
|
return key ? toTitleCase(key) : asString;
|
|
24
25
|
};
|
|
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`;
|
|
33
26
|
/**
|
|
34
27
|
* Classify a sign-time error as either a true wallet user-decline
|
|
35
28
|
* (viem `UserRejectedRequestError`, ethers `ACTION_REJECTED`, EIP-1193 4001,
|
|
@@ -258,13 +251,16 @@ const RAW_HOOKS_R1 = {
|
|
|
258
251
|
level: 'SUCCESS',
|
|
259
252
|
};
|
|
260
253
|
},
|
|
261
|
-
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02]: (errMessage, decodedError) =>
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
254
|
+
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02]: (errMessage, decodedError) => {
|
|
255
|
+
const normalizedErrMessage = (0, formatters_1.normalizePcInsufficientFundsError)(errMessage);
|
|
256
|
+
return {
|
|
257
|
+
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02,
|
|
258
|
+
title: 'Push Chain Tx Failed',
|
|
259
|
+
message: normalizedErrMessage,
|
|
260
|
+
response: Object.assign({ error: normalizedErrMessage }, (decodedError ? { decodedError } : {})),
|
|
261
|
+
level: 'ERROR',
|
|
262
|
+
};
|
|
263
|
+
},
|
|
268
264
|
};
|
|
269
265
|
// =============================================================================
|
|
270
266
|
// Route 2 — UEA → UGPC → CEA on target chain (201–299, signature-only)
|
|
@@ -313,8 +309,8 @@ const RAW_HOOKS_R2 = {
|
|
|
313
309
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
|
|
314
310
|
var _a, _b, _c;
|
|
315
311
|
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` :
|
|
317
|
-
const requiredStr = kind === 'PRC20' ? `${required} units` :
|
|
312
|
+
const availableStr = kind === 'PRC20' ? `${available} units` : (0, formatters_1.formatPc)(available, 4);
|
|
313
|
+
const requiredStr = kind === 'PRC20' ? `${required} units` : (0, formatters_1.formatPc)(required, 4);
|
|
318
314
|
return {
|
|
319
315
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03,
|
|
320
316
|
title: 'Pre-flight Balance Check',
|
|
@@ -336,7 +332,7 @@ const RAW_HOOKS_R2 = {
|
|
|
336
332
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
|
|
337
333
|
var _a, _b, _c, _d;
|
|
338
334
|
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` :
|
|
335
|
+
const shortfallStr = kind === 'PRC20' ? `${shortfall} units` : (0, formatters_1.formatPc)(shortfall, 4);
|
|
340
336
|
const remediation = kind === 'PRC20'
|
|
341
337
|
? `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
338
|
: `Bridge >=${shortfallStr} to UEA ${ueaAddress} before retrying.`;
|
|
@@ -360,7 +356,7 @@ const RAW_HOOKS_R2 = {
|
|
|
360
356
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_05]: (quoted, threshold, gasToken, pathTag) => ({
|
|
361
357
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_05,
|
|
362
358
|
title: 'SVM Native-Value Warn Threshold',
|
|
363
|
-
message: `Buffered pool quote ${
|
|
359
|
+
message: `Buffered pool quote ${(0, formatters_1.formatPc)(quoted, 4)} exceeds warn threshold ${(0, formatters_1.formatPc)(threshold, 4)} ` +
|
|
364
360
|
`for ${gasToken} (${pathTag}). Pool may be skewed or quote is unusually large. ` +
|
|
365
361
|
`No action taken — pre-flight will determine if balance covers it.`,
|
|
366
362
|
response: { quoted, threshold, gasToken, pathTag },
|
|
@@ -527,8 +523,8 @@ const RAW_HOOKS_R3 = {
|
|
|
527
523
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_04]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
|
|
528
524
|
var _a, _b, _c;
|
|
529
525
|
const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
|
|
530
|
-
const availableStr = kind === 'PRC20' ? `${available} units` :
|
|
531
|
-
const requiredStr = kind === 'PRC20' ? `${required} units` :
|
|
526
|
+
const availableStr = kind === 'PRC20' ? `${available} units` : (0, formatters_1.formatPc)(available, 4);
|
|
527
|
+
const requiredStr = kind === 'PRC20' ? `${required} units` : (0, formatters_1.formatPc)(required, 4);
|
|
532
528
|
return {
|
|
533
529
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_04,
|
|
534
530
|
title: 'Pre-flight Balance Check',
|
|
@@ -550,7 +546,7 @@ const RAW_HOOKS_R3 = {
|
|
|
550
546
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_05]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
|
|
551
547
|
var _a, _b, _c, _d;
|
|
552
548
|
const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
|
|
553
|
-
const shortfallStr = kind === 'PRC20' ? `${shortfall} units` :
|
|
549
|
+
const shortfallStr = kind === 'PRC20' ? `${shortfall} units` : (0, formatters_1.formatPc)(shortfall, 4);
|
|
554
550
|
const remediation = kind === 'PRC20'
|
|
555
551
|
? `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.`
|
|
556
552
|
: `Bridge >=${shortfallStr} to UEA ${ueaAddress} before retrying.`;
|
|
@@ -574,7 +570,7 @@ const RAW_HOOKS_R3 = {
|
|
|
574
570
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_06]: (quoted, threshold, gasToken, pathTag) => ({
|
|
575
571
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_303_06,
|
|
576
572
|
title: 'SVM Native-Value Warn Threshold',
|
|
577
|
-
message: `Buffered pool quote ${
|
|
573
|
+
message: `Buffered pool quote ${(0, formatters_1.formatPc)(quoted, 4)} exceeds warn threshold ${(0, formatters_1.formatPc)(threshold, 4)} ` +
|
|
578
574
|
`for ${gasToken} (${pathTag}). Pool may be skewed or quote is unusually large. ` +
|
|
579
575
|
`No action taken — pre-flight will determine if balance covers it.`,
|
|
580
576
|
response: { quoted, threshold, gasToken, pathTag },
|
|
@@ -671,17 +667,22 @@ const RAW_HOOKS_R3 = {
|
|
|
671
667
|
// Phase is passed by the emission site so the title matches the leg that
|
|
672
668
|
// actually failed. Default stays 'inbound' for callers that don't specify
|
|
673
669
|
// (backwards-compat with fixtures + response-builder's inbound block).
|
|
674
|
-
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02]: (errorMessage, phase = 'inbound', chain, decodedError) =>
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
670
|
+
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02]: (errorMessage, phase = 'inbound', chain, decodedError) => {
|
|
671
|
+
const normalizedErrorMessage = phase === 'push'
|
|
672
|
+
? (0, formatters_1.normalizePcInsufficientFundsError)(errorMessage)
|
|
673
|
+
: errorMessage;
|
|
674
|
+
return {
|
|
675
|
+
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_02,
|
|
676
|
+
title: phase === 'outbound'
|
|
677
|
+
? `${friendlyChain(chain)} Tx Failed`
|
|
678
|
+
: phase === 'push'
|
|
679
|
+
? 'Push Chain Tx Failed'
|
|
680
|
+
: 'Push Chain Inbound Tx Failed',
|
|
681
|
+
message: normalizedErrorMessage,
|
|
682
|
+
response: Object.assign({ error: normalizedErrorMessage, phase, chain: chain !== null && chain !== void 0 ? chain : null }, (decodedError ? { decodedError } : {})),
|
|
683
|
+
level: 'ERROR',
|
|
684
|
+
};
|
|
685
|
+
},
|
|
685
686
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03]: (sourceChain, elapsedMs, phase = 'inbound') => ({
|
|
686
687
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_03,
|
|
687
688
|
title: phase === 'outbound'
|
|
@@ -786,8 +787,8 @@ const RAW_HOOKS_MULTICHAIN = {
|
|
|
786
787
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03]: (required, available, sufficient, ueaAddress, pathTag, extra) => {
|
|
787
788
|
var _a, _b, _c;
|
|
788
789
|
const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
|
|
789
|
-
const availableStr = kind === 'PRC20' ? `${available} units` :
|
|
790
|
-
const requiredStr = kind === 'PRC20' ? `${required} units` :
|
|
790
|
+
const availableStr = kind === 'PRC20' ? `${available} units` : (0, formatters_1.formatPc)(available, 4);
|
|
791
|
+
const requiredStr = kind === 'PRC20' ? `${required} units` : (0, formatters_1.formatPc)(required, 4);
|
|
791
792
|
return {
|
|
792
793
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_03,
|
|
793
794
|
title: 'Cascade Pre-flight Balance Check',
|
|
@@ -809,7 +810,7 @@ const RAW_HOOKS_MULTICHAIN = {
|
|
|
809
810
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_04]: (required, available, shortfall, ueaAddress, pathTag, extra) => {
|
|
810
811
|
var _a, _b, _c, _d;
|
|
811
812
|
const kind = (_a = extra === null || extra === void 0 ? void 0 : extra.kind) !== null && _a !== void 0 ? _a : 'NATIVE';
|
|
812
|
-
const shortfallStr = kind === 'PRC20' ? `${shortfall} units` :
|
|
813
|
+
const shortfallStr = kind === 'PRC20' ? `${shortfall} units` : (0, formatters_1.formatPc)(shortfall, 4);
|
|
813
814
|
const remediation = kind === 'PRC20'
|
|
814
815
|
? `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.`
|
|
815
816
|
: `Bridge >=${shortfallStr} to UEA ${ueaAddress} before retrying.`;
|
|
@@ -833,7 +834,7 @@ const RAW_HOOKS_MULTICHAIN = {
|
|
|
833
834
|
[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_05]: (quoted, threshold, gasToken, pathTag) => ({
|
|
834
835
|
id: progress_hook_types_1.PROGRESS_HOOK.SEND_TX_003_05,
|
|
835
836
|
title: 'Cascade SVM Native-Value Warn Threshold',
|
|
836
|
-
message: `Buffered pool quote ${
|
|
837
|
+
message: `Buffered pool quote ${(0, formatters_1.formatPc)(quoted, 4)} exceeds warn threshold ${(0, formatters_1.formatPc)(threshold, 4)} ` +
|
|
837
838
|
`for ${gasToken} (${pathTag}). Pool may be skewed or quote is unusually large. ` +
|
|
838
839
|
`No action taken — pre-flight will determine if balance covers it.`,
|
|
839
840
|
response: { quoted, threshold, gasToken, pathTag },
|
|
@@ -77,8 +77,18 @@ export declare class PushChain {
|
|
|
77
77
|
/**
|
|
78
78
|
* Execute one or more prepared transactions as a cascade across chains.
|
|
79
79
|
* Accepts an array of PreparedUniversalTx (from prepareTransaction).
|
|
80
|
+
*
|
|
81
|
+
* @param txs - Prepared transactions to execute as a cascade.
|
|
82
|
+
* @param options.progressHook - Optional per-call progress callback.
|
|
83
|
+
* Additive with the init-time `progressHook` passed to `initialize`:
|
|
84
|
+
* both hooks receive every `ProgressEvent` emitted during this call
|
|
85
|
+
* (pre-flight, broadcast, and cascade tracking). Dedups by reference
|
|
86
|
+
* if it matches the init-time hook. Note: concurrent calls on the
|
|
87
|
+
* same instance share the hook channel during the broadcast phase.
|
|
80
88
|
*/
|
|
81
|
-
executeTransactions: (txs: PreparedUniversalTx[]
|
|
89
|
+
executeTransactions: (txs: PreparedUniversalTx[], options?: {
|
|
90
|
+
progressHook?: (event: ProgressEvent) => void;
|
|
91
|
+
}) => Promise<CascadedTxResponse>;
|
|
82
92
|
/**
|
|
83
93
|
* Tracks a transaction by hash on Push Chain
|
|
84
94
|
*/
|
|
@@ -84,11 +84,11 @@ class PushChain {
|
|
|
84
84
|
prepareTransaction: (params) => {
|
|
85
85
|
return orchestrator.prepareTransaction.bind(orchestrator)(params);
|
|
86
86
|
},
|
|
87
|
-
executeTransactions: (txs) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
executeTransactions: (txs, options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
88
88
|
if (this.isReadMode) {
|
|
89
89
|
throw new Error('Read only mode cannot call executeTransactions function');
|
|
90
90
|
}
|
|
91
|
-
return orchestrator.createCascadedBuilder(txs).send();
|
|
91
|
+
return orchestrator.createCascadedBuilder(txs, options).send();
|
|
92
92
|
}),
|
|
93
93
|
trackTransaction: (txHash, options) => {
|
|
94
94
|
return orchestrator.trackTransaction.bind(orchestrator)(txHash, options);
|
|
@@ -25,6 +25,7 @@ const enums_1 = require("../constants/enums");
|
|
|
25
25
|
Object.defineProperty(exports, "PUSH_NETWORK", { enumerable: true, get: function () { return enums_1.PUSH_NETWORK; } });
|
|
26
26
|
const child_inbounds_1 = require("./child-inbounds");
|
|
27
27
|
const detector_1 = require("./detector");
|
|
28
|
+
const normalize_1 = require("./normalize");
|
|
28
29
|
const PUSH_CHAIN_CAIPS = new Set([
|
|
29
30
|
enums_1.CHAIN.PUSH_MAINNET,
|
|
30
31
|
enums_1.CHAIN.PUSH_TESTNET_DONUT,
|
|
@@ -46,8 +47,10 @@ function traceUniversalTxCascade(startHash, startChain, opts) {
|
|
|
46
47
|
const root = yield walk(startHash, startChain, 0, state, opts);
|
|
47
48
|
if (!root) {
|
|
48
49
|
// Should never happen for depth=0; return an empty detection node so the
|
|
49
|
-
// caller has something to render.
|
|
50
|
-
|
|
50
|
+
// caller has something to render. No outbound summaries → nothing to
|
|
51
|
+
// normalize, but we still pass through `normalizeCascadeNodeForUser`
|
|
52
|
+
// for symmetry with the happy path below.
|
|
53
|
+
return (0, normalize_1.normalizeCascadeNodeForUser)({
|
|
51
54
|
detection: {
|
|
52
55
|
txHash: startHash,
|
|
53
56
|
chain: startChain,
|
|
@@ -60,9 +63,16 @@ function traceUniversalTxCascade(startHash, startChain, opts) {
|
|
|
60
63
|
},
|
|
61
64
|
children: [],
|
|
62
65
|
depth: 0,
|
|
63
|
-
};
|
|
66
|
+
});
|
|
64
67
|
}
|
|
65
|
-
|
|
68
|
+
// User-facing normalization pass — recursively rewrites every
|
|
69
|
+
// `PushChainOutboundSummary.externalTxHash` in the tree to base58 for SVM
|
|
70
|
+
// destinations. Each internal `detectUniversalTx` call (in `walk`) already
|
|
71
|
+
// produced a normalized detection; this final pass also normalizes the
|
|
72
|
+
// edge-level `relation` summaries inside `expandPushOutbounds` /
|
|
73
|
+
// `expandExternalChildInbounds` which build summaries DIRECTLY (without
|
|
74
|
+
// going through `detectUniversalTx`).
|
|
75
|
+
return (0, normalize_1.normalizeCascadeNodeForUser)(root);
|
|
66
76
|
});
|
|
67
77
|
}
|
|
68
78
|
// ── Core recursion ────────────────────────────────────────────────────
|
|
@@ -22,6 +22,7 @@ const tslib_1 = require("tslib");
|
|
|
22
22
|
* `pushClient.getUniversalTxByIdV2`, no event-attribute predicate needed.
|
|
23
23
|
*/
|
|
24
24
|
const viem_1 = require("viem");
|
|
25
|
+
const normalize_1 = require("./normalize");
|
|
25
26
|
const STATUS_NAMES = {
|
|
26
27
|
0: 'UNIVERSAL_TX_STATUS_UNSPECIFIED',
|
|
27
28
|
1: 'INBOUND_SUCCESS',
|
|
@@ -75,7 +76,14 @@ function resolveChildInboundsFromDetection(pushClient, detection, diagnostics) {
|
|
|
75
76
|
const inboundLogs = detection.detections
|
|
76
77
|
.filter((d) => INBOUND_EVENT_NAMES.has(d.log.eventName))
|
|
77
78
|
.map((d) => d.log);
|
|
78
|
-
|
|
79
|
+
const resolutions = yield resolveChildInboundsFromLogs(pushClient, detection.chain, detection.txHash, inboundLogs, diagnostics);
|
|
80
|
+
// User-facing normalization pass: rewrites nested
|
|
81
|
+
// `outboundHashes[n].externalTxHash` to base58 for SVM destinations.
|
|
82
|
+
// `pcTxHashes` is Push Chain (EVM) and stays hex by chain type. The lower-
|
|
83
|
+
// level `resolveChildInboundsFromLogs` is left producing raw hex so
|
|
84
|
+
// internal callers (`findChildUtxIdFromExternalTx` via the detector path)
|
|
85
|
+
// that go through it directly still see the canonical form.
|
|
86
|
+
return resolutions.map(normalize_1.normalizeChildInboundResolutionForUser);
|
|
79
87
|
});
|
|
80
88
|
}
|
|
81
89
|
/**
|
|
@@ -25,6 +25,7 @@ const events_1 = require("./events");
|
|
|
25
25
|
const classify_1 = require("./classify");
|
|
26
26
|
const child_inbounds_1 = require("./child-inbounds");
|
|
27
27
|
const detector_svm_1 = require("./detector-svm");
|
|
28
|
+
const normalize_1 = require("./normalize");
|
|
28
29
|
// ── Status name table (copied from scripts/poll-outbound.ts:33-44) ────
|
|
29
30
|
const UNIVERSAL_TX_STATUS_NAMES = {
|
|
30
31
|
0: 'UNIVERSAL_TX_STATUS_UNSPECIFIED',
|
|
@@ -51,7 +52,7 @@ function detectUniversalTx(txHash_1, chain_2) {
|
|
|
51
52
|
throw new Error(`detectUniversalTx: unknown chain ${chain}`);
|
|
52
53
|
}
|
|
53
54
|
if (chainInfo.vm === enums_1.VM.SVM) {
|
|
54
|
-
return (0, detector_svm_1.detectUniversalTxSvm)(txHash, chain, opts);
|
|
55
|
+
return (0, normalize_1.normalizeDetectionForUser)(yield (0, detector_svm_1.detectUniversalTxSvm)(txHash, chain, opts));
|
|
55
56
|
}
|
|
56
57
|
if (chainInfo.vm !== enums_1.VM.EVM) {
|
|
57
58
|
throw new Error(`detectUniversalTx: unsupported vm=${chainInfo.vm} for ${chain}`);
|
|
@@ -132,7 +133,12 @@ function detectUniversalTx(txHash_1, chain_2) {
|
|
|
132
133
|
notes.push('push cross-reference skipped (no pushClient provided)');
|
|
133
134
|
}
|
|
134
135
|
const detections = (0, classify_1.classifyAll)(classified.matchingLogs);
|
|
135
|
-
|
|
136
|
+
// User-facing normalization pass: rewrites `pushChainTx.outboundHashes[n]
|
|
137
|
+
// .externalTxHash` to base58 for SVM destinations. The raw `0x`-hex form
|
|
138
|
+
// never leaves this function — internal consumers (findChildUtxIdFromExternalTx,
|
|
139
|
+
// Cosmos `inbound_tx_hash=` queries) work off their own input parameters,
|
|
140
|
+
// not the detection result's outbound summaries.
|
|
141
|
+
return (0, normalize_1.normalizeDetectionForUser)({
|
|
136
142
|
txHash,
|
|
137
143
|
chain,
|
|
138
144
|
kind: classified.kind,
|
|
@@ -142,7 +148,7 @@ function detectUniversalTx(txHash_1, chain_2) {
|
|
|
142
148
|
detections,
|
|
143
149
|
pushChainTx,
|
|
144
150
|
notes,
|
|
145
|
-
};
|
|
151
|
+
});
|
|
146
152
|
});
|
|
147
153
|
}
|
|
148
154
|
// ── Helpers ───────────────────────────────────────────────────────────
|
|
@@ -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,
|
|
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,
|
|
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
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-facing normalization pass for detector outputs.
|
|
3
|
+
*
|
|
4
|
+
* The detector module's internal pipeline produces `PushChainOutboundSummary`
|
|
5
|
+
* objects with raw `0x`-hex `externalTxHash` for SVM destinations — that's
|
|
6
|
+
* the form Cosmos delivers and the form `findChildUtxIdFromExternalTx` /
|
|
7
|
+
* `inbound_tx_hash='…'` queries require. For USER-facing entry points
|
|
8
|
+
* (`detectUniversalTx`, `traceUniversalTxCascade`,
|
|
9
|
+
* `resolveChildInboundsFromDetection`), the SVM hash should be base58 so
|
|
10
|
+
* consumers can paste it straight into a Solana explorer or
|
|
11
|
+
* `connection.getTransaction(sig)`.
|
|
12
|
+
*
|
|
13
|
+
* These helpers are applied at the three public-API return points (and
|
|
14
|
+
* NOWHERE else) — they walk the result tree and rewrite
|
|
15
|
+
* `PushChainOutboundSummary.externalTxHash` for SVM destinations. The
|
|
16
|
+
* internal pipeline never sees the normalized form.
|
|
17
|
+
*
|
|
18
|
+
* Helpers are idempotent: a value not starting with `0x` or whose
|
|
19
|
+
* `destinationChain` isn't SVM passes through unchanged. New objects are
|
|
20
|
+
* returned only when a field actually changed; otherwise the same reference
|
|
21
|
+
* is reused so EVM-only graphs incur near-zero allocation.
|
|
22
|
+
*/
|
|
23
|
+
import type { PushChainOutboundSummary, UniversalTxDetection } from './types';
|
|
24
|
+
import type { CascadeNode } from './cascade';
|
|
25
|
+
import type { ChildInboundResolution } from './child-inbounds';
|
|
26
|
+
/**
|
|
27
|
+
* Normalize a single outbound summary's `externalTxHash` for user display.
|
|
28
|
+
* Returns the same reference when no change is needed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeOutboundSummaryForUser(s: PushChainOutboundSummary): PushChainOutboundSummary;
|
|
31
|
+
/**
|
|
32
|
+
* Normalize the outbound summaries embedded in `detection.pushChainTx`.
|
|
33
|
+
* The root `detection.txHash` is left untouched — per agreed scope.
|
|
34
|
+
*/
|
|
35
|
+
export declare function normalizeDetectionForUser(d: UniversalTxDetection): UniversalTxDetection;
|
|
36
|
+
/**
|
|
37
|
+
* Normalize the outbound summaries inside a `ChildInboundResolution`.
|
|
38
|
+
* `pcTxHashes` (Push Chain — always EVM) is left untouched.
|
|
39
|
+
*/
|
|
40
|
+
export declare function normalizeChildInboundResolutionForUser(r: ChildInboundResolution): ChildInboundResolution;
|
|
41
|
+
/** Recursively normalize a cascade tree. */
|
|
42
|
+
export declare function normalizeCascadeNodeForUser(n: CascadeNode): CascadeNode;
|