@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.
- package/package.json +1 -1
- package/src/lib/constants/abi/cea.evm.d.ts +52 -0
- package/src/lib/constants/abi/cea.evm.js +66 -1
- package/src/lib/constants/abi/prc20.evm.d.ts +117 -11
- package/src/lib/constants/abi/prc20.evm.js +38 -11
- package/src/lib/constants/abi/uea.evm.js +41 -0
- package/src/lib/constants/abi/universalGatewayPC.evm.d.ts +117 -1
- package/src/lib/constants/abi/universalGatewayPC.evm.js +40 -1
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +14 -14
- package/src/lib/constants/tokens.js +1 -0
- package/src/lib/formatters.d.ts +6 -0
- package/src/lib/formatters.js +14 -0
- package/src/lib/index.d.ts +2 -0
- package/src/lib/index.js +7 -1
- package/src/lib/orchestrator/internals/cascade.js +139 -81
- package/src/lib/orchestrator/internals/errors.js +1 -1
- package/src/lib/orchestrator/internals/execute-funds-only.js +3 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +2 -1
- package/src/lib/orchestrator/internals/execute-standard.js +4 -4
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +1 -0
- package/src/lib/orchestrator/internals/gas-calculator.js +13 -11
- package/src/lib/orchestrator/internals/helpers.js +1 -0
- package/src/lib/orchestrator/internals/inbound-tracker.js +4 -2
- package/src/lib/orchestrator/internals/outbound-sync.js +73 -60
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +1 -1
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +4 -3
- package/src/lib/orchestrator/internals/push-chain-tx.js +5 -1
- package/src/lib/orchestrator/internals/route-handlers.js +155 -185
- package/src/lib/orchestrator/internals/signing.js +7 -2
- package/src/lib/orchestrator/internals/svm-helpers.js +3 -3
- package/src/lib/orchestrator/internals/svm-rent.d.ts +42 -9
- package/src/lib/orchestrator/internals/svm-rent.js +148 -14
- package/src/lib/orchestrator/internals/tx-transformer.js +5 -2
- package/src/lib/orchestrator/max-pc-for-gas.d.ts +60 -0
- package/src/lib/orchestrator/max-pc-for-gas.js +66 -0
- package/src/lib/orchestrator/orchestrator.d.ts +1 -0
- package/src/lib/orchestrator/orchestrator.types.d.ts +31 -9
- package/src/lib/orchestrator/payload-builders.d.ts +7 -6
- package/src/lib/orchestrator/payload-builders.js +18 -6
- package/src/lib/progress-hook/progress-hook.js +26 -18
- package/src/lib/universal-tx-detector/events.d.ts +3 -1
- package/src/lib/universal-tx-detector/events.js +3 -1
- package/src/lib/universal-tx-detector/svm-events.d.ts +1 -1
- 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 = (
|
|
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 (
|
|
97
|
+
catch (_f) {
|
|
98
98
|
return { feeVaultPda, protocolFeeLamports: BigInt(0) };
|
|
99
99
|
}
|
|
100
100
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
|
15
|
-
*
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
*
|
|
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
|
|
22
|
-
*
|
|
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
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
exports.
|
|
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 = (
|
|
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
|
-
:
|
|
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
|
|
@@ -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
|
|
430
|
-
*
|
|
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
|
-
*
|
|
437
|
-
*
|
|
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
|
|
448
|
+
/** Gas limit for fee quote (0 = per-chain default resolved by UniversalCore) */
|
|
446
449
|
gasLimit: bigint;
|
|
447
|
-
/**
|
|
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 -
|
|
74
|
-
*
|
|
75
|
-
* The relay determines the destination from the PRC-20 token's SOURCE_CHAIN_NAMESPACE.
|
|
76
|
-
* Will be removed in future contract upgrades.
|
|
73
|
+
* @param target - Raw recipient bytes for the destination chain. For EVM CEA
|
|
74
|
+
* funds-parking, use the zero recipient when payload is empty.
|
|
77
75
|
* @param prc20Token - PRC20 token address to burn (or address(0) for native)
|
|
78
76
|
* @param amount - Amount to burn
|
|
79
77
|
* @param gasLimit - Gas limit for fee calculation
|
|
80
|
-
* @param payload -
|
|
78
|
+
* @param payload - Destination execution payload
|
|
81
79
|
* @param revertRecipient - Address to receive funds on revert
|
|
80
|
+
* @param maxPCForGas - Max native PC used for gas swap (0 = uncapped)
|
|
81
|
+
* @param gasPrice - Destination-chain gas price override (0 = UniversalCore default)
|
|
82
82
|
* @returns UniversalOutboundTxRequest object
|
|
83
83
|
*/
|
|
84
|
-
export declare function buildOutboundRequest(target: `0x${string}`, prc20Token: `0x${string}`, amount: bigint, gasLimit: bigint, payload: `0x${string}`, revertRecipient: `0x${string}
|
|
84
|
+
export declare function buildOutboundRequest(target: `0x${string}`, prc20Token: `0x${string}`, amount: bigint, gasLimit: bigint, payload: `0x${string}`, revertRecipient: `0x${string}`, maxPCForGas?: bigint, gasPrice?: bigint): UniversalOutboundTxRequest;
|
|
85
|
+
export declare function assertCeaFundsParkingInvariant(recipient: `0x${string}`, payload: `0x${string}`): void;
|
|
85
86
|
/**
|
|
86
87
|
* Build ERC20 transfer multicall
|
|
87
88
|
*
|