@pushchain/core 5.1.4-alpha.6 → 5.1.4-alpha.8
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
CHANGED
|
@@ -37,16 +37,28 @@ function prepareTransaction(ctx, params, callbacks) {
|
|
|
37
37
|
clientChain: ctx.universalSigner.account.chain,
|
|
38
38
|
});
|
|
39
39
|
const route = (0, route_detector_1.detectRoute)(params);
|
|
40
|
-
//
|
|
40
|
+
// Push native EOA: block Route 1 — use sendTransaction() for direct Push calls
|
|
41
|
+
const signerChain = ctx.universalSigner.account.chain;
|
|
42
|
+
const isPushNativeEOA = (0, helpers_1.isPushChain)(signerChain);
|
|
43
|
+
if (isPushNativeEOA && route === route_detector_1.TransactionRoute.UOA_TO_PUSH) {
|
|
44
|
+
throw new Error('Push native accounts cannot use prepareTransaction for Push Chain transactions. ' +
|
|
45
|
+
'Use sendTransaction() instead for direct Push Chain calls.');
|
|
46
|
+
}
|
|
47
|
+
// Fetch UEA nonce (skip for Push native EOA — uses EVM nonce, not UEA contract nonce)
|
|
41
48
|
let nonce;
|
|
42
|
-
const deployedHintCascade = (_b = (_a = ctx.accountStatusCache) === null || _a === void 0 ? void 0 : _a.uea) === null || _b === void 0 ? void 0 : _b.deployed;
|
|
43
49
|
const ueaAddress = (0, uea_manager_1.computeUEAOffchain)(ctx);
|
|
44
|
-
if (
|
|
45
|
-
nonce =
|
|
50
|
+
if (isPushNativeEOA) {
|
|
51
|
+
nonce = BigInt(0);
|
|
46
52
|
}
|
|
47
53
|
else {
|
|
48
|
-
const
|
|
49
|
-
|
|
54
|
+
const deployedHintCascade = (_b = (_a = ctx.accountStatusCache) === null || _a === void 0 ? void 0 : _a.uea) === null || _b === void 0 ? void 0 : _b.deployed;
|
|
55
|
+
if (deployedHintCascade) {
|
|
56
|
+
nonce = yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const status = yield (0, uea_manager_1.getUeaStatusAndNonce)(ctx);
|
|
60
|
+
nonce = status.nonce;
|
|
61
|
+
}
|
|
50
62
|
}
|
|
51
63
|
// Build the payload based on route
|
|
52
64
|
const { payload, gatewayRequest } = yield (0, route_handlers_1.buildPayloadForRoute)(ctx, params, route, nonce);
|
|
@@ -220,8 +232,13 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
220
232
|
burnAmount = params.value;
|
|
221
233
|
}
|
|
222
234
|
else if (params.data) {
|
|
235
|
+
// PAYLOAD-only (no value transfer): still need native PRC-20 token for
|
|
236
|
+
// chain namespace lookup + gas fees, but burn amount must be zero.
|
|
237
|
+
// Matches the direct executeUoaToCea path (route-handlers.ts).
|
|
238
|
+
// Using burnAmount=1 would trigger transferFrom on the PRC-20 token,
|
|
239
|
+
// which reverts when the UEA has no PRC-20 balance for that chain.
|
|
223
240
|
prc20Token = (0, helpers_1.getNativePRC20ForChain)(targetChain, ctx.pushNetwork);
|
|
224
|
-
burnAmount = BigInt(
|
|
241
|
+
burnAmount = BigInt(0);
|
|
225
242
|
}
|
|
226
243
|
// Query gas fee
|
|
227
244
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
@@ -283,10 +300,12 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
283
300
|
gasToken = result.gasToken;
|
|
284
301
|
gasFee = result.gasFee;
|
|
285
302
|
}
|
|
286
|
-
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain, ceaAddress: ceaPdaHex, isSvmTarget: true, prc20Token, burnAmount: amount
|
|
303
|
+
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain, ceaAddress: ceaPdaHex, isSvmTarget: true, prc20Token, burnAmount: amount, gasToken,
|
|
287
304
|
gasFee });
|
|
288
305
|
}
|
|
289
|
-
const { cea: ceaAddress
|
|
306
|
+
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (_h = ctx.rpcUrls[sourceChain]) === null || _h === void 0 ? void 0 : _h[0]);
|
|
307
|
+
// CEA auto-deploys on-chain: Vault.finalizeUniversalTx calls CEAFactory.deployCEA()
|
|
308
|
+
// if CEA doesn't exist yet. No SDK-side blocking needed.
|
|
290
309
|
// Determine token/amount for the inbound
|
|
291
310
|
let tokenAddress = selectors_1.ZERO_ADDRESS;
|
|
292
311
|
let amount = BigInt(0);
|
|
@@ -319,7 +338,7 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
319
338
|
}
|
|
320
339
|
return Object.assign(Object.assign({}, baseDescriptor), { sourceChain,
|
|
321
340
|
ceaAddress,
|
|
322
|
-
prc20Token, burnAmount: amount
|
|
341
|
+
prc20Token, burnAmount: amount, gasToken,
|
|
323
342
|
gasFee });
|
|
324
343
|
}
|
|
325
344
|
default:
|
|
@@ -551,15 +570,15 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
551
570
|
? new Uint8Array(Buffer.from(intermediatePayload.slice(2), 'hex'))
|
|
552
571
|
: undefined,
|
|
553
572
|
});
|
|
554
|
-
const
|
|
573
|
+
const svmBurnAmount = segment.totalBurnAmount || BigInt(0);
|
|
555
574
|
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, segment.prc20Token ||
|
|
556
|
-
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork),
|
|
575
|
+
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), svmBurnAmount, (_g = segment.gasLimit) !== null && _g !== void 0 ? _g : BigInt(0), svmPayload, ueaAddress);
|
|
557
576
|
const inboundGasFee = segment.gasFee || BigInt(0);
|
|
558
577
|
const outboundMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
559
578
|
prc20Token: segment.prc20Token ||
|
|
560
579
|
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork),
|
|
561
580
|
gasToken: segment.gasToken || selectors_1.ZERO_ADDRESS,
|
|
562
|
-
burnAmount,
|
|
581
|
+
burnAmount: svmBurnAmount,
|
|
563
582
|
gasFee: inboundGasFee,
|
|
564
583
|
nativeValueForGas: perOutboundNativeValue !== null && perOutboundNativeValue !== void 0 ? perOutboundNativeValue : inboundGasFee * BigInt(1000),
|
|
565
584
|
gatewayPcAddress,
|
|
@@ -626,13 +645,13 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
626
645
|
// Wrap CEA multicall in outbound from Push Chain
|
|
627
646
|
const ceaPayload = (0, payload_builders_1.buildCeaMulticallPayload)(ceaMulticalls);
|
|
628
647
|
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, segment.prc20Token ||
|
|
629
|
-
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), segment.totalBurnAmount || BigInt(
|
|
648
|
+
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), segment.totalBurnAmount || BigInt(0), (_j = segment.gasLimit) !== null && _j !== void 0 ? _j : BigInt(0), ceaPayload, ueaAddress);
|
|
630
649
|
const inboundGasFee = segment.gasFee || BigInt(0);
|
|
631
650
|
const outboundMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
632
651
|
prc20Token: segment.prc20Token ||
|
|
633
652
|
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork),
|
|
634
653
|
gasToken: segment.gasToken || selectors_1.ZERO_ADDRESS,
|
|
635
|
-
burnAmount: segment.totalBurnAmount || BigInt(
|
|
654
|
+
burnAmount: segment.totalBurnAmount || BigInt(0),
|
|
636
655
|
gasFee: inboundGasFee,
|
|
637
656
|
nativeValueForGas: perOutboundNativeValue !== null && perOutboundNativeValue !== void 0 ? perOutboundNativeValue : inboundGasFee * BigInt(1000),
|
|
638
657
|
gatewayPcAddress,
|
|
@@ -263,44 +263,56 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
263
263
|
let gasFee = BigInt(0);
|
|
264
264
|
let nativeValueForGas = BigInt(0);
|
|
265
265
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
266
|
+
let universalCoreAddress;
|
|
266
267
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
267
268
|
try {
|
|
268
269
|
const result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, outboundReq.gasLimit);
|
|
269
270
|
gasFee = result.gasFee;
|
|
270
271
|
gasToken = result.gasToken;
|
|
271
272
|
nativeValueForGas = result.nativeValueForGas;
|
|
273
|
+
universalCoreAddress = result.universalCoreAddress;
|
|
272
274
|
(0, context_1.printLog)(ctx, `executeUoaToCea — queried gas fee: ${gasFee.toString()}, gasToken: ${gasToken}, nativeValueForGas: ${nativeValueForGas.toString()}`);
|
|
273
275
|
}
|
|
274
276
|
catch (err) {
|
|
275
277
|
throw new Error(`Failed to query outbound gas fee: ${err}`);
|
|
276
278
|
}
|
|
277
279
|
}
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
//
|
|
280
|
+
// Estimate the actual WPC needed for the swap using on-chain pool price.
|
|
281
|
+
// The static 1Mx multiplier from queryOutboundGasFee doesn't reflect the real
|
|
282
|
+
// WPC/gasToken exchange rate. estimateNativeValueForSwap reads the Uniswap V3
|
|
283
|
+
// pool's slot0, computes the true cost, and adds a 2x buffer.
|
|
284
|
+
// This matches the SVM path (executeUoaToCeaSvm) which already uses this.
|
|
285
|
+
// Excess msg.value is refunded by the contract's swapAndBurnGas.
|
|
286
|
+
if (universalCoreAddress && gasFee > BigInt(0)) {
|
|
287
|
+
const estimated = yield (0, gas_calculator_1.estimateNativeValueForSwap)(ctx, universalCoreAddress, gasToken, gasFee, ueaBalance);
|
|
288
|
+
if (estimated > nativeValueForGas) {
|
|
289
|
+
(0, context_1.printLog)(ctx, `executeUoaToCea — pool-price estimate: ${estimated.toString()} ` +
|
|
290
|
+
`(was ${nativeValueForGas.toString()}), UEA balance: ${ueaBalance.toString()}`);
|
|
291
|
+
nativeValueForGas = estimated;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Balance-aware cap: avoid draining the entire UEA balance for gas.
|
|
295
|
+
// The contract's swapAndBurnGas does exactOutputSingle and refunds excess PC,
|
|
296
|
+
// so overshooting within balance is safe.
|
|
282
297
|
const EVM_NATIVE_VALUE_TARGET = BigInt(200e18); // 200 UPC
|
|
283
298
|
const EVM_GAS_RESERVE = BigInt(3e18); // 3 UPC for tx overhead
|
|
284
|
-
// Reuse ueaBalance fetched earlier (line 383) — no tx sent between, balance is stable
|
|
285
299
|
const currentBalance = ueaBalance;
|
|
286
|
-
// Balance-aware adjustment — same logic whether UEA is deployed or not.
|
|
287
|
-
// The old !isUEADeployed branch blindly used 200 UPC assuming fee-locking
|
|
288
|
-
// would deposit enough, but the actual deposit depends on origin-chain ETH
|
|
289
|
-
// locked — not a guaranteed 200 UPC. This caused executeUniversalTx to
|
|
290
|
-
// revert when UEA balance < 200 UPC. The contract's swapAndBurnGas does
|
|
291
|
-
// exactOutputSingle and refunds excess PC, so overshooting within balance
|
|
292
|
-
// is safe.
|
|
293
300
|
let adjustedValue;
|
|
294
301
|
if (currentBalance > EVM_NATIVE_VALUE_TARGET + EVM_GAS_RESERVE) {
|
|
295
|
-
// Enough balance:
|
|
296
|
-
adjustedValue = EVM_NATIVE_VALUE_TARGET
|
|
302
|
+
// Enough balance: cap at 200 UPC (pool estimate may be lower)
|
|
303
|
+
adjustedValue = nativeValueForGas < EVM_NATIVE_VALUE_TARGET
|
|
304
|
+
? nativeValueForGas
|
|
305
|
+
: EVM_NATIVE_VALUE_TARGET;
|
|
297
306
|
}
|
|
298
307
|
else if (currentBalance > EVM_GAS_RESERVE) {
|
|
299
308
|
// Low balance: use what's available minus reserve
|
|
300
|
-
|
|
309
|
+
const available = currentBalance - EVM_GAS_RESERVE;
|
|
310
|
+
adjustedValue = nativeValueForGas < available ? nativeValueForGas : available;
|
|
301
311
|
}
|
|
302
312
|
else {
|
|
303
|
-
// Very low balance
|
|
313
|
+
// Very low/zero balance (fresh wallet). The pool-price estimate (now in
|
|
314
|
+
// nativeValueForGas) is accurate. Fee-locking will deposit enough UPC
|
|
315
|
+
// because requiredFunds includes this value, and lockFee floors at $1.
|
|
304
316
|
adjustedValue = nativeValueForGas;
|
|
305
317
|
}
|
|
306
318
|
if (adjustedValue !== nativeValueForGas) {
|
|
@@ -576,10 +588,8 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
576
588
|
// 4. Get CEA address on source chain
|
|
577
589
|
const { cea: ceaAddress, isDeployed: ceaDeployed } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (_b = ctx.rpcUrls[sourceChain]) === null || _b === void 0 ? void 0 : _b[0]);
|
|
578
590
|
(0, context_1.printLog)(ctx, `executeCeaToPush — sourceChain: ${sourceChain}, CEA: ${ceaAddress}, deployed: ${ceaDeployed}`);
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
`Deploy CEA first using Route 2 (UOA -> CEA) before using Route 3.`);
|
|
582
|
-
}
|
|
591
|
+
// CEA auto-deploys on-chain: Vault.finalizeUniversalTx calls CEAFactory.deployCEA()
|
|
592
|
+
// if CEA doesn't exist yet. No SDK-side blocking needed.
|
|
583
593
|
// 5. Get UniversalGateway address on source chain
|
|
584
594
|
const gatewayAddress = chain_1.UNIVERSAL_GATEWAY_ADDRESSES[sourceChain];
|
|
585
595
|
if (!gatewayAddress) {
|
|
@@ -1108,6 +1118,8 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1108
1118
|
return { payload: svmPayload, gatewayRequest: outboundReq };
|
|
1109
1119
|
}
|
|
1110
1120
|
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (_l = ctx.rpcUrls[sourceChain]) === null || _l === void 0 ? void 0 : _l[0]);
|
|
1121
|
+
// CEA auto-deploys on-chain: Vault.finalizeUniversalTx calls CEAFactory.deployCEA()
|
|
1122
|
+
// if CEA doesn't exist yet. No SDK-side blocking needed.
|
|
1111
1123
|
const gatewayAddr = chain_1.UNIVERSAL_GATEWAY_ADDRESSES[sourceChain];
|
|
1112
1124
|
if (!gatewayAddr) {
|
|
1113
1125
|
throw new Error(`No UniversalGateway address configured for chain ${sourceChain}`);
|
|
@@ -10,6 +10,7 @@ exports.deriveExecutorAccount = deriveExecutorAccount;
|
|
|
10
10
|
exports.resolveControllerAccount = resolveControllerAccount;
|
|
11
11
|
const tslib_1 = require("tslib");
|
|
12
12
|
const viem_1 = require("viem");
|
|
13
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
13
14
|
const chain_1 = require("../../constants/chain");
|
|
14
15
|
const enums_1 = require("../../constants/enums");
|
|
15
16
|
const bs58_1 = require("../../internal/bs58");
|
|
@@ -430,6 +431,30 @@ function getChainName(chain) {
|
|
|
430
431
|
const entry = Object.entries(enums_1.CHAIN).find(([, val]) => val === chain);
|
|
431
432
|
return entry ? entry[0] : chain;
|
|
432
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* Derive the SVM CEA (PDA) for a UEA address on a Solana-based chain.
|
|
436
|
+
*
|
|
437
|
+
* Solana doesn't use a CEAFactory contract — instead, the CEA is a
|
|
438
|
+
* Program Derived Address (PDA) with seeds: ["push_identity", ueaBytes]
|
|
439
|
+
* and the SVM gateway program as the program ID.
|
|
440
|
+
*
|
|
441
|
+
* @param ueaAddress - The UEA (or Push EOA) hex address (20 bytes).
|
|
442
|
+
* @param targetChain - The SVM target chain.
|
|
443
|
+
* @param skipNetworkCheck - Whether to skip deployment status check.
|
|
444
|
+
* @returns The derived 32-byte Solana PDA address (as 0x-prefixed hex) and deployment status.
|
|
445
|
+
*/
|
|
446
|
+
function deriveSvmCeaPda(ueaAddress, targetChain, skipNetworkCheck) {
|
|
447
|
+
const gatewayAddress = chain_1.CHAIN_INFO[targetChain].lockerContract;
|
|
448
|
+
if (!gatewayAddress) {
|
|
449
|
+
throw new Error(`SVM gateway program not configured for chain ${targetChain}`);
|
|
450
|
+
}
|
|
451
|
+
const gatewayProgramId = new web3_js_1.PublicKey(gatewayAddress);
|
|
452
|
+
const ueaBytes = Buffer.from(ueaAddress.slice(2), 'hex'); // 20 bytes
|
|
453
|
+
const [ceaPda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from('push_identity'), ueaBytes], gatewayProgramId);
|
|
454
|
+
const ceaPdaHex = ('0x' +
|
|
455
|
+
Buffer.from(ceaPda.toBytes()).toString('hex'));
|
|
456
|
+
return { address: ceaPdaHex, deployed: skipNetworkCheck ? null : null };
|
|
457
|
+
}
|
|
433
458
|
/**
|
|
434
459
|
* Derive the executor account (UEA or CEA) for a given account.
|
|
435
460
|
*
|
|
@@ -490,6 +515,10 @@ function deriveExecutorAccount(account, options) {
|
|
|
490
515
|
}
|
|
491
516
|
// If target chain is external, derive CEA from the computed UEA
|
|
492
517
|
if (targetChain && !isPushChain(targetChain)) {
|
|
518
|
+
// SVM chains use PDA derivation, not CEAFactory
|
|
519
|
+
if (chain_1.CHAIN_INFO[targetChain].vm === enums_1.VM.SVM) {
|
|
520
|
+
return deriveSvmCeaPda(ueaAddress, targetChain, skipNetworkCheck);
|
|
521
|
+
}
|
|
493
522
|
const { cea, isDeployed } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, targetChain);
|
|
494
523
|
return { address: cea, deployed: skipNetworkCheck ? null : isDeployed };
|
|
495
524
|
}
|
|
@@ -512,6 +541,10 @@ function deriveExecutorAccount(account, options) {
|
|
|
512
541
|
// --- Case 2: Input is on Push Chain ---
|
|
513
542
|
// If target chain is external, derive CEA
|
|
514
543
|
if (targetChain && !isPushChain(targetChain)) {
|
|
544
|
+
// SVM chains use PDA derivation, not CEAFactory
|
|
545
|
+
if (chain_1.CHAIN_INFO[targetChain].vm === enums_1.VM.SVM) {
|
|
546
|
+
return deriveSvmCeaPda(address, targetChain, skipNetworkCheck);
|
|
547
|
+
}
|
|
515
548
|
const { cea, isDeployed } = yield (0, cea_utils_1.getCEAAddress)(address, targetChain);
|
|
516
549
|
return { address: cea, deployed: skipNetworkCheck ? null : isDeployed };
|
|
517
550
|
}
|