@pushchain/core 5.1.18 → 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.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/src/lib/constants/abi/cea.evm.d.ts +52 -0
  3. package/src/lib/constants/abi/cea.evm.js +66 -1
  4. package/src/lib/constants/abi/prc20.evm.d.ts +117 -11
  5. package/src/lib/constants/abi/prc20.evm.js +38 -11
  6. package/src/lib/constants/abi/uea.evm.js +41 -0
  7. package/src/lib/constants/abi/universalGatewayPC.evm.d.ts +117 -1
  8. package/src/lib/constants/abi/universalGatewayPC.evm.js +40 -1
  9. package/src/lib/constants/abi/universalGatewayV0.json +1 -1
  10. package/src/lib/constants/chain.js +14 -14
  11. package/src/lib/constants/tokens.js +1 -0
  12. package/src/lib/formatters.d.ts +6 -0
  13. package/src/lib/formatters.js +14 -0
  14. package/src/lib/index.d.ts +2 -0
  15. package/src/lib/index.js +7 -1
  16. package/src/lib/orchestrator/internals/cascade.js +139 -81
  17. package/src/lib/orchestrator/internals/errors.js +1 -1
  18. package/src/lib/orchestrator/internals/execute-funds-only.js +3 -2
  19. package/src/lib/orchestrator/internals/execute-funds-payload.js +2 -1
  20. package/src/lib/orchestrator/internals/execute-standard.js +4 -4
  21. package/src/lib/orchestrator/internals/gas-calculator.d.ts +1 -0
  22. package/src/lib/orchestrator/internals/gas-calculator.js +13 -11
  23. package/src/lib/orchestrator/internals/helpers.js +1 -0
  24. package/src/lib/orchestrator/internals/inbound-tracker.js +4 -2
  25. package/src/lib/orchestrator/internals/outbound-sync.js +73 -60
  26. package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +1 -1
  27. package/src/lib/orchestrator/internals/pc-usd-oracle.js +4 -3
  28. package/src/lib/orchestrator/internals/push-chain-tx.js +5 -1
  29. package/src/lib/orchestrator/internals/route-handlers.js +155 -185
  30. package/src/lib/orchestrator/internals/signing.js +7 -2
  31. package/src/lib/orchestrator/internals/svm-helpers.js +3 -3
  32. package/src/lib/orchestrator/internals/svm-rent.d.ts +42 -9
  33. package/src/lib/orchestrator/internals/svm-rent.js +148 -14
  34. package/src/lib/orchestrator/internals/tx-transformer.js +5 -2
  35. package/src/lib/orchestrator/max-pc-for-gas.d.ts +60 -0
  36. package/src/lib/orchestrator/max-pc-for-gas.js +66 -0
  37. package/src/lib/orchestrator/orchestrator.d.ts +1 -0
  38. package/src/lib/orchestrator/orchestrator.types.d.ts +31 -9
  39. package/src/lib/orchestrator/payload-builders.d.ts +7 -6
  40. package/src/lib/orchestrator/payload-builders.js +18 -6
  41. package/src/lib/progress-hook/progress-hook.js +26 -18
  42. package/src/lib/universal-tx-detector/events.d.ts +3 -1
  43. package/src/lib/universal-tx-detector/events.js +3 -1
  44. package/src/lib/universal-tx-detector/svm-events.d.ts +1 -1
  45. package/src/lib/universal-tx-detector/svm-events.js +1 -1
@@ -82,7 +82,7 @@ function buildSvmUniversalTxRequestFromReq(req, revertRecipient, signatureDataOv
82
82
  // ============================================================================
83
83
  function getSvmProtocolFee(svmClient, programId) {
84
84
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
85
- var _a, _b, _c;
85
+ var _a, _b, _c, _d, _e;
86
86
  const [feeVaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('fee_vault')], programId);
87
87
  try {
88
88
  const feeVault = yield svmClient.readContract({
@@ -91,10 +91,10 @@ function getSvmProtocolFee(svmClient, programId) {
91
91
  functionName: 'feeVault',
92
92
  args: [feeVaultPda.toBase58()],
93
93
  });
94
- const protocolFeeLamports = BigInt((_c = (_b = ((_a = feeVault.protocolFeeLamports) !== null && _a !== void 0 ? _a : feeVault.protocol_fee_lamports)) === null || _b === void 0 ? void 0 : _b.toString()) !== null && _c !== void 0 ? _c : '0');
94
+ const protocolFeeLamports = BigInt((_e = (_d = ((_c = (_b = (_a = feeVault.inboundFeeLamports) !== null && _a !== void 0 ? _a : feeVault.inbound_fee_lamports) !== null && _b !== void 0 ? _b : feeVault.protocolFeeLamports) !== null && _c !== void 0 ? _c : feeVault.protocol_fee_lamports)) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : '0');
95
95
  return { feeVaultPda, protocolFeeLamports };
96
96
  }
97
- catch (_d) {
97
+ catch (_f) {
98
98
  return { feeVaultPda, protocolFeeLamports: BigInt(0) };
99
99
  }
100
100
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Conditional CEA-ATA rent bump for SVM SPL outbounds.
2
+ * SVM finalize gas-budget helpers.
3
3
  *
4
4
  * The gateway program (svm-gateway) computes per-tx fees with a conditional
5
5
  * rent for first-time SPL transfers — see `calculateSplExecuteFees` in
@@ -7,21 +7,26 @@
7
7
  *
8
8
  * const ataExists = await ceaAtaExists(connection, ceaAta);
9
9
  * const ceaAtaRent = ataExists ? 0n : BigInt(getMinimumBalanceForRentExemption(165));
10
- * gasFee = executedTxRent + ceaAtaRent + COMPUTE_BUFFER;
10
+ * gasFee = signatureFee + executedTxRent + ceaAtaRent + COMPUTE_BUFFER;
11
11
  *
12
12
  * The gateway's on-chain `getOutboundTxGasAndFees` quote does NOT factor in
13
13
  * the ATA rent today, so the SDK has to bump `effectiveGasLimit` itself
14
- * before calling that quote. Native-SOL outbounds use `calculateSolExecuteFees`
15
- * which has no conditional rent, so no SDK bump is needed there.
14
+ * before building the outbound request. Native-SOL outbounds still need the
15
+ * same base finalize budget plus compute buffer.
16
16
  */
17
17
  import { PublicKey } from '@solana/web3.js';
18
18
  import type { OrchestratorContext } from './context';
19
19
  import type { CHAIN as ChainType } from '../../constants/enums';
20
- /** ATA rent (165-byte SPL token account) + executed-tx rent (8-byte) + compute buffer.
21
- * Mirrors getMinimumBalanceForRentExemption(165) ≈ 2_039_280
22
- * + getMinimumBalanceForRentExemption(8) ≈ 9_200
23
- * + COMPUTE_BUFFER 100_000.
24
- * Signature fee (5_000) is already included in the gateway's base quote. */
20
+ import { queryOutboundGasFee } from './gas-calculator';
21
+ /** Base Solana fee per relayer signature, mirrored from SVM gateway execute.rs. */
22
+ export declare const SVM_SIGNATURE_FEE_LAMPORTS: bigint;
23
+ /** Operational buffer used by SVM gateway tests for tx fees / compute. */
24
+ export declare const SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS: bigint;
25
+ /** Devnet/mainnet rent-exempt minimum for ExecutedSubTx::LEN = 8 bytes. */
26
+ export declare const SVM_EXECUTED_SUB_TX_RENT_FALLBACK: bigint;
27
+ /** Devnet/mainnet rent-exempt minimum for a 165-byte SPL token account. */
28
+ export declare const SVM_TOKEN_ACCOUNT_RENT_FALLBACK: bigint;
29
+ /** Back-compat export for older tests/callers: ATA rent + base finalization overhead. */
25
30
  export declare const CEA_ATA_RENT_LAMPORTS_BUMP: bigint;
26
31
  /** Derive CEA PDA from a 20-byte EVM address. Seeds: ["push_identity", evmBytes]. */
27
32
  export declare function deriveSvmCeaPda(evmAddress: `0x${string}`): PublicKey;
@@ -37,6 +42,33 @@ export interface MaybeBumpInput {
37
42
  burnAmount: bigint;
38
43
  effectiveGasLimit: bigint;
39
44
  }
45
+ export interface SvmFinalizeGasBudgetInput {
46
+ ctx: OrchestratorContext;
47
+ ueaAddress: `0x${string}`;
48
+ targetChain: ChainType;
49
+ /** SPL mint as base58. undefined means native SOL / no SPL staging. */
50
+ splMintBase58: string | undefined;
51
+ /** Burn amount in token units. 0 means no SPL staging. */
52
+ burnAmount: bigint;
53
+ }
54
+ export declare function gasLimitForSvmGasFeeBudget(gasFeeBudget: bigint, gasPrice: bigint): bigint;
55
+ type OutboundGasQuote = Awaited<ReturnType<typeof queryOutboundGasFee>>;
56
+ export declare function ensureSvmFinalizeGasBudgetQuote({ ctx, ueaAddress, targetChain, prc20Token, quote, splMintBase58, burnAmount, pathTag, }: {
57
+ ctx: OrchestratorContext;
58
+ ueaAddress: `0x${string}`;
59
+ targetChain: ChainType;
60
+ prc20Token: `0x${string}`;
61
+ quote: OutboundGasQuote;
62
+ splMintBase58: string | undefined;
63
+ burnAmount: bigint;
64
+ pathTag: string;
65
+ }): Promise<OutboundGasQuote>;
66
+ /**
67
+ * Returns the minimum SVM `gas_fee` budget in lamports for the gateway
68
+ * finalize instruction, including a small compute buffer. If RPC is not
69
+ * available, falls back to Solana protocol rent constants.
70
+ */
71
+ export declare function getSvmFinalizeGasBudget(input: SvmFinalizeGasBudgetInput): Promise<bigint>;
40
72
  /**
41
73
  * Returns the (possibly bumped) effectiveGasLimit. Logs the decision via
42
74
  * printLog. On any RPC failure or invalid input, logs a warning and returns
@@ -44,3 +76,4 @@ export interface MaybeBumpInput {
44
76
  * outbounds on RPC flake; pre-flight will surface insufficient gas anyway.
45
77
  */
46
78
  export declare function maybeBumpForCeaAtaRent(input: MaybeBumpInput): Promise<bigint>;
79
+ export {};
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CEA_ATA_RENT_LAMPORTS_BUMP = void 0;
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;
4
4
  exports.deriveSvmCeaPda = deriveSvmCeaPda;
5
5
  exports.deriveAtaPubkey = deriveAtaPubkey;
6
+ exports.gasLimitForSvmGasFeeBudget = gasLimitForSvmGasFeeBudget;
7
+ exports.ensureSvmFinalizeGasBudgetQuote = ensureSvmFinalizeGasBudgetQuote;
8
+ exports.getSvmFinalizeGasBudget = getSvmFinalizeGasBudget;
6
9
  exports.maybeBumpForCeaAtaRent = maybeBumpForCeaAtaRent;
7
10
  const tslib_1 = require("tslib");
8
11
  /**
9
- * Conditional CEA-ATA rent bump for SVM SPL outbounds.
12
+ * SVM finalize gas-budget helpers.
10
13
  *
11
14
  * The gateway program (svm-gateway) computes per-tx fees with a conditional
12
15
  * rent for first-time SPL transfers — see `calculateSplExecuteFees` in
@@ -14,31 +17,40 @@ const tslib_1 = require("tslib");
14
17
  *
15
18
  * const ataExists = await ceaAtaExists(connection, ceaAta);
16
19
  * const ceaAtaRent = ataExists ? 0n : BigInt(getMinimumBalanceForRentExemption(165));
17
- * gasFee = executedTxRent + ceaAtaRent + COMPUTE_BUFFER;
20
+ * gasFee = signatureFee + executedTxRent + ceaAtaRent + COMPUTE_BUFFER;
18
21
  *
19
22
  * The gateway's on-chain `getOutboundTxGasAndFees` quote does NOT factor in
20
23
  * the ATA rent today, so the SDK has to bump `effectiveGasLimit` itself
21
- * before calling that quote. Native-SOL outbounds use `calculateSolExecuteFees`
22
- * which has no conditional rent, so no SDK bump is needed there.
24
+ * before building the outbound request. Native-SOL outbounds still need the
25
+ * same base finalize budget plus compute buffer.
23
26
  */
24
27
  const web3_js_1 = require("@solana/web3.js");
25
28
  const buffer_1 = require("buffer");
26
29
  const context_1 = require("./context");
27
30
  const chain_1 = require("../../constants/chain");
31
+ const gas_calculator_1 = require("./gas-calculator");
28
32
  // ---------------------------------------------------------------------------
29
33
  // Constants — mirror gateway test-utils.ts. These are SOL protocol values;
30
34
  // they only change if Solana itself adjusts rent rates (effectively never).
31
35
  // ---------------------------------------------------------------------------
32
- /** ATA rent (165-byte SPL token account) + executed-tx rent (8-byte) + compute buffer.
33
- * Mirrors getMinimumBalanceForRentExemption(165) ≈ 2_039_280
34
- * + getMinimumBalanceForRentExemption(8) ≈ 9_200
35
- * + COMPUTE_BUFFER 100_000.
36
- * Signature fee (5_000) is already included in the gateway's base quote. */
37
- exports.CEA_ATA_RENT_LAMPORTS_BUMP = BigInt(2148480);
36
+ /** Base Solana fee per relayer signature, mirrored from SVM gateway execute.rs. */
37
+ exports.SVM_SIGNATURE_FEE_LAMPORTS = BigInt(5000);
38
+ /** Operational buffer used by SVM gateway tests for tx fees / compute. */
39
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS = BigInt(100000);
40
+ /** Devnet/mainnet rent-exempt minimum for ExecutedSubTx::LEN = 8 bytes. */
41
+ exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK = BigInt(946560);
42
+ /** Devnet/mainnet rent-exempt minimum for a 165-byte SPL token account. */
43
+ exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK = BigInt(2039280);
44
+ /** Back-compat export for older tests/callers: ATA rent + base finalization overhead. */
45
+ exports.CEA_ATA_RENT_LAMPORTS_BUMP = exports.SVM_SIGNATURE_FEE_LAMPORTS +
46
+ exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK +
47
+ exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK +
48
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
38
49
  /** SVM gateway program ID (matches CHAIN_INFO[SOLANA_DEVNET].lockerContract). */
39
50
  const SVM_GATEWAY_PROGRAM = new web3_js_1.PublicKey('CFVSincHYbETh2k7w6u1ENEkjbSLtveRCEBupKidw2VS');
40
51
  const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
41
52
  const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
53
+ const SVM_RENT_RPC_TIMEOUT_MS = 3000;
42
54
  // ---------------------------------------------------------------------------
43
55
  // PDA derivations
44
56
  // ---------------------------------------------------------------------------
@@ -53,6 +65,129 @@ function deriveAtaPubkey(owner, mint) {
53
65
  const [ata] = web3_js_1.PublicKey.findProgramAddressSync([owner.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID);
54
66
  return ata;
55
67
  }
68
+ 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]);
71
+ }
72
+ function isAccountInitialized(info) {
73
+ return info !== null && info.data.length > 0;
74
+ }
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
+ });
93
+ }
94
+ function gasLimitForSvmGasFeeBudget(gasFeeBudget, gasPrice) {
95
+ if (gasPrice <= BigInt(0)) {
96
+ throw new Error(`Cannot derive SVM gasLimit from gasPrice=${gasPrice.toString()}`);
97
+ }
98
+ return (gasFeeBudget + gasPrice - BigInt(1)) / gasPrice;
99
+ }
100
+ function ensureSvmFinalizeGasBudgetQuote(_a) {
101
+ return tslib_1.__awaiter(this, arguments, void 0, function* ({ ctx, ueaAddress, targetChain, prc20Token, quote, splMintBase58, burnAmount, pathTag, }) {
102
+ const minGasFee = yield getSvmFinalizeGasBudget({
103
+ ctx,
104
+ ueaAddress,
105
+ targetChain,
106
+ splMintBase58,
107
+ burnAmount,
108
+ });
109
+ if (quote.gasFee >= minGasFee) {
110
+ (0, context_1.printLog)(ctx, `${pathTag} — SVM finalize gas budget ok: gasFee=${quote.gasFee.toString()}, ` +
111
+ `minimum=${minGasFee.toString()}, gasLimit=${quote.gasLimitUsed.toString()}`);
112
+ return quote;
113
+ }
114
+ const bumpedGasLimit = gasLimitForSvmGasFeeBudget(minGasFee, quote.gasPrice);
115
+ (0, context_1.printLog)(ctx, `${pathTag} — bumping SVM gasLimit ${quote.gasLimitUsed.toString()} → ${bumpedGasLimit.toString()}; ` +
116
+ `gasFee=${quote.gasFee.toString()} below finalize minimum=${minGasFee.toString()}`);
117
+ const bumpedQuote = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, bumpedGasLimit, targetChain);
118
+ if (bumpedQuote.gasFee < minGasFee) {
119
+ (0, context_1.printLog)(ctx, `${pathTag} — WARNING: bumped SVM gasFee=${bumpedQuote.gasFee.toString()} ` +
120
+ `still below finalize minimum=${minGasFee.toString()}`);
121
+ }
122
+ return bumpedQuote;
123
+ });
124
+ }
125
+ /**
126
+ * Returns the minimum SVM `gas_fee` budget in lamports for the gateway
127
+ * finalize instruction, including a small compute buffer. If RPC is not
128
+ * available, falls back to Solana protocol rent constants.
129
+ */
130
+ function getSvmFinalizeGasBudget(input) {
131
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
132
+ const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount } = input;
133
+ const needsSplAta = Boolean(splMintBase58) && burnAmount > BigInt(0);
134
+ const rpcUrl = getRpcUrl(ctx, targetChain);
135
+ let executedTxRent = exports.SVM_EXECUTED_SUB_TX_RENT_FALLBACK;
136
+ let ataRent = BigInt(0);
137
+ if (!needsSplAta) {
138
+ const budget = exports.SVM_SIGNATURE_FEE_LAMPORTS +
139
+ executedTxRent +
140
+ ataRent +
141
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
142
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — no SPL ATA needed for ${targetChain}; ` +
143
+ `using fallback base budget ${budget.toString()}`);
144
+ return budget;
145
+ }
146
+ if (!rpcUrl) {
147
+ ataRent = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK;
148
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — no Solana RPC URL for ${targetChain}; ` +
149
+ `using fallback budget ${(exports.SVM_SIGNATURE_FEE_LAMPORTS +
150
+ executedTxRent +
151
+ ataRent +
152
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS).toString()}`);
153
+ return (exports.SVM_SIGNATURE_FEE_LAMPORTS +
154
+ executedTxRent +
155
+ ataRent +
156
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS);
157
+ }
158
+ try {
159
+ const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
160
+ executedTxRent = BigInt(yield withSvmRentRpcTimeout(conn.getMinimumBalanceForRentExemption(8), 'getMinimumBalanceForRentExemption(8)'));
161
+ if (needsSplAta && splMintBase58) {
162
+ const ceaPda = deriveSvmCeaPda(ueaAddress);
163
+ const splMint = new web3_js_1.PublicKey(splMintBase58);
164
+ const ceaAta = deriveAtaPubkey(ceaPda, splMint);
165
+ const info = yield withSvmRentRpcTimeout(conn.getAccountInfo(ceaAta), `getAccountInfo(${ceaAta.toBase58()})`);
166
+ if (!isAccountInitialized(info)) {
167
+ ataRent = BigInt(yield withSvmRentRpcTimeout(conn.getMinimumBalanceForRentExemption(165), 'getMinimumBalanceForRentExemption(165)'));
168
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — CEA ATA ${ceaAta.toBase58()} not deployed on ${targetChain}; ` +
169
+ `including ${ataRent.toString()} lamports ATA rent`);
170
+ }
171
+ else {
172
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — CEA ATA ${ceaAta.toBase58()} already deployed on ${targetChain}; no ATA rent`);
173
+ }
174
+ }
175
+ }
176
+ catch (err) {
177
+ ataRent = exports.SVM_TOKEN_ACCOUNT_RENT_FALLBACK;
178
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — RPC error on ${targetChain}: ` +
179
+ `${err instanceof Error ? err.message : String(err)}; using fallback rents`);
180
+ }
181
+ const budget = exports.SVM_SIGNATURE_FEE_LAMPORTS +
182
+ executedTxRent +
183
+ ataRent +
184
+ exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS;
185
+ (0, context_1.printLog)(ctx, `getSvmFinalizeGasBudget — budget=${budget.toString()} ` +
186
+ `(signature=${exports.SVM_SIGNATURE_FEE_LAMPORTS}, executedTxRent=${executedTxRent}, ataRent=${ataRent}, ` +
187
+ `computeBuffer=${exports.SVM_FINALIZE_COMPUTE_BUFFER_LAMPORTS})`);
188
+ return budget;
189
+ });
190
+ }
56
191
  /**
57
192
  * Returns the (possibly bumped) effectiveGasLimit. Logs the decision via
58
193
  * printLog. On any RPC failure or invalid input, logs a warning and returns
@@ -61,14 +196,13 @@ function deriveAtaPubkey(owner, mint) {
61
196
  */
62
197
  function maybeBumpForCeaAtaRent(input) {
63
198
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
64
- var _a, _b, _c, _d, _e;
65
199
  const { ctx, ueaAddress, targetChain, splMintBase58, burnAmount, effectiveGasLimit, } = input;
66
200
  // Only applies to SPL outbounds. Native SOL outbounds use the gateway's
67
201
  // calculateSolExecuteFees which has no ATA conditional.
68
202
  if (!splMintBase58 || burnAmount === BigInt(0)) {
69
203
  return effectiveGasLimit;
70
204
  }
71
- const rpcUrl = (_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];
205
+ const rpcUrl = getRpcUrl(ctx, targetChain);
72
206
  if (!rpcUrl) {
73
207
  (0, context_1.printLog)(ctx, `maybeBumpForCeaAtaRent — no Solana RPC URL for ${targetChain}; skipping rent bump`);
74
208
  return effectiveGasLimit;
@@ -78,7 +212,7 @@ function maybeBumpForCeaAtaRent(input) {
78
212
  const splMint = new web3_js_1.PublicKey(splMintBase58);
79
213
  const ceaAta = deriveAtaPubkey(ceaPda, splMint);
80
214
  const conn = new web3_js_1.Connection(rpcUrl, 'confirmed');
81
- const info = yield conn.getAccountInfo(ceaAta);
215
+ const info = yield withSvmRentRpcTimeout(conn.getAccountInfo(ceaAta), `getAccountInfo(${ceaAta.toBase58()})`);
82
216
  const ataExists = info !== null && info.data.length > 0;
83
217
  if (!ataExists) {
84
218
  const bumped = effectiveGasLimit + exports.CEA_ATA_RENT_LAMPORTS_BUMP;
@@ -16,6 +16,7 @@ const types_1 = require("../../generated/uexecutor/v1/types");
16
16
  const types_2 = require("../../generated/uexecutor/v2/types");
17
17
  const progress_hook_1 = tslib_1.__importDefault(require("../../progress-hook/progress-hook"));
18
18
  const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
19
+ const formatters_1 = require("../../formatters");
19
20
  const payload_builders_1 = require("../payload-builders");
20
21
  const route_detector_1 = require("../route-detector");
21
22
  // ============================================================================
@@ -58,9 +59,12 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
58
59
  // scoped phase ('outbound' + source-chain). Emitting in both places
59
60
  // would double-fire the terminal with a misleading 'push' title on top.
60
61
  const isFailed = isPcFailed || isOutboundFailed;
62
+ const pcErrorMsg = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg)
63
+ ? (0, formatters_1.normalizePcInsufficientFundsError)(pcTx.errorMsg)
64
+ : 'Unknown error';
61
65
  const errorMsg = isOutboundFailed
62
66
  ? 'Outbound transaction failed (status: OUTBOUND_FAILED)'
63
- : ((pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg) || 'Unknown error');
67
+ : pcErrorMsg;
64
68
  // Route 2 / 3 reconstruction — keep parity with live emission from
65
69
  // route-handlers.ts (which fires 201/203/207 or 301/303/307 then suppresses
66
70
  // R1 IDs via fireProgressHook). Skip the R1 101–107 sequence here; it would
@@ -70,7 +74,6 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
70
74
  // leg itself failed — so prefer pcTx.errorMsg over the outbound-failed
71
75
  // sentinel. The outer `errorMsg` above carries the outbound text when
72
76
  // `isOutboundFailed` is set; that path is handled by wait() instead.
73
- const pcErrorMsg = (pcTx === null || pcTx === void 0 ? void 0 : pcTx.errorMsg) || 'Unknown error';
74
77
  // Multichain cascade: a single Push-chain tx that fanned out into >1
75
78
  // outbound legs (executeTransactions([tx1, tx2, …])). The cosmos record
76
79
  // carries one UniversalTx with multiple outboundTx entries; wrap the
@@ -0,0 +1,60 @@
1
+ export declare const DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS = 1000;
2
+ export declare const MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT = 10000;
3
+ export interface MaxPCForGasCapInput {
4
+ /**
5
+ * Native PC estimate intended for the gas-token swap, excluding protocolFee.
6
+ */
7
+ gasLegNativePc: bigint;
8
+ /**
9
+ * Protocol fee returned by UniversalCore. Included in nativeValueForGas but
10
+ * excluded from maxPCForGas because UGPC subtracts it before applying the cap.
11
+ */
12
+ protocolFee?: bigint;
13
+ /**
14
+ * Slippage buffer in basis points. Defaults to 1000 bps (10%).
15
+ */
16
+ bufferBps?: number;
17
+ }
18
+ export interface MaxPCForGasCapFromNativeValueInput {
19
+ /**
20
+ * Total native PC value planned for sendUniversalTxOutbound msg.value.
21
+ */
22
+ nativeValueForGas: bigint;
23
+ /**
24
+ * Protocol fee returned by UniversalCore.
25
+ */
26
+ protocolFee: bigint;
27
+ /**
28
+ * Slippage buffer in basis points. Defaults to 1000 bps (10%).
29
+ */
30
+ bufferBps?: number;
31
+ }
32
+ export interface MaxPCForGasCapQuote {
33
+ /**
34
+ * Value to pass as UniversalExecuteParams.maxPCForGas.
35
+ */
36
+ maxPCForGas: bigint;
37
+ /**
38
+ * Minimum native PC msg.value that satisfies the cap:
39
+ * protocolFee + maxPCForGas.
40
+ */
41
+ nativeValueForGas: bigint;
42
+ /**
43
+ * Gas-swap leg before the buffer, excluding protocolFee.
44
+ */
45
+ gasLegNativePc: bigint;
46
+ protocolFee: bigint;
47
+ bufferBps: number;
48
+ }
49
+ /**
50
+ * Builds a contract-safe maxPCForGas cap from a native PC gas-leg estimate.
51
+ *
52
+ * UGPC validates maxPCForGas against `msg.value - protocolFee`, so the helper
53
+ * returns the minimum matching nativeValueForGas as well as the cap.
54
+ */
55
+ export declare function quoteMaxPCForGasCap(input: MaxPCForGasCapInput): MaxPCForGasCapQuote;
56
+ /**
57
+ * Builds a maxPCForGas cap from queryOutboundGasFee's nativeValueForGas and
58
+ * protocolFee fields.
59
+ */
60
+ export declare function quoteMaxPCForGasCapFromNativeValue(input: MaxPCForGasCapFromNativeValueInput): MaxPCForGasCapQuote;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT = exports.DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS = void 0;
4
+ exports.quoteMaxPCForGasCap = quoteMaxPCForGasCap;
5
+ exports.quoteMaxPCForGasCapFromNativeValue = quoteMaxPCForGasCapFromNativeValue;
6
+ const BPS_DENOMINATOR = BigInt(10000);
7
+ exports.DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS = 1000;
8
+ exports.MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT = 10000;
9
+ /**
10
+ * Builds a contract-safe maxPCForGas cap from a native PC gas-leg estimate.
11
+ *
12
+ * UGPC validates maxPCForGas against `msg.value - protocolFee`, so the helper
13
+ * returns the minimum matching nativeValueForGas as well as the cap.
14
+ */
15
+ function quoteMaxPCForGasCap(input) {
16
+ var _a;
17
+ assertNonNegativeBigInt('gasLegNativePc', input.gasLegNativePc);
18
+ const protocolFee = (_a = input.protocolFee) !== null && _a !== void 0 ? _a : BigInt(0);
19
+ assertNonNegativeBigInt('protocolFee', protocolFee);
20
+ const bufferBps = normalizeBufferBps(input.bufferBps);
21
+ const maxPCForGas = applyBufferCeil(input.gasLegNativePc, bufferBps);
22
+ return {
23
+ maxPCForGas,
24
+ nativeValueForGas: protocolFee + maxPCForGas,
25
+ gasLegNativePc: input.gasLegNativePc,
26
+ protocolFee,
27
+ bufferBps,
28
+ };
29
+ }
30
+ /**
31
+ * Builds a maxPCForGas cap from queryOutboundGasFee's nativeValueForGas and
32
+ * protocolFee fields.
33
+ */
34
+ function quoteMaxPCForGasCapFromNativeValue(input) {
35
+ assertNonNegativeBigInt('nativeValueForGas', input.nativeValueForGas);
36
+ assertNonNegativeBigInt('protocolFee', input.protocolFee);
37
+ if (input.nativeValueForGas < input.protocolFee) {
38
+ throw new RangeError('nativeValueForGas must be greater than or equal to protocolFee');
39
+ }
40
+ return quoteMaxPCForGasCap({
41
+ gasLegNativePc: input.nativeValueForGas - input.protocolFee,
42
+ protocolFee: input.protocolFee,
43
+ bufferBps: input.bufferBps,
44
+ });
45
+ }
46
+ function normalizeBufferBps(bufferBps) {
47
+ const normalized = bufferBps !== null && bufferBps !== void 0 ? bufferBps : exports.DEFAULT_MAX_PC_FOR_GAS_BUFFER_BPS;
48
+ if (!Number.isInteger(normalized) ||
49
+ normalized < 0 ||
50
+ normalized > exports.MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT) {
51
+ throw new RangeError(`bufferBps must be an integer between 0 and ${exports.MAX_PC_FOR_GAS_BUFFER_BPS_LIMIT}`);
52
+ }
53
+ return normalized;
54
+ }
55
+ function applyBufferCeil(amount, bufferBps) {
56
+ if (amount === BigInt(0))
57
+ return BigInt(0);
58
+ const multiplier = BPS_DENOMINATOR + BigInt(bufferBps);
59
+ return (amount * multiplier + BPS_DENOMINATOR - BigInt(1)) / BPS_DENOMINATOR;
60
+ }
61
+ function assertNonNegativeBigInt(name, value) {
62
+ if (value < BigInt(0)) {
63
+ throw new RangeError(`${name} must be non-negative`);
64
+ }
65
+ }
66
+ //# sourceMappingURL=max-pc-for-gas.js.map
@@ -105,6 +105,7 @@ export declare class Orchestrator {
105
105
  protocolFee: bigint;
106
106
  nativeValueForGas: bigint;
107
107
  gasPrice: bigint;
108
+ gasLimitUsed: bigint;
108
109
  }>;
109
110
  /**
110
111
  * Extracts the first universal sub-tx ID from a Push Chain transaction's Cosmos events.
@@ -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.
@@ -426,25 +432,26 @@ export interface SvmExecutePayloadFields {
426
432
  * Request structure for sendUniversalTxOutbound on Push Chain
427
433
  * Used for Routes 2, 3, 4 (outbound from Push)
428
434
  *
429
- * NOTE: The `target` field is a LEGACY parameter for contract compatibility.
430
- * The deployed UniversalGatewayPC contract still expects this field, but it will
431
- * be removed in future contract upgrades. Pass any non-zero address (e.g., CEA address).
432
- * The actual destination is determined by the relay from the token's SOURCE_CHAIN_NAMESPACE.
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.
433
437
  */
434
438
  export interface UniversalOutboundTxRequest {
435
439
  /**
436
- * LEGACY/DUMMY: Raw destination address bytes for contract compatibility.
437
- * Pass any non-zero address - this value is NOT used by the relay to determine
438
- * the actual transaction destination. Will be removed in future contract upgrades.
440
+ * Raw destination recipient bytes. EVM routes usually pass a 20-byte address;
441
+ * SVM routes pass a 32-byte program/account address.
439
442
  */
440
443
  target: `0x${string}`;
441
444
  /** PRC20 token address on Push Chain to burn */
442
445
  token: `0x${string}`;
443
446
  /** Amount to burn (0 for no-burn, use existing CEA balance) */
444
447
  amount: bigint;
445
- /** Gas limit for fee quote (0 = default BASE_GAS_LIMIT) */
448
+ /** Gas limit for fee quote (0 = per-chain default resolved by UniversalCore) */
446
449
  gasLimit: bigint;
447
- /** Raw ABI-encoded Multicall[] (no selector prefix) */
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 */
448
455
  payload: `0x${string}`;
449
456
  /** Address to receive funds on revert */
450
457
  revertRecipient: `0x${string}`;
@@ -488,8 +495,12 @@ export interface HopDescriptor {
488
495
  gasToken?: `0x${string}`;
489
496
  /** Gas fee amount in gas token */
490
497
  gasFee?: bigint;
498
+ /** Destination-chain gas price quoted by UniversalCore */
499
+ gasPrice?: bigint;
491
500
  /** Gas limit for outbound relay */
492
501
  gasLimit: bigint;
502
+ /** Max native PC used for outbound gas swap (0 = uncapped) */
503
+ maxPCForGas: bigint;
493
504
  /** UEA address */
494
505
  ueaAddress: `0x${string}`;
495
506
  /** Address to receive funds on revert */
@@ -538,8 +549,12 @@ export interface CascadeSegment {
538
549
  gasToken?: `0x${string}`;
539
550
  /** Total gas fee for this segment */
540
551
  gasFee?: bigint;
552
+ /** Destination-chain gas price quoted by UniversalCore */
553
+ gasPrice?: bigint;
541
554
  /** Gas limit for this segment */
542
555
  gasLimit?: bigint;
556
+ /** Max native PC used for outbound gas swap (0 = uncapped) */
557
+ maxPCForGas?: bigint;
543
558
  /**
544
559
  * SDK 5.2 gas-abstraction sizing decision for this segment. When the
545
560
  * segment merges multiple hops, the strictest (highest category) sizing
@@ -756,6 +771,13 @@ export interface WaitForOutboundOptions {
756
771
  * has multiple outbound operations to different chains.
757
772
  */
758
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;
759
781
  }
760
782
  /**
761
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 - LEGACY/DUMMY: Any non-zero address for contract compatibility.
74
- * This value is NOT used by the relay to determine the actual destination.
75
- * The relay determines the destination from the PRC-20 token's SOURCE_CHAIN_NAMESPACE.
76
- * Will be removed in future contract upgrades.
73
+ * @param 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 - CEA multicall payload
78
+ * @param payload - Destination execution payload
81
79
  * @param revertRecipient - Address to receive funds on revert
80
+ * @param maxPCForGas - Max native PC used for gas swap (0 = uncapped)
81
+ * @param gasPrice - Destination-chain gas price override (0 = UniversalCore default)
82
82
  * @returns UniversalOutboundTxRequest object
83
83
  */
84
- export declare function buildOutboundRequest(target: `0x${string}`, prc20Token: `0x${string}`, amount: bigint, gasLimit: bigint, payload: `0x${string}`, revertRecipient: `0x${string}`): UniversalOutboundTxRequest;
84
+ export declare function buildOutboundRequest(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
  *