@pushchain/core 5.1.5-alpha.1 → 5.1.5

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 (86) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +1 -1
  3. package/src/lib/constants/abi/index.d.ts +2 -0
  4. package/src/lib/constants/abi/index.js +6 -1
  5. package/src/lib/constants/abi/uniswap-v3-router.evm.d.ts +58 -0
  6. package/src/lib/constants/abi/uniswap-v3-router.evm.js +41 -0
  7. package/src/lib/constants/abi/wpc.evm.d.ts +24 -0
  8. package/src/lib/constants/abi/wpc.evm.js +27 -0
  9. package/src/lib/constants/chain.d.ts +1 -0
  10. package/src/lib/constants/chain.js +8 -6
  11. package/src/lib/constants/tokens.js +3 -3
  12. package/src/lib/generated/uexecutor/v2/types.d.ts +14 -0
  13. package/src/lib/generated/uexecutor/v2/types.js +96 -3
  14. package/src/lib/orchestrator/internals/cascade.d.ts +1 -1
  15. package/src/lib/orchestrator/internals/cascade.js +521 -239
  16. package/src/lib/orchestrator/internals/confirmation.js +60 -15
  17. package/src/lib/orchestrator/internals/context.d.ts +23 -0
  18. package/src/lib/orchestrator/internals/context.js +54 -0
  19. package/src/lib/orchestrator/internals/execute-funds-only.js +47 -21
  20. package/src/lib/orchestrator/internals/execute-funds-payload.js +53 -31
  21. package/src/lib/orchestrator/internals/execute-standard.js +137 -26
  22. package/src/lib/orchestrator/internals/gas-calculator.d.ts +5 -2
  23. package/src/lib/orchestrator/internals/gas-calculator.js +59 -11
  24. package/src/lib/orchestrator/internals/gas-usd-sizer.d.ts +53 -0
  25. package/src/lib/orchestrator/internals/gas-usd-sizer.js +165 -0
  26. package/src/lib/orchestrator/internals/helpers.js +2 -0
  27. package/src/lib/orchestrator/internals/inbound-tracker.d.ts +83 -0
  28. package/src/lib/orchestrator/internals/inbound-tracker.js +322 -0
  29. package/src/lib/orchestrator/internals/index.d.ts +3 -1
  30. package/src/lib/orchestrator/internals/index.js +8 -2
  31. package/src/lib/orchestrator/internals/outbound-sync.d.ts +32 -1
  32. package/src/lib/orchestrator/internals/outbound-sync.js +154 -17
  33. package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +28 -0
  34. package/src/lib/orchestrator/internals/pc-usd-oracle.js +285 -0
  35. package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +23 -0
  36. package/src/lib/orchestrator/internals/progress-route-hooks.js +72 -0
  37. package/src/lib/orchestrator/internals/push-chain-tx.d.ts +27 -1
  38. package/src/lib/orchestrator/internals/push-chain-tx.js +111 -15
  39. package/src/lib/orchestrator/internals/rescue.js +1 -1
  40. package/src/lib/orchestrator/internals/response-builder.d.ts +5 -0
  41. package/src/lib/orchestrator/internals/response-builder.js +242 -66
  42. package/src/lib/orchestrator/internals/route-handlers.js +480 -206
  43. package/src/lib/orchestrator/internals/tx-transformer.js +293 -35
  44. package/src/lib/orchestrator/orchestrator.d.ts +7 -1
  45. package/src/lib/orchestrator/orchestrator.js +108 -56
  46. package/src/lib/orchestrator/orchestrator.types.d.ts +111 -5
  47. package/src/lib/orchestrator/payload-builders.d.ts +16 -0
  48. package/src/lib/orchestrator/payload-builders.js +6 -5
  49. package/src/lib/orchestrator/route-detector.js +20 -8
  50. package/src/lib/orchestrator/svm-idl/normalize-address.d.ts +19 -0
  51. package/src/lib/orchestrator/svm-idl/normalize-address.js +56 -0
  52. package/src/lib/orchestrator/svm-idl/registry.d.ts +13 -4
  53. package/src/lib/orchestrator/svm-idl/registry.js +15 -14
  54. package/src/lib/orchestrator/svm-idl/resolve.js +5 -2
  55. package/src/lib/progress-hook/progress-hook.d.ts +28 -0
  56. package/src/lib/progress-hook/progress-hook.js +545 -131
  57. package/src/lib/progress-hook/progress-hook.types.d.ts +76 -29
  58. package/src/lib/progress-hook/progress-hook.types.js +74 -35
  59. package/src/lib/push-client/push-client.d.ts +7 -0
  60. package/src/lib/push-client/push-client.js +18 -1
  61. package/src/lib/universal-tx-detector/__tests__/fixtures/builders.d.ts +32 -0
  62. package/src/lib/universal-tx-detector/__tests__/fixtures/builders.js +65 -0
  63. package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.d.ts +72 -0
  64. package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.js +669 -0
  65. package/src/lib/universal-tx-detector/auto-detect.d.ts +37 -0
  66. package/src/lib/universal-tx-detector/auto-detect.js +112 -0
  67. package/src/lib/universal-tx-detector/cascade.d.ts +64 -0
  68. package/src/lib/universal-tx-detector/cascade.js +254 -0
  69. package/src/lib/universal-tx-detector/child-inbounds.d.ts +58 -0
  70. package/src/lib/universal-tx-detector/child-inbounds.js +145 -0
  71. package/src/lib/universal-tx-detector/classify.d.ts +33 -0
  72. package/src/lib/universal-tx-detector/classify.js +228 -0
  73. package/src/lib/universal-tx-detector/detector-svm.d.ts +46 -0
  74. package/src/lib/universal-tx-detector/detector-svm.js +324 -0
  75. package/src/lib/universal-tx-detector/detector.d.ts +13 -0
  76. package/src/lib/universal-tx-detector/detector.js +233 -0
  77. package/src/lib/universal-tx-detector/events.d.ts +765 -0
  78. package/src/lib/universal-tx-detector/events.js +241 -0
  79. package/src/lib/universal-tx-detector/index.d.ts +18 -0
  80. package/src/lib/universal-tx-detector/index.js +36 -0
  81. package/src/lib/universal-tx-detector/svm-events.d.ts +41 -0
  82. package/src/lib/universal-tx-detector/svm-events.js +68 -0
  83. package/src/lib/universal-tx-detector/types.d.ts +100 -0
  84. package/src/lib/universal-tx-detector/types.js +3 -0
  85. package/src/lib/utils.d.ts +30 -13
  86. package/src/lib/utils.js +47 -21
@@ -10,6 +10,23 @@ 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
30
  type TransformToResponseFn = (tx: TxResponse, eventBuffer: ProgressEvent[]) => Promise<UniversalTxResponse>;
14
31
  /**
15
32
  * Sends an EVM transaction directly on Push Chain.
@@ -19,11 +36,20 @@ type TransformToResponseFn = (tx: TxResponse, eventBuffer: ProgressEvent[]) => P
19
36
  * local nonce management and per-tx receipt confirmation.
20
37
  */
21
38
  export declare function sendPushTx(ctx: OrchestratorContext, execute: ExecuteParams, eventBuffer: ProgressEvent[], transformFn: TransformToResponseFn): Promise<UniversalTxResponse>;
39
+ export type ResignUniversalPayloadFn = () => Promise<{
40
+ universalPayload: UniversalPayload;
41
+ verificationData: `0x${string}`;
42
+ }>;
22
43
  /**
23
44
  * Sends a Cosmos tx to Push Chain (gasless) to execute user intent.
24
45
  * Wraps the EVM payload in a MsgExecutePayload Cosmos message.
46
+ *
47
+ * `resignFn` (optional): if provided, `sendUniversalTx` retries up to
48
+ * `MAX_SIG_RETRIES` times when the Cosmos revert carries the
49
+ * `InvalidEVMSignature()` selector. Each retry calls `resignFn` to obtain
50
+ * a payload re-signed against the UEA's current on-chain nonce.
25
51
  */
26
- export declare function sendUniversalTx(ctx: OrchestratorContext, isUEADeployed: boolean, feeLockTxHash: string | undefined, universalPayload: UniversalPayload | undefined, verificationData: `0x${string}` | undefined, eventBuffer: ProgressEvent[], transformFn: TransformToResponseFn): Promise<UniversalTxResponse[]>;
52
+ export declare function sendUniversalTx(ctx: OrchestratorContext, isUEADeployed: boolean, feeLockTxHash: string | undefined, universalPayload: UniversalPayload | undefined, verificationData: `0x${string}` | undefined, eventBuffer: ProgressEvent[], transformFn: TransformToResponseFn, resignFn?: ResignUniversalPayloadFn): Promise<UniversalTxResponse[]>;
27
53
  /**
28
54
  * Validates Push Chain tx response, extracts last pcTx, fetches EVM tx,
29
55
  * and transforms to UniversalTxResponse.
@@ -6,6 +6,7 @@
6
6
  * sendUniversalTx: Cosmos-wrapped EVM tx via PushClient (gasless path)
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PushChainExecutionError = void 0;
9
10
  exports.sendPushTx = sendPushTx;
10
11
  exports.sendUniversalTx = sendUniversalTx;
11
12
  exports.extractPcTxAndTransform = extractPcTxAndTransform;
@@ -14,8 +15,31 @@ const bs58_1 = require("../../internal/bs58");
14
15
  const viem_1 = require("viem");
15
16
  const chain_1 = require("../../constants/chain");
16
17
  const enums_1 = require("../../constants/enums");
18
+ const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
17
19
  const context_1 = require("./context");
18
20
  // ============================================================================
21
+ // PushChainExecutionError
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
+ class PushChainExecutionError extends Error {
34
+ constructor(message, opts = {}) {
35
+ super(message);
36
+ this.code = 'PUSH_CHAIN_EXECUTION_FAILED';
37
+ this.name = 'PushChainExecutionError';
38
+ this.gatewayTxHash = opts.gatewayTxHash;
39
+ }
40
+ }
41
+ exports.PushChainExecutionError = PushChainExecutionError;
42
+ // ============================================================================
19
43
  // sendPushTx
20
44
  // ============================================================================
21
45
  /**
@@ -117,11 +141,31 @@ function sendPushTx(ctx, execute, eventBuffer, transformFn) {
117
141
  // ============================================================================
118
142
  // sendUniversalTx
119
143
  // ============================================================================
144
+ /**
145
+ * UEAErrors.InvalidEVMSignature() selector. Thrown by UEA_EVM.executeUniversalTx
146
+ * when the recovered EIP-712 signer doesn't match the UEA owner — typically
147
+ * because UEA storage `nonce` advanced between getUEANonce() and Cosmos
148
+ * inclusion. The retry hook re-fetches nonce, re-signs, and re-broadcasts.
149
+ */
150
+ const INVALID_EVM_SIGNATURE_SELECTOR = '0xc7dbd31d';
151
+ const MAX_SIG_RETRIES = 2;
152
+ // Cosmos-layer sequence race: two broadcasts sign with the same account
153
+ // sequence before either lands; the node rejects the loser with
154
+ // "account sequence mismatch". Re-signing pulls a fresh sequence (signCosmosTx
155
+ // re-fetches it per call), so a simple loop-back is sufficient.
156
+ const COSMOS_SEQUENCE_MISMATCH_RE = /account sequence mismatch|incorrect account sequence/i;
157
+ const MAX_SEQ_RETRIES = 3;
158
+ const SEQ_RETRY_BASE_DELAY_MS = 400;
120
159
  /**
121
160
  * Sends a Cosmos tx to Push Chain (gasless) to execute user intent.
122
161
  * Wraps the EVM payload in a MsgExecutePayload Cosmos message.
162
+ *
163
+ * `resignFn` (optional): if provided, `sendUniversalTx` retries up to
164
+ * `MAX_SIG_RETRIES` times when the Cosmos revert carries the
165
+ * `InvalidEVMSignature()` selector. Each retry calls `resignFn` to obtain
166
+ * a payload re-signed against the UEA's current on-chain nonce.
123
167
  */
124
- function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, verificationData, eventBuffer, transformFn) {
168
+ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, verificationData, eventBuffer, transformFn, resignFn) {
125
169
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
126
170
  var _a, _b, _c, _d;
127
171
  const { chain, address } = ctx.universalSigner.account;
@@ -136,19 +180,63 @@ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, ve
136
180
  : address,
137
181
  };
138
182
  const { cosmosAddress: signer } = ctx.pushClient.getSignerAddress();
139
- const msgs = [];
140
- if (universalPayload && verificationData) {
141
- msgs.push(ctx.pushClient.createMsgExecutePayload({
142
- signer,
143
- universalAccountId,
144
- universalPayload,
145
- verificationData,
146
- }));
147
- }
148
- const txBody = yield ctx.pushClient.createCosmosTxBody(msgs);
149
- const txRaw = yield ctx.pushClient.signCosmosTx(txBody);
150
- const tx = yield ctx.pushClient.broadcastCosmosTx(txRaw);
151
- if (tx.code !== 0) {
183
+ let currentPayload = universalPayload;
184
+ let currentVerificationData = verificationData;
185
+ let tx;
186
+ let seqRetryCount = 0;
187
+ for (let attempt = 0; attempt <= MAX_SIG_RETRIES; attempt++) {
188
+ const msgs = [];
189
+ if (currentPayload && currentVerificationData) {
190
+ msgs.push(ctx.pushClient.createMsgExecutePayload({
191
+ signer,
192
+ universalAccountId,
193
+ universalPayload: currentPayload,
194
+ verificationData: currentVerificationData,
195
+ }));
196
+ }
197
+ const txBody = yield ctx.pushClient.createCosmosTxBody(msgs);
198
+ const txRaw = yield ctx.pushClient.signCosmosTx(txBody);
199
+ try {
200
+ tx = yield ctx.pushClient.broadcastCosmosTx(txRaw);
201
+ }
202
+ catch (err) {
203
+ const msg = (err === null || err === void 0 ? void 0 : err.message) || String(err);
204
+ if (COSMOS_SEQUENCE_MISMATCH_RE.test(msg) &&
205
+ seqRetryCount < MAX_SEQ_RETRIES) {
206
+ seqRetryCount++;
207
+ const delay = Math.round(SEQ_RETRY_BASE_DELAY_MS * seqRetryCount * (1 + Math.random() * 0.2));
208
+ (0, context_1.printLog)(ctx, `sendUniversalTx — Cosmos sequence mismatch on broadcast (retry ${seqRetryCount}/${MAX_SEQ_RETRIES}), sleeping ${delay}ms: ${msg}`);
209
+ yield new Promise((r) => setTimeout(r, delay));
210
+ attempt--; // don't consume EVM-signature retry budget
211
+ continue;
212
+ }
213
+ throw err;
214
+ }
215
+ if (tx.code === 0)
216
+ break;
217
+ // Cosmos sequence race: returned via tx.rawLog rather than thrown
218
+ const isSeqMismatch = typeof tx.rawLog === 'string' &&
219
+ COSMOS_SEQUENCE_MISMATCH_RE.test(tx.rawLog);
220
+ if (isSeqMismatch && seqRetryCount < MAX_SEQ_RETRIES) {
221
+ seqRetryCount++;
222
+ const delay = Math.round(SEQ_RETRY_BASE_DELAY_MS * seqRetryCount * (1 + Math.random() * 0.2));
223
+ (0, context_1.printLog)(ctx, `sendUniversalTx — Cosmos sequence mismatch in tx.rawLog (retry ${seqRetryCount}/${MAX_SEQ_RETRIES}), sleeping ${delay}ms: ${tx.rawLog}`);
224
+ yield new Promise((r) => setTimeout(r, delay));
225
+ attempt--; // don't consume EVM-signature retry budget
226
+ continue;
227
+ }
228
+ // Nonce-race retry: UEA storage nonce advanced between our read and
229
+ // tx inclusion. Re-sign with the fresh nonce and rebroadcast.
230
+ const isSigMismatch = typeof tx.rawLog === 'string' &&
231
+ tx.rawLog.includes(INVALID_EVM_SIGNATURE_SELECTOR);
232
+ if (attempt < MAX_SIG_RETRIES && isSigMismatch && resignFn) {
233
+ (0, context_1.printLog)(ctx, `sendUniversalTx — InvalidEVMSignature on attempt ${attempt + 1} (${tx.rawLog}); re-signing with fresh UEA nonce (retry ${attempt + 1}/${MAX_SIG_RETRIES})`);
234
+ const fresh = yield resignFn();
235
+ currentPayload = fresh.universalPayload;
236
+ currentVerificationData = fresh.verificationData;
237
+ continue;
238
+ }
239
+ // Terminal failure
152
240
  const failedEthTxHashes = (_b = (_a = tx.events) === null || _a === void 0 ? void 0 : _a.filter((e) => e.type === 'ethereum_tx').flatMap((e) => {
153
241
  var _a;
154
242
  return (_a = e.attributes) === null || _a === void 0 ? void 0 : _a.filter((attr) => attr.key === 'ethereumTxHash').map((attr) => attr.value);
@@ -164,6 +252,9 @@ function sendUniversalTx(ctx, isUEADeployed, feeLockTxHash, universalPayload, ve
164
252
  (0, context_1.printLog)(ctx, failureSummary);
165
253
  throw new Error(tx.rawLog);
166
254
  }
255
+ if (!tx || tx.code !== 0) {
256
+ throw new Error(`sendUniversalTx — unreachable: loop exited without success or throw`);
257
+ }
167
258
  const ethTxHashes = (_d = (_c = tx.events) === null || _c === void 0 ? void 0 : _c.filter((e) => e.type === 'ethereum_tx').flatMap((e) => {
168
259
  var _a;
169
260
  return (_a = e.attributes) === null || _a === void 0 ? void 0 : _a.filter((attr) => attr.key === 'ethereumTxHash').map((attr) => attr.value);
@@ -212,7 +303,12 @@ function extractPcTxAndTransform(ctx, pushChainUniversalTx, gatewayTxHash, event
212
303
  hint = ' [ExpiredDeadline: the transaction deadline has passed.]';
213
304
  }
214
305
  }
215
- throw new Error(`Push Chain transaction failed for gateway tx: ${gatewayTxHash}${errorDetails}${hint}`);
306
+ const fullMessage = `Push Chain transaction failed for gateway tx: ${gatewayTxHash}${errorDetails}${hint}`;
307
+ // Live-emit 199-02 before throwing so the terminal failure hook reaches
308
+ // any caller-registered progress stream (parity with reconstructProgressEvents
309
+ // which emits 199-02 on replay).
310
+ (0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_199_02, fullMessage);
311
+ throw new PushChainExecutionError(fullMessage, { gatewayTxHash });
216
312
  }
217
313
  const tx = yield ctx.pushClient.getTransaction(lastPcTransaction.txHash);
218
314
  return transformFn(tx, eventBuffer);
@@ -55,7 +55,7 @@ function rescueFunds(ctx, params, executeFn) {
55
55
  // Query rescue gas fee
56
56
  let nativeValueForGas = BigInt(0);
57
57
  try {
58
- const result = yield (0, gas_calculator_1.queryRescueGasFee)(ctx, params.prc20);
58
+ const result = yield (0, gas_calculator_1.queryRescueGasFee)(ctx, params.prc20, ctx.universalSigner.account.chain);
59
59
  nativeValueForGas = result.nativeValueForGas;
60
60
  (0, context_1.printLog)(ctx, `rescueFunds — queried gas fee: gasFee=${result.gasFee.toString()}, gasToken=${result.gasToken}, nativeValueForGas=${nativeValueForGas.toString()}`);
61
61
  }
@@ -20,6 +20,11 @@ export interface ResponseBuilderCallbacks {
20
20
  pollingIntervalMs: number;
21
21
  maxTimeoutMs: number;
22
22
  };
23
+ inboundConstants: {
24
+ initialWaitMs: number;
25
+ pollingIntervalMs: number;
26
+ maxTimeoutMs: number;
27
+ };
23
28
  }
24
29
  export declare function queryUniversalTxStatusFromGatewayTx(ctx: OrchestratorContext, evmClient: EvmClient | undefined, gatewayAddress: `0x${string}` | undefined, txHash: string, evmGatewayMethod: 'sendFunds' | 'sendTxWithFunds' | 'sendTxWithGas'): Promise<UniversalTx | undefined>;
25
30
  export declare function trackTransaction(ctx: OrchestratorContext, txHash: string, options?: TrackTransactionOptions, callbacks?: ResponseBuilderCallbacks): Promise<UniversalTxResponse>;