@pushchain/core 6.0.19 → 6.0.21

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 (112) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/package.json +1 -1
  3. package/src/lib/cache/cache.js +2 -0
  4. package/src/lib/constants/abi/index.d.ts +1 -0
  5. package/src/lib/constants/abi/index.js +8 -1
  6. package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
  7. package/src/lib/constants/abi/pc20.evm.js +150 -0
  8. package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
  9. package/src/lib/constants/abi/prc20.evm.js +97 -0
  10. package/src/lib/constants/abi/universalGatewayV0.json +1 -1
  11. package/src/lib/constants/chain.js +38 -8
  12. package/src/lib/constants/selectors.js +2 -2
  13. package/src/lib/constants/tokens.js +4 -3
  14. package/src/lib/formatters.js +16 -6
  15. package/src/lib/generated/uexecutor/v1/query.js +2 -4
  16. package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
  17. package/src/lib/generated/uexecutor/v1/types.js +90 -47
  18. package/src/lib/generated/uexecutor/v2/query.js +2 -4
  19. package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
  20. package/src/lib/generated/uexecutor/v2/types.js +49 -33
  21. package/src/lib/generated/v1/tx.js +30 -37
  22. package/src/lib/index.d.ts +4 -1
  23. package/src/lib/index.js +21 -3
  24. package/src/lib/internal/buffer.js +1 -2
  25. package/src/lib/orchestrator/cea-utils.js +73 -83
  26. package/src/lib/orchestrator/internals/account-manager.js +130 -139
  27. package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
  28. package/src/lib/orchestrator/internals/cascade.js +1184 -1059
  29. package/src/lib/orchestrator/internals/confirmation.js +138 -148
  30. package/src/lib/orchestrator/internals/error-decoder.js +1 -1
  31. package/src/lib/orchestrator/internals/errors.js +12 -3
  32. package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
  33. package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
  34. package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
  35. package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
  36. package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
  37. package/src/lib/orchestrator/internals/execute-standard.js +339 -342
  38. package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
  39. package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
  40. package/src/lib/orchestrator/internals/gateway-client.js +102 -103
  41. package/src/lib/orchestrator/internals/helpers.js +30 -27
  42. package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
  43. package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
  44. package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
  45. package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
  46. package/src/lib/orchestrator/internals/payload-builder.js +119 -100
  47. package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
  48. package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
  49. package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
  50. package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
  51. package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
  52. package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
  53. package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
  54. package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
  55. package/src/lib/orchestrator/internals/pc20/export.js +412 -0
  56. package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
  57. package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
  58. package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
  59. package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
  60. package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
  61. package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
  62. package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
  63. package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
  64. package/src/lib/orchestrator/internals/preflight.js +1 -1
  65. package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
  66. package/src/lib/orchestrator/internals/push-chain-tx.js +319 -331
  67. package/src/lib/orchestrator/internals/quote.js +90 -94
  68. package/src/lib/orchestrator/internals/rescue.js +76 -79
  69. package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
  70. package/src/lib/orchestrator/internals/response-builder.js +817 -701
  71. package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
  72. package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
  73. package/src/lib/orchestrator/internals/signing.js +78 -83
  74. package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
  75. package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
  76. package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
  77. package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
  78. package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
  79. package/src/lib/orchestrator/internals/svm-rent.js +163 -141
  80. package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
  81. package/src/lib/orchestrator/internals/uea-manager.js +89 -86
  82. package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
  83. package/src/lib/orchestrator/orchestrator.js +217 -200
  84. package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
  85. package/src/lib/orchestrator/orchestrator.types.js +19 -0
  86. package/src/lib/orchestrator/payload-builders.d.ts +2 -2
  87. package/src/lib/orchestrator/payload-builders.js +26 -24
  88. package/src/lib/orchestrator/route-detector.js +26 -9
  89. package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
  90. package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
  91. package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
  92. package/src/lib/price-fetch/price-fetch.js +67 -68
  93. package/src/lib/progress-hook/progress-hook.js +124 -72
  94. package/src/lib/push-chain/push-chain.js +171 -153
  95. package/src/lib/push-client/push-client.js +223 -237
  96. package/src/lib/universal/account/account.js +349 -365
  97. package/src/lib/universal/signer/signer.d.ts +2 -1
  98. package/src/lib/universal/signer/signer.js +315 -299
  99. package/src/lib/universal-tx-detector/auto-detect.js +55 -60
  100. package/src/lib/universal-tx-detector/cascade.js +160 -172
  101. package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
  102. package/src/lib/universal-tx-detector/classify.js +2 -3
  103. package/src/lib/universal-tx-detector/detector-svm.js +139 -147
  104. package/src/lib/universal-tx-detector/detector.js +145 -157
  105. package/src/lib/universal-tx-detector/normalize.js +7 -7
  106. package/src/lib/utils/external-tx-hash.js +1 -2
  107. package/src/lib/utils.d.ts +44 -0
  108. package/src/lib/utils.js +762 -683
  109. package/src/lib/vm-client/evm-client.js +186 -202
  110. package/src/lib/vm-client/svm-client.d.ts +1 -1
  111. package/src/lib/vm-client/svm-client.js +220 -224
  112. package/src/lib/vm-client/vm-client.types.d.ts +14 -2
@@ -26,6 +26,10 @@ export declare const SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS: bigint;
26
26
  export declare const SVM_EXECUTED_SUB_TX_RENT_FALLBACK: bigint;
27
27
  /** Devnet/mainnet rent-exempt minimum for a 165-byte SPL token account. */
28
28
  export declare const SVM_TOKEN_ACCOUNT_RENT_FALLBACK: bigint;
29
+ /** Rent-exempt minimum for an 82-byte SPL mint — created on a first PC20 export. */
30
+ export declare const SVM_MINT_RENT_FALLBACK: bigint;
31
+ /** Rent-exempt minimum for the 62-byte Pc20State PDA (state.rs: 8+20+32+1+1). */
32
+ export declare const SVM_PC20_STATE_RENT_FALLBACK: bigint;
29
33
  /** Back-compat export for older tests/callers: ATA rent + base finalization overhead. */
30
34
  export declare const CEA_ATA_RENT_LAMPORTS_BUMP: bigint;
31
35
  /** Derive CEA PDA from a 20-byte EVM address. Seeds: ["push_identity", evmBytes]. */
@@ -50,10 +54,14 @@ export interface SvmFinalizeGasBudgetInput {
50
54
  splMintBase58: string | undefined;
51
55
  /** Burn amount in token units. 0 means no SPL staging. */
52
56
  burnAmount: bigint;
57
+ /** PC20 export: use the id=5 finalize rent profile instead of the SPL one. */
58
+ pc20?: {
59
+ isFirstExport: boolean;
60
+ };
53
61
  }
54
62
  export declare function gasLimitForSvmGasFeeBudget(gasFeeBudget: bigint, gasPrice: bigint): bigint;
55
63
  type OutboundGasQuote = Awaited<ReturnType<typeof queryOutboundGasFee>>;
56
- export declare function ensureSvmFinalizeGasBudgetQuote({ ctx, ueaAddress, targetChain, prc20Token, quote, splMintBase58, burnAmount, pathTag, }: {
64
+ export declare function ensureSvmFinalizeGasBudgetQuote({ ctx, ueaAddress, targetChain, prc20Token, quote, splMintBase58, burnAmount, pathTag, pc20, requoteFn, }: {
57
65
  ctx: OrchestratorContext;
58
66
  ueaAddress: `0x${string}`;
59
67
  targetChain: ChainType;
@@ -62,6 +70,16 @@ export declare function ensureSvmFinalizeGasBudgetQuote({ ctx, ueaAddress, targe
62
70
  splMintBase58: string | undefined;
63
71
  burnAmount: bigint;
64
72
  pathTag: string;
73
+ /** PC20 export: switches the floor to the id=5 rent profile. */
74
+ pc20?: {
75
+ isFirstExport: boolean;
76
+ };
77
+ /**
78
+ * Re-quote function for the bump path. PC20 exports MUST pass one backed by
79
+ * getPC20ExportGasAndFees — the default getOutboundTxGasAndFees reverts for a
80
+ * PC20 token, which has no PRC20 config.
81
+ */
82
+ requoteFn?: (gasLimit: bigint) => Promise<OutboundGasQuote>;
65
83
  }): Promise<OutboundGasQuote>;
66
84
  /**
67
85
  * Returns the minimum SVM `gas_fee` budget in lamports for the gateway
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CEA_ATA_RENT_LAMPORTS_BUMP = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK = exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK = exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS = exports.SVM_SIGNATURE_FEE_LAMPORTS = void 0;
3
+ exports.CEA_ATA_RENT_LAMPORTS_BUMP = exports.SVM_PC20_STATE_RENT_FALLBACK = exports.SVM_MINT_RENT_FALLBACK = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK = exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK = exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS = exports.SVM_SIGNATURE_FEE_LAMPORTS = void 0;
4
4
  exports.deriveSvmCeaPda = deriveSvmCeaPda;
5
5
  exports.deriveAtaPubkey = deriveAtaPubkey;
6
6
  exports.gasLimitForSvmGasFeeBudget = gasLimitForSvmGasFeeBudget;
7
7
  exports.ensureSvmFinalizeGasBudgetQuote = ensureSvmFinalizeGasBudgetQuote;
8
8
  exports.getSvmFinalizeGasBudget = getSvmFinalizeGasBudget;
9
9
  exports.maybeBumpForCeaAtaRent = maybeBumpForCeaAtaRent;
10
- const tslib_1 = require("tslib");
11
10
  /**
12
11
  * SVM finalize gas-budget helpers.
13
12
  *
@@ -34,13 +33,17 @@ const gas_calculator_1 = require("./gas-calculator");
34
33
  // they only change if Solana itself adjusts rent rates (effectively never).
35
34
  // ---------------------------------------------------------------------------
36
35
  /** Base Solana fee per relayer signature, mirrored from SVM gateway execute.rs. */
37
- exports.SVM_SIGNATURE_FEE_LAMPORTS = BigInt(5000);
36
+ exports.SVM_SIGNATURE_FEE_LAMPORTS = BigInt(5_000);
38
37
  /** Operational buffer used by SVM gateway tests for tx fees / compute. */
39
- exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS = BigInt(100000);
38
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS = BigInt(100_000);
40
39
  /** Devnet/mainnet rent-exempt minimum for ExecutedSubTx::LEN = 8 bytes. */
41
- exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK = BigInt(946560);
40
+ exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK = BigInt(946_560);
42
41
  /** Devnet/mainnet rent-exempt minimum for a 165-byte SPL token account. */
43
- exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK = BigInt(2039280);
42
+ exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK = BigInt(2_039_280);
43
+ /** Rent-exempt minimum for an 82-byte SPL mint — created on a first PC20 export. */
44
+ exports.SVM_MINT_RENT_FALLBACK = BigInt(1_461_600);
45
+ /** Rent-exempt minimum for the 62-byte Pc20State PDA (state.rs: 8+20+32+1+1). */
46
+ exports.SVM_PC20_STATE_RENT_FALLBACK = BigInt(1_322_400);
44
47
  /** Back-compat export for older tests/callers: ATA rent + base finalization overhead. */
45
48
  exports.CEA_ATA_RENT_LAMPORTS_BUMP = exports.SVM_SIGNATURE_FEE_LAMPORTS +
46
49
  exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK +
@@ -50,7 +53,7 @@ exports.CEA_ATA_RENT_LAMPORTS_BUMP = exports.SVM_SIGNATURE_FEE_LAMPORTS +
50
53
  const SVM_GATEWAY_PROGRAM = new web3_js_1.PublicKey('CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS');
51
54
  const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
52
55
  const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
53
- const SVM_RENT_RPC_TIMEOUT_MS = 3000;
56
+ const SVM_RENT_RPC_TIMEOUT_MS = 3_000;
54
57
  // ---------------------------------------------------------------------------
55
58
  // PDA derivations
56
59
  // ---------------------------------------------------------------------------
@@ -66,30 +69,27 @@ function deriveAtaPubkey(owner, mint) {
66
69
  return ata;
67
70
  }
68
71
  function getRpcUrl(ctx, targetChain) {
69
- var _a, _b, _c, _d, _e;
70
- return ((_c = (_b = (_a = ctx.rpcUrls) === null || _a === void 0 ? void 0 : _a[targetChain]) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : (_e = (_d = chain_1.CHAIN_INFO[targetChain]) === null || _d === void 0 ? void 0 : _d.defaultRPC) === null || _e === void 0 ? void 0 : _e[0]);
72
+ return (ctx.rpcUrls?.[targetChain]?.[0] ??
73
+ chain_1.CHAIN_INFO[targetChain]?.defaultRPC?.[0]);
71
74
  }
72
75
  function isAccountInitialized(info) {
73
76
  return info !== null && info.data.length > 0;
74
77
  }
75
- function withSvmRentRpcTimeout(promise, label) {
76
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
77
- let timer;
78
- try {
79
- return yield Promise.race([
80
- promise,
81
- new Promise((_, reject) => {
82
- var _a, _b;
83
- timer = setTimeout(() => reject(new Error(`${label} timed out after ${SVM_RENT_RPC_TIMEOUT_MS}ms`)), SVM_RENT_RPC_TIMEOUT_MS);
84
- (_b = (_a = timer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
85
- }),
86
- ]);
87
- }
88
- finally {
89
- if (timer)
90
- clearTimeout(timer);
91
- }
92
- });
78
+ async function withSvmRentRpcTimeout(promise, label) {
79
+ let timer;
80
+ try {
81
+ return await Promise.race([
82
+ promise,
83
+ new Promise((_, reject) => {
84
+ timer = setTimeout(() => reject(new Error(`${label} timed out after ${SVM_RENT_RPC_TIMEOUT_MS}ms`)), SVM_RENT_RPC_TIMEOUT_MS);
85
+ timer.unref?.();
86
+ }),
87
+ ]);
88
+ }
89
+ finally {
90
+ if (timer)
91
+ clearTimeout(timer);
92
+ }
93
93
  }
94
94
  function gasLimitForSvmGasFeeBudget(gasFeeBudget, gasPrice) {
95
95
  if (gasPrice <= BigInt(0)) {
@@ -103,99 +103,123 @@ function resolveSvmGasLimitUsed(quote) {
103
103
  quote.gasPrice <= BigInt(0)) {
104
104
  return quote;
105
105
  }
106
- return Object.assign(Object.assign({}, quote), { gasLimitUsed: gasLimitForSvmGasFeeBudget(quote.gasFee, quote.gasPrice) });
106
+ return {
107
+ ...quote,
108
+ gasLimitUsed: gasLimitForSvmGasFeeBudget(quote.gasFee, quote.gasPrice),
109
+ };
107
110
  }
108
- function ensureSvmFinalizeGasBudgetQuote(_a) {
109
- return tslib_1.__awaiter(this, arguments, void 0, function* ({ ctx, ueaAddress, targetChain, prc20Token, quote, splMintBase58, burnAmount, pathTag, }) {
110
- const minGasFee = yield getSvmFinalizeGasBudget({
111
- ctx,
112
- ueaAddress,
113
- targetChain,
114
- splMintBase58,
115
- burnAmount,
116
- });
117
- if (quote.gasFee >= minGasFee) {
118
- const resolvedQuote = resolveSvmGasLimitUsed(quote);
119
- (0, context_1.printLog)(ctx, `${pathTag} — SVM finalize gas budget ok: gasFee=${resolvedQuote.gasFee.toString()}, ` +
120
- `minimum=${minGasFee.toString()}, gasLimit=${resolvedQuote.gasLimitUsed.toString()}`);
121
- return resolvedQuote;
122
- }
123
- const bumpedGasLimit = gasLimitForSvmGasFeeBudget(minGasFee, quote.gasPrice);
124
- (0, context_1.printLog)(ctx, `${pathTag} — bumping SVM gasLimit ${quote.gasLimitUsed.toString()} → ${bumpedGasLimit.toString()}; ` +
125
- `gasFee=${quote.gasFee.toString()} below finalize minimum=${minGasFee.toString()}`);
126
- const bumpedQuote = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, bumpedGasLimit, targetChain);
127
- if (bumpedQuote.gasFee < minGasFee) {
128
- (0, context_1.printLog)(ctx, `${pathTag} — WARNING: bumped SVM gasFee=${bumpedQuote.gasFee.toString()} ` +
129
- `still below finalize minimum=${minGasFee.toString()}`);
130
- }
131
- return resolveSvmGasLimitUsed(bumpedQuote);
111
+ async function ensureSvmFinalizeGasBudgetQuote({ ctx, ueaAddress, targetChain, prc20Token, quote, splMintBase58, burnAmount, pathTag, pc20, requoteFn, }) {
112
+ const minGasFee = await getSvmFinalizeGasBudget({
113
+ ctx,
114
+ ueaAddress,
115
+ targetChain,
116
+ splMintBase58,
117
+ burnAmount,
118
+ pc20,
132
119
  });
120
+ if (quote.gasFee >= minGasFee) {
121
+ const resolvedQuote = resolveSvmGasLimitUsed(quote);
122
+ (0, context_1.printLog)(ctx, `${pathTag} — SVM finalize gas budget ok: gasFee=${resolvedQuote.gasFee.toString()}, ` +
123
+ `minimum=${minGasFee.toString()}, gasLimit=${resolvedQuote.gasLimitUsed.toString()}`);
124
+ return resolvedQuote;
125
+ }
126
+ const bumpedGasLimit = gasLimitForSvmGasFeeBudget(minGasFee, quote.gasPrice);
127
+ (0, context_1.printLog)(ctx, `${pathTag} — bumping SVM gasLimit ${quote.gasLimitUsed.toString()} → ${bumpedGasLimit.toString()}; ` +
128
+ `gasFee=${quote.gasFee.toString()} below finalize minimum=${minGasFee.toString()}`);
129
+ const bumpedQuote = requoteFn
130
+ ? await requoteFn(bumpedGasLimit)
131
+ : await (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, bumpedGasLimit, targetChain);
132
+ if (bumpedQuote.gasFee < minGasFee) {
133
+ (0, context_1.printLog)(ctx, `${pathTag} — WARNING: bumped SVM gasFee=${bumpedQuote.gasFee.toString()} ` +
134
+ `still below finalize minimum=${minGasFee.toString()}`);
135
+ }
136
+ return resolveSvmGasLimitUsed(bumpedQuote);
133
137
  }
134
138
  /**
135
139
  * Returns the minimum SVM `gas_fee` budget in lamports for the gateway
136
140
  * finalize instruction, including a small compute buffer. If RPC is not
137
141
  * available, falls back to Solana protocol rent constants.
138
142
  */
139
- function getSvmFinalizeGasBudget(input) {
140
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
141
- const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount } = input;
142
- const needsSplAta = Boolean(splMintBase58) && burnAmount > BigInt(0);
143
- const rpcUrl = getRpcUrl(ctx, targetChain);
144
- let executedTxRent = exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK;
145
- let ataRent = BigInt(0);
146
- if (!needsSplAta) {
147
- const budget = exports.SVM_SIGNATURE_FEE_LAMPORTS +
148
- executedTxRent +
149
- ataRent +
150
- exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
151
- (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — no SPL ATA needed for ${targetChain}; ` +
152
- `using fallback base budget ${budget.toString()}`);
153
- return budget;
154
- }
155
- if (!rpcUrl) {
156
- ataRent = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK;
157
- (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — no Solana RPC URL for ${targetChain}; ` +
158
- `using fallback budget ${(exports.SVM_SIGNATURE_FEE_LAMPORTS +
159
- executedTxRent +
160
- ataRent +
161
- exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS).toString()}`);
162
- return (exports.SVM_SIGNATURE_FEE_LAMPORTS +
163
- executedTxRent +
164
- ataRent +
165
- exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS);
166
- }
167
- try {
168
- const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
169
- executedTxRent = BigInt(yield withSvmRentRpcTimeout(conn.getMinimumBalanceForRentExemption(8), 'getMinimumBalanceForRentExemption(8)'));
170
- if (needsSplAta && splMintBase58) {
171
- const ceaPda = deriveSvmCeaPda(ueaAddress);
172
- const splMint = new web3_js_1.PublicKey(splMintBase58);
173
- const ceaAta = deriveAtaPubkey(ceaPda, splMint);
174
- const info = yield withSvmRentRpcTimeout(conn.getAccountInfo(ceaAta), `getAccountInfo(${ceaAta.toBase58()})`);
175
- if (!isAccountInitialized(info)) {
176
- ataRent = BigInt(yield withSvmRentRpcTimeout(conn.getMinimumBalanceForRentExemption(165), 'getMinimumBalanceForRentExemption(165)'));
177
- (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — CEA ATA ${ceaAta.toBase58()} not deployed on ${targetChain}; ` +
178
- `including ${ataRent.toString()} lamports ATA rent`);
179
- }
180
- else {
181
- (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — CEA ATA ${ceaAta.toBase58()} already deployed on ${targetChain}; no ATA rent`);
182
- }
183
- }
184
- }
185
- catch (err) {
186
- ataRent = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK;
187
- (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — RPC error on ${targetChain}: ` +
188
- `${err instanceof Error ? err.message : String(err)}; using fallback rents`);
143
+ async function getSvmFinalizeGasBudget(input) {
144
+ const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount, pc20 } = input;
145
+ const needsSplAta = Boolean(splMintBase58) && burnAmount > BigInt(0);
146
+ // PC20 export finalize (id=5) has its own rent profile — settle_pc20_finalize_gas
147
+ // (pc20.rs) requires gas_fee to cover, beyond the base costs:
148
+ // - CEA ATA rent for the *wrapper mint* (created at settlement);
149
+ // - on a first export, the mint account (82B) and Pc20State PDA (62B) rents.
150
+ // The on-chain quote does not know about Solana rent, so without this floor a
151
+ // first export reverts InsufficientGasBudget on the destination — after the
152
+ // source token is locked. Fallback constants are used rather than RPC reads:
153
+ // the mint does not exist yet on a first export, so there is nothing to query,
154
+ // and rent-exempt minimums are Solana protocol values that effectively never
155
+ // change.
156
+ if (pc20) {
157
+ let budget = exports.SVM_SIGNATURE_FEE_LAMPORTS +
158
+ exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK +
159
+ exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK + // CEA ATA for the wrapper mint
160
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
161
+ if (pc20.isFirstExport) {
162
+ budget += exports.SVM_MINT_RENT_FALLBACK + exports.SVM_PC20_STATE_RENT_FALLBACK;
189
163
  }
164
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — PC20 budget=${budget.toString()} ` +
165
+ `(isFirstExport=${pc20.isFirstExport})`);
166
+ return budget;
167
+ }
168
+ const rpcUrl = getRpcUrl(ctx, targetChain);
169
+ let executedTxRent = exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK;
170
+ let ataRent = BigInt(0);
171
+ if (!needsSplAta) {
190
172
  const budget = exports.SVM_SIGNATURE_FEE_LAMPORTS +
191
173
  executedTxRent +
192
174
  ataRent +
193
175
  exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
194
- (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — budget=${budget.toString()} ` +
195
- `(signature=${exports.SVM_SIGNATURE_FEE_LAMPORTS}, executedTxRent=${executedTxRent}, ataRent=${ataRent}, ` +
196
- `computeBuffer=${exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS})`);
176
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — no SPL ATA needed for ${targetChain}; ` +
177
+ `using fallback base budget ${budget.toString()}`);
197
178
  return budget;
198
- });
179
+ }
180
+ if (!rpcUrl) {
181
+ ataRent = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK;
182
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — no Solana RPC URL for ${targetChain}; ` +
183
+ `using fallback budget ${(exports.SVM_SIGNATURE_FEE_LAMPORTS +
184
+ executedTxRent +
185
+ ataRent +
186
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS).toString()}`);
187
+ return (exports.SVM_SIGNATURE_FEE_LAMPORTS +
188
+ executedTxRent +
189
+ ataRent +
190
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS);
191
+ }
192
+ try {
193
+ const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
194
+ executedTxRent = BigInt(await withSvmRentRpcTimeout(conn.getMinimumBalanceForRentExemption(8), 'getMinimumBalanceForRentExemption(8)'));
195
+ if (needsSplAta && splMintBase58) {
196
+ const ceaPda = deriveSvmCeaPda(ueaAddress);
197
+ const splMint = new web3_js_1.PublicKey(splMintBase58);
198
+ const ceaAta = deriveAtaPubkey(ceaPda, splMint);
199
+ const info = await withSvmRentRpcTimeout(conn.getAccountInfo(ceaAta), `getAccountInfo(${ceaAta.toBase58()})`);
200
+ if (!isAccountInitialized(info)) {
201
+ ataRent = BigInt(await withSvmRentRpcTimeout(conn.getMinimumBalanceForRentExemption(165), 'getMinimumBalanceForRentExemption(165)'));
202
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — CEA ATA ${ceaAta.toBase58()} not deployed on ${targetChain}; ` +
203
+ `including ${ataRent.toString()} lamports ATA rent`);
204
+ }
205
+ else {
206
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — CEA ATA ${ceaAta.toBase58()} already deployed on ${targetChain}; no ATA rent`);
207
+ }
208
+ }
209
+ }
210
+ catch (err) {
211
+ ataRent = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK;
212
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — RPC error on ${targetChain}: ` +
213
+ `${err instanceof Error ? err.message : String(err)}; using fallback rents`);
214
+ }
215
+ const budget = exports.SVM_SIGNATURE_FEE_LAMPORTS +
216
+ executedTxRent +
217
+ ataRent +
218
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
219
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — budget=${budget.toString()} ` +
220
+ `(signature=${exports.SVM_SIGNATURE_FEE_LAMPORTS}, executedTxRent=${executedTxRent}, ataRent=${ataRent}, ` +
221
+ `computeBuffer=${exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS})`);
222
+ return budget;
199
223
  }
200
224
  /**
201
225
  * Returns the (possibly bumped) effectiveGasLimit. Logs the decision via
@@ -203,41 +227,39 @@ function getSvmFinalizeGasBudget(input) {
203
227
  * the input unchanged — better to risk one underflow than to block all SPL
204
228
  * outbounds on RPC flake; pre-flight will surface insufficient gas anyway.
205
229
  */
206
- function maybeBumpForCeaAtaRent(input) {
207
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
208
- const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount, effectiveGasLimit, } = input;
209
- // Only applies to SPL outbounds. Native SOL outbounds use the gateway's
210
- // calculateSolExecuteFees which has no ATA conditional.
211
- if (!splMintBase58 || burnAmount === BigInt(0)) {
212
- return effectiveGasLimit;
213
- }
214
- const rpcUrl = getRpcUrl(ctx, targetChain);
215
- if (!rpcUrl) {
216
- (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — no Solana RPC URL for ${targetChain}; skipping rent bump`);
217
- return effectiveGasLimit;
218
- }
219
- try {
220
- const ceaPda = deriveSvmCeaPda(ueaAddress);
221
- const splMint = new web3_js_1.PublicKey(splMintBase58);
222
- const ceaAta = deriveAtaPubkey(ceaPda, splMint);
223
- const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
224
- const info = yield withSvmRentRpcTimeout(conn.getAccountInfo(ceaAta), `getAccountInfo(${ceaAta.toBase58()})`);
225
- const ataExists = info !== null && info.data.length > 0;
226
- if (!ataExists) {
227
- const bumped = effectiveGasLimit + exports.CEA_ATA_RENT_LAMPORTS_BUMP;
228
- (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — CEA ATA ${ceaAta.toBase58()} not deployed on ${targetChain}; ` +
229
- `bumping effectiveGasLimit ${effectiveGasLimit} → ${bumped} ` +
230
- `(+${exports.CEA_ATA_RENT_LAMPORTS_BUMP} lamports for ATA rent + exec rent + compute buffer)`);
231
- return bumped;
232
- }
233
- (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — CEA ATA ${ceaAta.toBase58()} already deployed on ${targetChain}; no rent bump`);
234
- return effectiveGasLimit;
235
- }
236
- catch (err) {
237
- (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — RPC error querying CEA ATA on ${targetChain}: ` +
238
- `${err instanceof Error ? err.message : String(err)}; proceeding without bump`);
239
- return effectiveGasLimit;
230
+ async function maybeBumpForCeaAtaRent(input) {
231
+ const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount, effectiveGasLimit, } = input;
232
+ // Only applies to SPL outbounds. Native SOL outbounds use the gateway's
233
+ // calculateSolExecuteFees which has no ATA conditional.
234
+ if (!splMintBase58 || burnAmount === BigInt(0)) {
235
+ return effectiveGasLimit;
236
+ }
237
+ const rpcUrl = getRpcUrl(ctx, targetChain);
238
+ if (!rpcUrl) {
239
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — no Solana RPC URL for ${targetChain}; skipping rent bump`);
240
+ return effectiveGasLimit;
241
+ }
242
+ try {
243
+ const ceaPda = deriveSvmCeaPda(ueaAddress);
244
+ const splMint = new web3_js_1.PublicKey(splMintBase58);
245
+ const ceaAta = deriveAtaPubkey(ceaPda, splMint);
246
+ const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
247
+ const info = await withSvmRentRpcTimeout(conn.getAccountInfo(ceaAta), `getAccountInfo(${ceaAta.toBase58()})`);
248
+ const ataExists = info !== null && info.data.length > 0;
249
+ if (!ataExists) {
250
+ const bumped = effectiveGasLimit + exports.CEA_ATA_RENT_LAMPORTS_BUMP;
251
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — CEA ATA ${ceaAta.toBase58()} not deployed on ${targetChain}; ` +
252
+ `bumping effectiveGasLimit ${effectiveGasLimit} → ${bumped} ` +
253
+ `(+${exports.CEA_ATA_RENT_LAMPORTS_BUMP} lamports for ATA rent + exec rent + compute buffer)`);
254
+ return bumped;
240
255
  }
241
- });
256
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — CEA ATA ${ceaAta.toBase58()} already deployed on ${targetChain}; no rent bump`);
257
+ return effectiveGasLimit;
258
+ }
259
+ catch (err) {
260
+ (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — RPC error querying CEA ATA on ${targetChain}: ` +
261
+ `${err instanceof Error ? err.message : String(err)}; proceeding without bump`);
262
+ return effectiveGasLimit;
263
+ }
242
264
  }
243
265
  //# sourceMappingURL=svm-rent.js.map
@@ -50,11 +50,10 @@ function transformToUniversalTxReceipt(receipt, originalTxResponse) {
50
50
  // Progress Event Reconstruction
51
51
  // ============================================================================
52
52
  function reconstructProgressEvents(universalTxResponse, universalTxData) {
53
- var _a, _b, _c;
54
53
  const route = universalTxResponse.route;
55
- const pcTx = (_a = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.pcTx) === null || _a === void 0 ? void 0 : _a[0];
56
- const isOutboundFailed = (universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.universalStatus) === types_1.UniversalTxStatus.OUTBOUND_FAILED;
57
- const isPcFailed = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.status) === 'FAILED';
54
+ const pcTx = universalTxData?.pcTx?.[0];
55
+ const isOutboundFailed = universalTxData?.universalStatus === types_1.UniversalTxStatus.OUTBOUND_FAILED;
56
+ const isPcFailed = pcTx?.status === 'FAILED';
58
57
  // R1 fallback keeps the inclusive view (any terminal failure → 199-02).
59
58
  // R2 and R3 reconstructors narrow to Push-chain-only failures (see call
60
59
  // sites below) — an outbound-leg revert is re-detected during wait() by
@@ -62,7 +61,7 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
62
61
  // scoped phase ('outbound' + source-chain). Emitting in both places
63
62
  // would double-fire the terminal with a misleading 'push' title on top.
64
63
  const isFailed = isPcFailed || isOutboundFailed;
65
- const pcErrorMsg = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg)
64
+ const pcErrorMsg = pcTx?.errorMsg
66
65
  ? (0, formatters_1.normalizePcInsufficientFundsError)(pcTx.errorMsg)
67
66
  : 'Unknown error';
68
67
  const errorMsg = isOutboundFailed
@@ -82,7 +81,7 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
82
81
  // carries one UniversalTx with multiple outboundTx entries; wrap the
83
82
  // per-leg R2/R3 backbones with the SEND-TX-001 / 002-xx / 999-xx markers
84
83
  // so replay parity matches live cascade emission.
85
- if (((_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 1) {
84
+ if ((universalTxData?.outboundTx?.length ?? 0) > 1) {
86
85
  return reconstructMultichain(universalTxResponse, universalTxData, isFailed, errorMsg);
87
86
  }
88
87
  if (route === route_detector_1.TransactionRoute.UOA_TO_CEA) {
@@ -132,10 +131,9 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
132
131
  return events;
133
132
  }
134
133
  function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg) {
135
- var _a, _b, _c, _d, _e, _f, _g;
136
134
  const events = [];
137
- const targetChain = ((_a = universalTxResponse.chain) !== null && _a !== void 0 ? _a : 'external');
138
- const targetAddress = (_d = (_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.recipient) !== null && _d !== void 0 ? _d : universalTxResponse.to;
135
+ const targetChain = (universalTxResponse.chain ?? 'external');
136
+ const targetAddress = universalTxData?.outboundTx?.[0]?.recipient ?? universalTxResponse.to;
139
137
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_201](targetChain, targetAddress));
140
138
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_202_01](targetChain));
141
139
  // Reconstruction: gas split unavailable from historical data — pass zeroes
@@ -151,7 +149,7 @@ function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg)
151
149
  // had a non-zero burn amount (proxy for "user supplied funds.amount > 0").
152
150
  // Values are zero-placeholders matching the existing 202-02 pattern.
153
151
  const ueaFrom = universalTxResponse.from;
154
- const burnAmount = BigInt((_g = (_f = (_e = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.amount) !== null && _g !== void 0 ? _g : '0');
152
+ const burnAmount = BigInt(universalTxData?.outboundTx?.[0]?.amount ?? '0');
155
153
  if (burnAmount > BigInt(0)) {
156
154
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_03](BigInt(0), BigInt(0), true, ueaFrom, 'R2_EVM', { kind: 'PRC20' }));
157
155
  }
@@ -166,10 +164,9 @@ function reconstructR2(universalTxResponse, universalTxData, isFailed, errorMsg)
166
164
  return events;
167
165
  }
168
166
  function reconstructR3(universalTxResponse, universalTxData, isFailed, errorMsg) {
169
- var _a, _b, _c, _d;
170
167
  const events = [];
171
- const sourceChain = ((_a = universalTxResponse.chain) !== null && _a !== void 0 ? _a : 'source');
172
- const ceaAddress = (_d = (_c = (_b = universalTxData === null || universalTxData === void 0 ? void 0 : universalTxData.outboundTx) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.recipient) !== null && _d !== void 0 ? _d : universalTxResponse.to;
168
+ const sourceChain = (universalTxResponse.chain ?? 'source');
169
+ const ceaAddress = universalTxData?.outboundTx?.[0]?.recipient ?? universalTxResponse.to;
173
170
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_301](sourceChain, ceaAddress));
174
171
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_01](sourceChain));
175
172
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_02](sourceChain, BigInt(0), BigInt(0)));
@@ -205,7 +202,7 @@ function decodeUeaMulticall(data) {
205
202
  const [tuples] = (0, viem_1.decodeAbiParameters)([payload_builders_1.MULTICALL_TUPLE_TYPE], body);
206
203
  return tuples;
207
204
  }
208
- catch (_a) {
205
+ catch {
209
206
  return null;
210
207
  }
211
208
  }
@@ -260,14 +257,13 @@ function decodeR3MergedInnerCount(outboundPayload) {
260
257
  if (pushCalls)
261
258
  return pushCalls.length;
262
259
  }
263
- catch (_a) {
260
+ catch {
264
261
  // fall through to next outer call
265
262
  }
266
263
  }
267
264
  return 0;
268
265
  }
269
266
  function reconstructMultichain(universalTxResponse, universalTxData, isFailed, errorMsg) {
270
- var _a, _b, _c, _d, _e;
271
267
  const events = [];
272
268
  const outbounds = universalTxData.outboundTx;
273
269
  // Merged-R1 recovery: each R3 outbound's payload embeds the
@@ -310,7 +306,6 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
310
306
  let failedAt = null;
311
307
  let failureMsg = errorMsg;
312
308
  outbounds.forEach((ob, i) => {
313
- var _a, _b;
314
309
  const hopNum = i + 1;
315
310
  const fromChain = i === 0 ? sourceChain : outbounds[i - 1].destinationChain;
316
311
  const toChain = ob.destinationChain;
@@ -318,12 +313,19 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
318
313
  // Build a single-leg view so the per-leg reconstructors (R2/R3) emit
319
314
  // their usual backbone. We narrow `outboundTx` to this leg so any field
320
315
  // reads (e.g. `outboundTx[0].recipient`) resolve to this leg's data.
321
- const legResponse = Object.assign(Object.assign({}, universalTxResponse), { chain: toChain, chainNamespace: toChain });
322
- const legData = Object.assign(Object.assign({}, universalTxData), { outboundTx: [ob] });
316
+ const legResponse = {
317
+ ...universalTxResponse,
318
+ chain: toChain,
319
+ chainNamespace: toChain,
320
+ };
321
+ const legData = {
322
+ ...universalTxData,
323
+ outboundTx: [ob],
324
+ };
323
325
  const payload = (ob.payload || '').toLowerCase();
324
326
  const isR3Leg = payload.includes(SEND_UNIVERSAL_TX_TO_UEA_SELECTOR);
325
327
  const legFailed = ob.outboundStatus === types_2.OutboundStatus.REVERTED;
326
- const legError = ob.abortReason || ((_a = ob.observedTx) === null || _a === void 0 ? void 0 : _a.errorMsg) || 'leg execution failed';
328
+ const legError = ob.abortReason || ob.observedTx?.errorMsg || 'leg execution failed';
327
329
  if (isR3Leg) {
328
330
  events.push(...reconstructR3(legResponse, legData, legFailed, legError));
329
331
  }
@@ -332,7 +334,7 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
332
334
  }
333
335
  if (!legFailed) {
334
336
  if (hopNum < hopCount) {
335
- const txHash = ((_b = ob.observedTx) === null || _b === void 0 ? void 0 : _b.txHash) || legResponse.hash;
337
+ const txHash = ob.observedTx?.txHash || legResponse.hash;
336
338
  events.push(isR3Leg
337
339
  ? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_399_99](toChain, txHash)
338
340
  : progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_299_99](toChain, txHash));
@@ -344,9 +346,10 @@ function reconstructMultichain(universalTxResponse, universalTxData, isFailed, e
344
346
  failureMsg = legError;
345
347
  }
346
348
  });
347
- const finalObservedTxHash = (_c = (_b = (_a = [...outbounds].reverse().find((ob) => { var _a; return (_a = ob.observedTx) === null || _a === void 0 ? void 0 : _a.txHash; })) === null || _a === void 0 ? void 0 : _a.observedTx) === null || _b === void 0 ? void 0 : _b.txHash) !== null && _c !== void 0 ? _c : universalTxResponse.hash;
349
+ const finalObservedTxHash = [...outbounds].reverse().find((ob) => ob.observedTx?.txHash)?.observedTx
350
+ ?.txHash ?? universalTxResponse.hash;
348
351
  const failedObservedTxHash = failedAt !== null
349
- ? (_e = (_d = outbounds[failedAt - 1]) === null || _d === void 0 ? void 0 : _d.observedTx) === null || _e === void 0 ? void 0 : _e.txHash
352
+ ? outbounds[failedAt - 1]?.observedTx?.txHash
350
353
  : undefined;
351
354
  if (failedAt !== null) {
352
355
  events.push(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_999_02](failedAt, hopCount, failureMsg, failedObservedTxHash, universalTxResponse.hash));