@pushchain/core 2.1.0 → 2.1.2

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.
@@ -63,7 +63,7 @@ class Orchestrator {
63
63
  */
64
64
  execute(execute) {
65
65
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
66
- var _a, _b, _c;
66
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
67
67
  try {
68
68
  // FUNDS_TX short-circuit: Bridge tokens from origin chain to Push Chain
69
69
  // - EVM (Sepolia): UniversalGatewayV0
@@ -138,16 +138,41 @@ class Orchestrator {
138
138
  const bridgeToken = execute.funds.token.mechanism === 'approve'
139
139
  ? tokenAddr
140
140
  : '0x0000000000000000000000000000000000000000';
141
+ const { nonce } = yield this.getUeaStatusAndNonce();
142
+ const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', bridgeAmount);
143
+ // Get UEA info
144
+ const ueaAddress = this.computeUEAOffchain();
145
+ const ueaVersion = yield this.fetchUEAVersion();
146
+ const eip712Signature = yield this.signUniversalPayload(universalPayload, ueaAddress, ueaVersion);
147
+ const eip712SignatureHex = (0, viem_1.bytesToHex)(eip712Signature);
141
148
  let txHash;
142
149
  try {
150
+ // Compute minimal native amount to deposit for gas on Push Chain
151
+ const ueaAddressForGas = this.computeUEAOffchain();
152
+ const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddressForGas);
153
+ const nativeAmount = yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas);
143
154
  txHash = yield evmClient.writeContract({
144
155
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
145
156
  address: gatewayAddress,
146
- functionName: 'sendFunds',
147
- args: [recipient, bridgeToken, bridgeAmount, revertCFG],
157
+ functionName: 'sendTxWithFunds',
158
+ args: [
159
+ tokenAddr,
160
+ bridgeAmount,
161
+ universalPayload,
162
+ revertCFG,
163
+ eip712SignatureHex,
164
+ ],
148
165
  signer: this.universalSigner,
149
- value: isNative ? bridgeAmount : BigInt(0),
166
+ value: nativeAmount,
150
167
  });
168
+ // txHash = await evmClient.writeContract({
169
+ // abi: UNIVERSAL_GATEWAY_V0 as unknown as Abi,
170
+ // address: gatewayAddress,
171
+ // functionName: 'sendFunds',
172
+ // args: [recipient, bridgeToken, bridgeAmount, revertCFG],
173
+ // signer: this.universalSigner,
174
+ // value: isNative ? bridgeAmount : BigInt(0),
175
+ // });
151
176
  }
152
177
  catch (err) {
153
178
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_04);
@@ -169,6 +194,10 @@ class Orchestrator {
169
194
  const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
170
195
  const [whitelistPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
171
196
  const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
197
+ // pay-with-token gas abstraction is not supported on Solana
198
+ if (((_a = execute.funds) === null || _a === void 0 ? void 0 : _a.payWith) !== undefined) {
199
+ throw new Error('Pay-with token is not supported on Solana');
200
+ }
172
201
  let txSignature;
173
202
  // SVM-specific RevertSettings: bytes must be a Buffer
174
203
  const revertSvm = {
@@ -329,13 +358,13 @@ class Orchestrator {
329
358
  }
330
359
  const mechanism = execute.funds.token.mechanism;
331
360
  const { deployed, nonce } = yield this.getUeaStatusAndNonce();
332
- const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce);
361
+ const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendTxWithFunds');
333
362
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_01);
334
363
  // Compute required gas funding on Push Chain and current UEA balance
335
364
  const gasEstimate = execute.gasLimit || BigInt(1e7);
336
365
  const gasPrice = yield this.pushClient.getGasPrice();
337
366
  const requiredGasFee = gasEstimate * gasPrice;
338
- const payloadValue = (_a = execute.value) !== null && _a !== void 0 ? _a : BigInt(0);
367
+ const payloadValue = (_b = execute.value) !== null && _b !== void 0 ? _b : BigInt(0);
339
368
  const requiredFunds = requiredGasFee + payloadValue;
340
369
  const ueaAddress = this.computeUEAOffchain();
341
370
  const [ueaBalance] = yield Promise.all([
@@ -368,8 +397,8 @@ class Orchestrator {
368
397
  functionName: 'config',
369
398
  args: [configPda.toBase58()],
370
399
  });
371
- const minField = (_b = cfg.minCapUniversalTxUsd) !== null && _b !== void 0 ? _b : cfg.min_cap_universal_tx_usd;
372
- const maxField = (_c = cfg.maxCapUniversalTxUsd) !== null && _c !== void 0 ? _c : cfg.max_cap_universal_tx_usd;
400
+ const minField = (_c = cfg.minCapUniversalTxUsd) !== null && _c !== void 0 ? _c : cfg.min_cap_universal_tx_usd;
401
+ const maxField = (_d = cfg.maxCapUniversalTxUsd) !== null && _d !== void 0 ? _d : cfg.max_cap_universal_tx_usd;
373
402
  const minCapUsd = BigInt(minField.toString());
374
403
  const maxCapUsd = BigInt(maxField.toString());
375
404
  if (depositUsd < minCapUsd)
@@ -381,7 +410,7 @@ class Orchestrator {
381
410
  if (depositUsd > maxCapUsd)
382
411
  depositUsd = maxCapUsd;
383
412
  }
384
- catch (_d) {
413
+ catch (_m) {
385
414
  // best-effort; fallback to previous bounds if read fails
386
415
  }
387
416
  }
@@ -430,20 +459,73 @@ class Orchestrator {
430
459
  : (0, viem_1.bytesToHex)(eip712Signature);
431
460
  const evmClientEvm = evmClient;
432
461
  const gatewayAddressEvm = gatewayAddress;
433
- txHash = yield evmClientEvm.writeContract({
434
- abi: abi_1.UNIVERSAL_GATEWAY_V0,
435
- address: gatewayAddressEvm,
436
- functionName: 'sendTxWithFunds',
437
- args: [
438
- tokenAddr,
439
- bridgeAmount,
440
- universalPayload,
441
- revertCFG,
442
- eip712SignatureHex,
443
- ],
444
- signer: this.universalSigner,
445
- value: nativeAmount,
446
- });
462
+ // New behavior: if user provided a gasTokenAddress, pay gas in that token via Uniswap quote
463
+ // Determine pay-with token address, min-out and slippage
464
+ const payWith = execute.funds.payWith;
465
+ const gasTokenAddress = (_e = payWith === null || payWith === void 0 ? void 0 : payWith.token) === null || _e === void 0 ? void 0 : _e.address;
466
+ if (gasTokenAddress) {
467
+ if (chain !== enums_1.CHAIN.ETHEREUM_SEPOLIA) {
468
+ throw new Error(`Only ${push_chain_1.PushChain.utils.chains.getChainName(enums_1.CHAIN.ETHEREUM_SEPOLIA)} is supported for paying gas fees with ERC-20 tokens`);
469
+ }
470
+ let amountOutMinETH = (payWith === null || payWith === void 0 ? void 0 : payWith.minAmountOut) !== undefined
471
+ ? BigInt(payWith.minAmountOut)
472
+ : nativeAmount;
473
+ const slippageBps = (_f = payWith === null || payWith === void 0 ? void 0 : payWith.slippageBps) !== null && _f !== void 0 ? _f : 100;
474
+ amountOutMinETH = BigInt(push_chain_1.PushChain.utils.conversion.slippageToMinAmount(amountOutMinETH.toString(), { slippageBps }));
475
+ const { gasAmount } = yield this.calculateGasAmountFromAmountOutMinETH(gasTokenAddress, amountOutMinETH);
476
+ const deadline = BigInt(0);
477
+ // Ensure caller has enough balance of the gas token to cover fees
478
+ const ownerAddress = this.universalSigner.account
479
+ .address;
480
+ const gasTokenBalance = yield evmClientEvm.getErc20Balance({
481
+ tokenAddress: gasTokenAddress,
482
+ ownerAddress,
483
+ });
484
+ if (gasTokenBalance < gasAmount) {
485
+ const sym = (_h = (_g = payWith === null || payWith === void 0 ? void 0 : payWith.token) === null || _g === void 0 ? void 0 : _g.symbol) !== null && _h !== void 0 ? _h : 'gas token';
486
+ const decimals = (_k = (_j = payWith === null || payWith === void 0 ? void 0 : payWith.token) === null || _j === void 0 ? void 0 : _j.decimals) !== null && _k !== void 0 ? _k : 18;
487
+ const needFmt = push_chain_1.PushChain.utils.helpers.formatUnits(gasAmount, decimals);
488
+ const haveFmt = push_chain_1.PushChain.utils.helpers.formatUnits(gasTokenBalance, decimals);
489
+ throw new Error(`Insufficient ${sym} balance to cover gas fees: need ${needFmt}, have ${haveFmt}`);
490
+ }
491
+ // Approve gas token to gateway
492
+ yield this.ensureErc20Allowance(evmClientEvm, gasTokenAddress, gatewayAddressEvm, gasAmount);
493
+ // Approve bridge token already done above; now call new gateway signature (nonpayable)
494
+ txHash = yield evmClientEvm.writeContract({
495
+ abi: abi_1.UNIVERSAL_GATEWAY_V0,
496
+ address: gatewayAddressEvm,
497
+ functionName: 'sendTxWithFunds',
498
+ args: [
499
+ tokenAddr,
500
+ bridgeAmount,
501
+ gasTokenAddress,
502
+ gasAmount,
503
+ amountOutMinETH,
504
+ deadline,
505
+ universalPayload,
506
+ revertCFG,
507
+ eip712SignatureHex,
508
+ ],
509
+ signer: this.universalSigner,
510
+ });
511
+ }
512
+ else {
513
+ // Existing native-ETH value path
514
+ txHash = yield evmClientEvm.writeContract({
515
+ abi: abi_1.UNIVERSAL_GATEWAY_V0,
516
+ address: gatewayAddressEvm,
517
+ functionName: 'sendTxWithFunds',
518
+ args: [
519
+ tokenAddr,
520
+ bridgeAmount,
521
+ universalPayload,
522
+ revertCFG,
523
+ eip712SignatureHex,
524
+ ],
525
+ signer: this.universalSigner,
526
+ value: nativeAmount,
527
+ });
528
+ }
447
529
  }
448
530
  else {
449
531
  // SVM funds+payload path
@@ -457,6 +539,10 @@ class Orchestrator {
457
539
  // whitelistPda already computed above
458
540
  const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
459
541
  const priceUpdatePk = new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
542
+ // pay-with-token gas abstraction is not supported on Solana
543
+ if (((_l = execute.funds) === null || _l === void 0 ? void 0 : _l.payWith) !== undefined) {
544
+ throw new Error('Pay-with token is not supported on Solana');
545
+ }
460
546
  const isNative = mechanism === 'native' || execute.funds.token.symbol === 'SOL';
461
547
  const revertSvm2 = {
462
548
  fundRecipient: userPk,
@@ -1193,6 +1279,118 @@ class Orchestrator {
1193
1279
  }
1194
1280
  });
1195
1281
  }
1282
+ /**
1283
+ * Quotes exact-output on Uniswap V3 for EVM origin chains using QuoterV2.
1284
+ * Returns the minimum required input (amountIn) to receive the target amountOut.
1285
+ */
1286
+ _quoteExactOutput(amountOut_1, _a) {
1287
+ return tslib_1.__awaiter(this, arguments, void 0, function* (amountOut, { from, to, }) {
1288
+ var _b, _c, _d;
1289
+ const originChain = this.universalSigner.account.chain;
1290
+ if (originChain !== enums_1.CHAIN.ETHEREUM_MAINNET &&
1291
+ originChain !== enums_1.CHAIN.ETHEREUM_SEPOLIA) {
1292
+ throw new Error('Exact-output quoting is only supported on Ethereum Mainnet and Sepolia for now');
1293
+ }
1294
+ if (!from) {
1295
+ throw new Error('from token is required');
1296
+ }
1297
+ if (!to) {
1298
+ throw new Error('to token is required');
1299
+ }
1300
+ const rpcUrls = this.getRpcUrls()[originChain] || chain_1.CHAIN_INFO[originChain].defaultRPC;
1301
+ const evm = new evm_client_1.EvmClient({ rpcUrls });
1302
+ const factoryFromConfig = (_b = chain_1.CHAIN_INFO[originChain].dex) === null || _b === void 0 ? void 0 : _b.uniV3Factory;
1303
+ const quoterFromConfig = (_c = chain_1.CHAIN_INFO[originChain].dex) === null || _c === void 0 ? void 0 : _c.uniV3QuoterV2;
1304
+ if (!factoryFromConfig || !quoterFromConfig) {
1305
+ throw new Error('Uniswap V3 addresses not configured for this chain');
1306
+ }
1307
+ const UNISWAP_V3_FACTORY = factoryFromConfig;
1308
+ const UNISWAP_V3_QUOTER_V2 = quoterFromConfig;
1309
+ const factoryAbi = (0, viem_1.parseAbi)([
1310
+ 'function getPool(address tokenA, address tokenB, uint24 fee) view returns (address)',
1311
+ ]);
1312
+ const quoterAbi = (0, viem_1.parseAbi)([
1313
+ 'function quoteExactOutputSingle((address tokenIn, address tokenOut, uint256 amount, uint24 fee, uint160 sqrtPriceLimitX96) params) returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)',
1314
+ ]);
1315
+ const poolAbi = (0, viem_1.parseAbi)([
1316
+ 'function liquidity() view returns (uint128)',
1317
+ ]);
1318
+ const feeTiers = [100, 500, 3000, 10000];
1319
+ let bestAmountIn = null;
1320
+ let bestFee = null;
1321
+ for (const fee of feeTiers) {
1322
+ // Find pool address for this fee tier
1323
+ const poolAddress = yield evm.readContract({
1324
+ abi: factoryAbi,
1325
+ address: UNISWAP_V3_FACTORY,
1326
+ functionName: 'getPool',
1327
+ args: [from.address, to.address, fee],
1328
+ });
1329
+ const isZero = !poolAddress ||
1330
+ poolAddress.toLowerCase() ===
1331
+ '0x0000000000000000000000000000000000000000';
1332
+ if (isZero)
1333
+ continue;
1334
+ // Skip uninitialized/empty pools to avoid Quoter reverts
1335
+ try {
1336
+ const liquidity = yield evm.readContract({
1337
+ abi: poolAbi,
1338
+ address: poolAddress,
1339
+ functionName: 'liquidity',
1340
+ args: [],
1341
+ });
1342
+ if (!liquidity || liquidity === BigInt(0))
1343
+ continue;
1344
+ }
1345
+ catch (_e) {
1346
+ continue;
1347
+ }
1348
+ // Quote exact output single for this fee tier
1349
+ try {
1350
+ const result = yield evm.readContract({
1351
+ abi: quoterAbi,
1352
+ address: UNISWAP_V3_QUOTER_V2,
1353
+ functionName: 'quoteExactOutputSingle',
1354
+ args: [
1355
+ {
1356
+ tokenIn: from.address,
1357
+ tokenOut: to.address,
1358
+ amount: amountOut,
1359
+ fee,
1360
+ sqrtPriceLimitX96: BigInt(0),
1361
+ },
1362
+ ],
1363
+ });
1364
+ const amountIn = (_d = result === null || result === void 0 ? void 0 : result[0]) !== null && _d !== void 0 ? _d : BigInt(0);
1365
+ if (amountIn === BigInt(0))
1366
+ continue;
1367
+ if (bestAmountIn === null || amountIn < bestAmountIn) {
1368
+ bestAmountIn = amountIn;
1369
+ bestFee = fee;
1370
+ }
1371
+ }
1372
+ catch (_f) {
1373
+ // try next fee
1374
+ }
1375
+ }
1376
+ if (bestAmountIn === null || bestFee === null) {
1377
+ throw new Error('No direct Uniswap V3 pool found for the given token pair on common fee tiers');
1378
+ }
1379
+ const amountInBig = BigInt(bestAmountIn);
1380
+ const amountInHuman = parseFloat(push_chain_1.PushChain.utils.helpers.formatUnits(amountInBig, {
1381
+ decimals: from.decimals,
1382
+ }));
1383
+ const amountOutHuman = parseFloat(push_chain_1.PushChain.utils.helpers.formatUnits(amountOut, { decimals: to.decimals }));
1384
+ const rate = amountInHuman > 0 ? amountOutHuman / amountInHuman : 0;
1385
+ return {
1386
+ amountIn: bestAmountIn.toString(),
1387
+ amountOut: amountOut.toString(),
1388
+ rate,
1389
+ route: [from.symbol, to.symbol],
1390
+ timestamp: Date.now(),
1391
+ };
1392
+ });
1393
+ }
1196
1394
  ensureErc20Allowance(evmClient, tokenAddress, spender, requiredAmount) {
1197
1395
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
1198
1396
  const chain = this.universalSigner.account.chain;
@@ -1303,26 +1501,53 @@ class Orchestrator {
1303
1501
  });
1304
1502
  }
1305
1503
  /**
1306
- * Builds UniversalPayload for the gateway and computes the native gas deposit.
1504
+ * For sendFunds, we will call internally the sendTxWithFunds.
1307
1505
  */
1308
- buildGatewayPayloadAndGas(execute, nonce) {
1506
+ buildGatewayPayloadAndGas(execute, nonce, type, fundsValue) {
1309
1507
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
1310
1508
  var _a, _b;
1311
1509
  const gasEstimate = execute.gasLimit || BigInt(1e7);
1312
1510
  const payloadValue = (_a = execute.value) !== null && _a !== void 0 ? _a : BigInt(0);
1313
1511
  const gasAmount = (_b = execute.value) !== null && _b !== void 0 ? _b : BigInt(0);
1314
- const universalPayload = {
1315
- to: execute.to,
1316
- value: payloadValue,
1317
- data: execute.data || '0x',
1318
- gasLimit: gasEstimate,
1319
- maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
1320
- maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
1321
- nonce,
1322
- deadline: execute.deadline || BigInt(9999999999),
1323
- vType: tx_1.VerificationType.signedVerification,
1324
- };
1325
- return { payload: universalPayload, gasAmount };
1512
+ if (type === 'sendTxWithFunds') {
1513
+ if (fundsValue)
1514
+ throw new Error('fundsValue property must be empty');
1515
+ const universalPayload = {
1516
+ to: execute.to,
1517
+ value: payloadValue,
1518
+ data: execute.data || '0x',
1519
+ gasLimit: gasEstimate,
1520
+ maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
1521
+ maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
1522
+ nonce,
1523
+ deadline: execute.deadline || BigInt(9999999999),
1524
+ vType: tx_1.VerificationType.signedVerification,
1525
+ };
1526
+ return { payload: universalPayload, gasAmount };
1527
+ }
1528
+ else {
1529
+ if (!fundsValue)
1530
+ throw new Error('fundsValue property must not be empty');
1531
+ // The data will be the abi-encoded transfer function from erc-20 function. The recipient will be `execute.to`, the value
1532
+ // will be the fundsValue property.
1533
+ const data = (0, viem_1.encodeFunctionData)({
1534
+ abi: abi_1.ERC20_EVM,
1535
+ functionName: 'transfer',
1536
+ args: [execute.to, fundsValue],
1537
+ });
1538
+ const universalPayload = {
1539
+ to: viem_1.zeroAddress, // We can't simply do `0x` because we will get an error when eip712 signing the transaction.
1540
+ value: payloadValue,
1541
+ data,
1542
+ gasLimit: gasEstimate,
1543
+ maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
1544
+ maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
1545
+ nonce,
1546
+ deadline: execute.deadline || BigInt(9999999999),
1547
+ vType: tx_1.VerificationType.signedVerification,
1548
+ };
1549
+ return { payload: universalPayload, gasAmount };
1550
+ }
1326
1551
  });
1327
1552
  }
1328
1553
  /********************************** HELPER FUNCTIONS **************************************************/
@@ -1719,6 +1944,102 @@ class Orchestrator {
1719
1944
  return version;
1720
1945
  });
1721
1946
  }
1947
+ // Build EVM gas payment parameters when paying gas with an ERC-20 token
1948
+ calculateGasAmountFromAmountOutMinETH(gasTokenAddress, amountOutMinETH) {
1949
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1950
+ var _a, _b, _c;
1951
+ const originChain = this.universalSigner.account.chain;
1952
+ if (originChain !== enums_1.CHAIN.ETHEREUM_SEPOLIA &&
1953
+ originChain !== enums_1.CHAIN.ARBITRUM_SEPOLIA &&
1954
+ originChain !== enums_1.CHAIN.BASE_SEPOLIA) {
1955
+ throw new Error('Gas payment in ERC-20 is supported only on Ethereum Sepolia, Arbitrum Sepolia, and Base Sepolia for now');
1956
+ }
1957
+ // Resolve WETH: prefer chain config, fallback to registry
1958
+ const WETH = (_a = chain_1.CHAIN_INFO[originChain].dex) === null || _a === void 0 ? void 0 : _a.weth;
1959
+ if (!WETH)
1960
+ throw new Error('WETH address not configured for this chain');
1961
+ let gasAmount;
1962
+ if (gasTokenAddress.toLowerCase() === WETH.toLowerCase()) {
1963
+ gasAmount = BigInt(amountOutMinETH);
1964
+ }
1965
+ else {
1966
+ // Resolve token objects from registries
1967
+ const fromList = (_b = tokens_1.PAYABLE_TOKENS[originChain]) !== null && _b !== void 0 ? _b : [];
1968
+ const fromToken = fromList.find((t) => (t.address || '').toLowerCase() === gasTokenAddress.toLowerCase());
1969
+ const toList = ((_c = tokens_1.MOVEABLE_TOKENS[originChain]) !== null && _c !== void 0 ? _c : []);
1970
+ const toToken = toList.find((t) => t.symbol === 'WETH' ||
1971
+ (t.address || '').toLowerCase() === (WETH || '').toLowerCase());
1972
+ if (!fromToken || !toToken) {
1973
+ throw new Error('Token not supported for quoting');
1974
+ }
1975
+ const targetOut = BigInt(amountOutMinETH);
1976
+ const exactOutQuote = yield this._quoteExactOutput(targetOut, {
1977
+ from: fromToken,
1978
+ to: toToken,
1979
+ });
1980
+ const requiredIn = BigInt(exactOutQuote.amountIn);
1981
+ gasAmount = (requiredIn * BigInt(101)) / BigInt(100); // 1% safety margin
1982
+ }
1983
+ return { gasAmount };
1984
+ });
1985
+ }
1986
+ calculateNativeAmountForDeposit(chain, requiredFunds, ueaBalance) {
1987
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1988
+ var _a, _b;
1989
+ // Determine USD to deposit via gateway (8 decimals) with caps: min=$1, max=$10
1990
+ const oneUsd = push_chain_1.PushChain.utils.helpers.parseUnits('1', 8);
1991
+ const tenUsd = push_chain_1.PushChain.utils.helpers.parseUnits('10', 8);
1992
+ const deficit = requiredFunds > ueaBalance ? requiredFunds - ueaBalance : BigInt(0);
1993
+ let depositUsd = deficit > BigInt(0) ? this.pushClient.pushToUSDC(deficit) : oneUsd;
1994
+ if (depositUsd < oneUsd)
1995
+ depositUsd = oneUsd;
1996
+ if (depositUsd > tenUsd)
1997
+ throw new Error('Deposit value exceeds max $10 worth of native token');
1998
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_02, depositUsd);
1999
+ // If SVM, clamp depositUsd to on-chain Config caps
2000
+ if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM) {
2001
+ const svmClient = new svm_client_1.SvmClient({
2002
+ rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
2003
+ chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
2004
+ });
2005
+ const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
2006
+ const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
2007
+ try {
2008
+ const cfg = yield svmClient.readContract({
2009
+ abi: abi_1.SVM_GATEWAY_IDL,
2010
+ address: abi_1.SVM_GATEWAY_IDL.address,
2011
+ functionName: 'config',
2012
+ args: [configPda.toBase58()],
2013
+ });
2014
+ const minField = (_a = cfg.minCapUniversalTxUsd) !== null && _a !== void 0 ? _a : cfg.min_cap_universal_tx_usd;
2015
+ const maxField = (_b = cfg.maxCapUniversalTxUsd) !== null && _b !== void 0 ? _b : cfg.max_cap_universal_tx_usd;
2016
+ const minCapUsd = BigInt(minField.toString());
2017
+ const maxCapUsd = BigInt(maxField.toString());
2018
+ if (depositUsd < minCapUsd)
2019
+ depositUsd = minCapUsd;
2020
+ // Add 20% safety margin to avoid BelowMinCap due to price drift
2021
+ const withMargin = (minCapUsd * BigInt(12)) / BigInt(10);
2022
+ if (depositUsd < withMargin)
2023
+ depositUsd = withMargin;
2024
+ if (depositUsd > maxCapUsd)
2025
+ depositUsd = maxCapUsd;
2026
+ }
2027
+ catch (_c) {
2028
+ // best-effort; fallback to previous bounds if read fails
2029
+ }
2030
+ }
2031
+ // Convert USD(8) -> native units using pricing path
2032
+ const nativeTokenUsdPrice = yield new price_fetch_1.PriceFetch(this.rpcUrls).getPrice(chain); // 8 decimals
2033
+ const nativeDecimals = chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM ? 9 : 18;
2034
+ const oneNativeUnit = push_chain_1.PushChain.utils.helpers.parseUnits('1', nativeDecimals);
2035
+ // Ceil division to avoid rounding below min USD on-chain
2036
+ let nativeAmount = (depositUsd * oneNativeUnit + (nativeTokenUsdPrice - BigInt(1))) /
2037
+ nativeTokenUsdPrice;
2038
+ // Add 1 unit safety to avoid BelowMinCap from rounding differences
2039
+ nativeAmount = nativeAmount + BigInt(1);
2040
+ return nativeAmount;
2041
+ });
2042
+ }
1722
2043
  }
1723
2044
  exports.Orchestrator = Orchestrator;
1724
2045
  //# sourceMappingURL=orchestrator.js.map