@pushchain/core 5.1.4-alpha.2 → 5.1.4-alpha.3

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.
@@ -255,11 +255,7 @@ function executeUoaToCea(ctx, params, executeFn) {
255
255
  ctx.pushClient.getBalance(ueaAddress),
256
256
  ]);
257
257
  const isUEADeployed = isNativePushEOA || ueaCode !== undefined;
258
- if (!isUEADeployed) {
259
- throw new Error('UEA is not deployed. Please send an inbound transaction to Push Chain first ' +
260
- '(e.g. sendTransaction with value) to deploy your Universal Execution Account before using outbound transfers.');
261
- }
262
- const ueaNonce = isNativePushEOA ? BigInt(0) : yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress);
258
+ const ueaNonce = (!isUEADeployed || isNativePushEOA) ? BigInt(0) : yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress);
263
259
  // Build the multicall that will execute ON Push Chain from UEA context
264
260
  // This includes: 1) approve PRC-20 (if needed), 2) call sendUniversalTxOutbound
265
261
  const pushChainMulticalls = [];
@@ -288,7 +284,11 @@ function executeUoaToCea(ctx, params, executeFn) {
288
284
  // Reuse ueaBalance fetched earlier (line 383) — no tx sent between, balance is stable
289
285
  const currentBalance = ueaBalance;
290
286
  let adjustedValue;
291
- if (currentBalance > EVM_NATIVE_VALUE_TARGET + EVM_GAS_RESERVE) {
287
+ if (!isUEADeployed) {
288
+ // UEA not yet deployed — fee-locking will deposit funds; use target value, excess is refunded
289
+ adjustedValue = nativeValueForGas > BigInt(0) ? EVM_NATIVE_VALUE_TARGET : nativeValueForGas;
290
+ }
291
+ else if (currentBalance > EVM_NATIVE_VALUE_TARGET + EVM_GAS_RESERVE) {
292
292
  // Enough balance: use 200 UPC target
293
293
  adjustedValue = EVM_NATIVE_VALUE_TARGET;
294
294
  }
@@ -354,7 +354,7 @@ function executeUoaToCea(ctx, params, executeFn) {
354
354
  nonce: ueaNonce,
355
355
  balance: ueaBalance,
356
356
  },
357
- _skipFeeLocking: true, // outbound executes on Push Chain, no external fee locking
357
+ _skipFeeLocking: isUEADeployed, // skip fee-locking only if UEA is already deployed
358
358
  };
359
359
  const response = yield executeFn(executeParams);
360
360
  // Add chain info to response
@@ -463,11 +463,7 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
463
463
  isUEADeployed = ueaCode !== undefined;
464
464
  ueaBalance = balance;
465
465
  }
466
- if (!isUEADeployed) {
467
- throw new Error('UEA is not deployed. Please send an inbound transaction to Push Chain first ' +
468
- '(e.g. sendTransaction with value) to deploy your Universal Execution Account before using outbound transfers.');
469
- }
470
- const ueaNonce = isNativePushEOASvm ? BigInt(0) : yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress);
466
+ const ueaNonce = (!isUEADeployed || isNativePushEOASvm) ? BigInt(0) : yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress);
471
467
  // --- Query gas fee (identical to EVM path) ---
472
468
  let gasFee = BigInt(0);
473
469
  let gasToken = selectors_1.ZERO_ADDRESS;
@@ -531,7 +527,7 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
531
527
  nonce: ueaNonce,
532
528
  balance: ueaBalance,
533
529
  },
534
- _skipFeeLocking: true, // outbound executes on Push Chain, no external fee locking
530
+ _skipFeeLocking: isUEADeployed, // skip fee-locking only if UEA is already deployed
535
531
  };
536
532
  const response = yield executeFn(executeParams);
537
533
  // Add chain info to response
@@ -617,7 +613,7 @@ function executeCeaToPush(ctx, params, executeFn) {
617
613
  // external chain), but that approach is racy: the balance can change between the SDK
618
614
  // query and relay execution, causing sendUniversalTxToUEA to revert with
619
615
  // InsufficientBalance. Pre-existing CEA funds remain parked and can be swept separately.
620
- let bridgeAmount = amount;
616
+ const bridgeAmount = amount;
621
617
  // Note: CEA contract may reject amount=0 in sendUniversalTxToUEA.
622
618
  // Keeping bridgeAmount as-is (0) for payload-only to test precompile behavior.
623
619
  // For ERC20 tokens, add approve call for the bridge amount
@@ -400,6 +400,7 @@ class PushChain {
400
400
  // Stored on instance so consumers can await it if needed: await client.accountStatusReady
401
401
  const ACCOUNT_STATUS_TIMEOUT = 30000;
402
402
  instance.accountStatusReady = Promise.race([
403
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
403
404
  instance.getAccountStatus().then(() => { }),
404
405
  new Promise((_, reject) => setTimeout(() => reject(new Error('Account status fetch timed out')), ACCOUNT_STATUS_TIMEOUT)),
405
406
  ]).catch(() => {
@@ -69,14 +69,22 @@ export declare function convertExecutorToOrigin(executorAddress: string, options
69
69
  _internal?: boolean;
70
70
  }): Promise<OriginAccountInfo>;
71
71
  /**
72
- * Derive the executor account (UEA or CEA) for a given Push Chain account.
72
+ * Derive the executor account (UEA or CEA) for a given account.
73
73
  *
74
- * @param address - Plain address string (e.g., "0xABC...")
75
- * @param options.chain - Target external chain for CEA derivation. If omitted, treats address as Push Chain account.
74
+ * - If account is on an external chain (Ethereum, Solana, etc.):
75
+ * Computes the UEA on Push Chain via the factory contract's computeUEA.
76
+ * If options.chain is an external chain, further derives the CEA on that chain.
77
+ *
78
+ * - If account is on Push Chain:
79
+ * Returns the address as-is (it's already a UEA or Push EOA).
80
+ * If options.chain is an external chain, derives the CEA on that chain.
81
+ *
82
+ * @param account - UniversalAccount with chain and address.
83
+ * @param options.chain - Target external chain for CEA derivation. If omitted, returns UEA.
76
84
  * @param options.skipNetworkCheck - If true, skip deployment check and return deployed: false.
77
85
  * @returns The derived executor account address and deployment status.
78
86
  */
79
- export declare function deriveExecutorAccount(address: string, options?: {
87
+ export declare function deriveExecutorAccount(account: UniversalAccount, options?: {
80
88
  chain?: CHAIN;
81
89
  skipNetworkCheck?: boolean;
82
90
  }): Promise<DerivedExecutorAccount>;
@@ -431,30 +431,97 @@ function getChainName(chain) {
431
431
  return entry ? entry[0] : chain;
432
432
  }
433
433
  /**
434
- * Derive the executor account (UEA or CEA) for a given Push Chain account.
434
+ * Derive the executor account (UEA or CEA) for a given account.
435
435
  *
436
- * @param address - Plain address string (e.g., "0xABC...")
437
- * @param options.chain - Target external chain for CEA derivation. If omitted, treats address as Push Chain account.
436
+ * - If account is on an external chain (Ethereum, Solana, etc.):
437
+ * Computes the UEA on Push Chain via the factory contract's computeUEA.
438
+ * If options.chain is an external chain, further derives the CEA on that chain.
439
+ *
440
+ * - If account is on Push Chain:
441
+ * Returns the address as-is (it's already a UEA or Push EOA).
442
+ * If options.chain is an external chain, derives the CEA on that chain.
443
+ *
444
+ * @param account - UniversalAccount with chain and address.
445
+ * @param options.chain - Target external chain for CEA derivation. If omitted, returns UEA.
438
446
  * @param options.skipNetworkCheck - If true, skip deployment check and return deployed: false.
439
447
  * @returns The derived executor account address and deployment status.
440
448
  */
441
- function deriveExecutorAccount(address, options) {
449
+ function deriveExecutorAccount(account, options) {
442
450
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
443
451
  var _a;
444
452
  const skipNetworkCheck = (_a = options === null || options === void 0 ? void 0 : options.skipNetworkCheck) !== null && _a !== void 0 ? _a : false;
445
453
  const targetChain = options === null || options === void 0 ? void 0 : options.chain;
446
- // If target chain is external, derive CEA on that chain
454
+ const { chain, address } = account;
455
+ // --- Case 1: Input is on an external chain ---
456
+ if (!isPushChain(chain)) {
457
+ const { vm, chainId } = chain_1.CHAIN_INFO[chain];
458
+ const pushNetwork = getPushNetworkFromChain(chain);
459
+ // Check cache for previously computed UEA
460
+ const cachedUea = accountCache.get(cache_1.CacheKeys.ueaAddressOnchain(chain, address, pushNetwork, vm));
461
+ let ueaAddress;
462
+ if (cachedUea) {
463
+ ueaAddress = cachedUea;
464
+ }
465
+ else {
466
+ // Compute UEA via factory contract
467
+ const pushChainKey = pushNetworkToChainKey(pushNetwork);
468
+ const pushClient = new push_client_1.PushClient({
469
+ rpcUrls: chain_1.CHAIN_INFO[pushChainKey].defaultRPC,
470
+ network: pushNetwork,
471
+ });
472
+ ueaAddress = yield pushClient.readContract({
473
+ address: pushClient.pushChainInfo.factoryAddress,
474
+ abi: factoryV1_1.FACTORY_V1,
475
+ functionName: 'computeUEA',
476
+ args: [
477
+ {
478
+ chainNamespace: chain_1.VM_NAMESPACE[vm],
479
+ chainId: chainId,
480
+ owner: vm === enums_1.VM.EVM
481
+ ? address
482
+ : vm === enums_1.VM.SVM
483
+ ? (0, viem_1.bytesToHex)(Uint8Array.from(bs58_1.bs58.decode(address)))
484
+ : address,
485
+ },
486
+ ],
487
+ });
488
+ // Cache the computed address
489
+ accountCache.set(cache_1.CacheKeys.ueaAddressOnchain(chain, address, pushNetwork, vm), ueaAddress);
490
+ }
491
+ // If target chain is external, derive CEA from the computed UEA
492
+ if (targetChain && !isPushChain(targetChain)) {
493
+ const { cea, isDeployed } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, targetChain);
494
+ return { address: cea, deployed: skipNetworkCheck ? false : isDeployed };
495
+ }
496
+ // Return UEA with deployment check
497
+ if (skipNetworkCheck) {
498
+ return { address: ueaAddress, deployed: false };
499
+ }
500
+ const pushChainKey = pushNetworkToChainKey(pushNetwork);
501
+ const pushClient = new push_client_1.PushClient({
502
+ rpcUrls: chain_1.CHAIN_INFO[pushChainKey].defaultRPC,
503
+ network: pushNetwork,
504
+ });
505
+ const byteCode = yield pushClient.publicClient.getCode({
506
+ address: ueaAddress,
507
+ });
508
+ const isDeployed = byteCode !== undefined;
509
+ accountCache.set(cache_1.CacheKeys.deploymentStatus(ueaAddress), isDeployed);
510
+ return { address: ueaAddress, deployed: isDeployed };
511
+ }
512
+ // --- Case 2: Input is on Push Chain ---
513
+ // If target chain is external, derive CEA
447
514
  if (targetChain && !isPushChain(targetChain)) {
448
515
  const { cea, isDeployed } = yield (0, cea_utils_1.getCEAAddress)(address, targetChain);
449
516
  return { address: cea, deployed: skipNetworkCheck ? false : isDeployed };
450
517
  }
451
- // Address is on Push Chain — return with deployment check
518
+ // Push address, no external target — return with deployment check
452
519
  if (skipNetworkCheck) {
453
520
  return { address: address, deployed: false };
454
521
  }
455
522
  const pushNetwork = targetChain && isPushChain(targetChain)
456
523
  ? getPushNetworkFromChain(targetChain)
457
- : enums_1.PUSH_NETWORK.TESTNET_DONUT;
524
+ : getPushNetworkFromChain(chain);
458
525
  const pushChainKey = pushNetworkToChainKey(pushNetwork);
459
526
  const pushClient = new push_client_1.PushClient({
460
527
  rpcUrls: chain_1.CHAIN_INFO[pushChainKey].defaultRPC,