@pushchain/core 2.1.11 → 3.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 (35) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +4 -3
  3. package/src/lib/constants/abi/erc20.evm.d.ts +33 -0
  4. package/src/lib/constants/abi/erc20.evm.js +19 -0
  5. package/src/lib/constants/abi/erc20.evm.js.map +1 -1
  6. package/src/lib/constants/abi/universalGatewayV0.evm.d.ts +56 -9
  7. package/src/lib/constants/abi/universalGatewayV0.evm.js +1023 -64
  8. package/src/lib/constants/abi/universalGatewayV0.evm.js.map +1 -1
  9. package/src/lib/constants/abi/universalGatewayV0.json +1223 -206
  10. package/src/lib/constants/chain.d.ts +4 -0
  11. package/src/lib/constants/chain.js +24 -2
  12. package/src/lib/constants/chain.js.map +1 -1
  13. package/src/lib/constants/tokens.d.ts +1 -0
  14. package/src/lib/constants/tokens.js +3 -0
  15. package/src/lib/constants/tokens.js.map +1 -1
  16. package/src/lib/generated/v1/tx.d.ts +1 -2
  17. package/src/lib/generated/v1/tx.js +2 -1
  18. package/src/lib/generated/v1/tx.js.map +1 -1
  19. package/src/lib/orchestrator/orchestrator.d.ts +6 -2
  20. package/src/lib/orchestrator/orchestrator.js +645 -336
  21. package/src/lib/orchestrator/orchestrator.js.map +1 -1
  22. package/src/lib/orchestrator/payload-builders.d.ts +5 -0
  23. package/src/lib/orchestrator/payload-builders.js +58 -0
  24. package/src/lib/orchestrator/payload-builders.js.map +1 -0
  25. package/src/lib/push-chain/helpers/abis.d.ts +31 -0
  26. package/src/lib/push-chain/helpers/abis.js +75 -0
  27. package/src/lib/push-chain/helpers/abis.js.map +1 -0
  28. package/src/lib/push-chain/helpers/addresses.d.ts +1 -0
  29. package/src/lib/push-chain/helpers/addresses.js +5 -0
  30. package/src/lib/push-chain/helpers/addresses.js.map +1 -0
  31. package/src/lib/utils.d.ts +9 -0
  32. package/src/lib/utils.js +73 -0
  33. package/src/lib/utils.js.map +1 -1
  34. package/src/lib/vm-client/svm-client.js +26 -3
  35. package/src/lib/vm-client/svm-client.js.map +1 -1
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const viem_1 = require("viem");
6
6
  const push_chain_1 = require("../push-chain/push-chain");
7
7
  const enums_1 = require("../constants/enums");
8
+ const payload_builders_1 = require("./payload-builders");
8
9
  const evm_client_1 = require("../vm-client/evm-client");
9
10
  const chain_1 = require("../constants/chain");
10
11
  const abi_1 = require("../constants/abi");
@@ -70,13 +71,21 @@ class Orchestrator {
70
71
  // - SVM (Solana Devnet): pushsolanagateway
71
72
  if (execute.funds) {
72
73
  if (!execute.data || execute.data === '0x') {
73
- // Disallow user-provided `value` for funds-only bridging. The SDK derives
74
- // origin-chain msg.value automatically from the funds input:
75
- // - Native path: msg.value = bridgeAmount
76
- // - ERC-20 path: msg.value = 0
77
- if (execute.value !== undefined && execute.value !== BigInt(0)) {
78
- throw new Error('Do not set `value` when using funds bridging; the SDK sets origin msg.value from `funds.amount` automatically');
79
- }
74
+ // @@@@@@@@@@@@@@@
75
+ // @@@@@@@@@@@@@@@
76
+ // @@@@@@@@@@@@@@@
77
+ // @@@@@@@@@@@@@@@
78
+ // @@@@@@@@@@@@@@@
79
+ // @@@@@@@@@@@@@@@
80
+ // // Disallow user-provided `value` for funds-only bridging. The SDK derives
81
+ // // origin-chain msg.value automatically from the funds input:
82
+ // // - Native path: msg.value = bridgeAmount
83
+ // // - ERC-20 path: msg.value = 0
84
+ // if (execute.value !== undefined && execute.value !== BigInt(0)) {
85
+ // throw new Error(
86
+ // 'Do not set `value` when using funds bridging; the SDK sets origin msg.value from `funds.amount` automatically'
87
+ // );
88
+ // }
80
89
  const chain = this.universalSigner.account.chain;
81
90
  const { vm } = chain_1.CHAIN_INFO[chain];
82
91
  if (!(chain === enums_1.CHAIN.ETHEREUM_SEPOLIA ||
@@ -138,16 +147,53 @@ class Orchestrator {
138
147
  const bridgeToken = execute.funds.token.mechanism === 'approve'
139
148
  ? tokenAddr
140
149
  : '0x0000000000000000000000000000000000000000';
150
+ const { nonce } = yield this.getUeaStatusAndNonce();
151
+ const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', bridgeAmount);
152
+ // Get UEA info
153
+ const ueaAddress = this.computeUEAOffchain();
154
+ const ueaVersion = yield this.fetchUEAVersion();
155
+ const eip712Signature = yield this.signUniversalPayload(universalPayload, ueaAddress, ueaVersion);
156
+ const eip712SignatureHex = (0, viem_1.bytesToHex)(eip712Signature);
141
157
  let txHash;
142
158
  try {
143
- txHash = yield evmClient.writeContract({
144
- abi: abi_1.UNIVERSAL_GATEWAY_V0,
145
- address: gatewayAddress,
146
- functionName: 'sendFunds',
147
- args: [recipient, bridgeToken, bridgeAmount, revertCFG],
148
- signer: this.universalSigner,
149
- value: isNative ? bridgeAmount : BigInt(0),
150
- });
159
+ // Compute minimal native amount to deposit for gas on Push Chain
160
+ const ueaAddressForGas = this.computeUEAOffchain();
161
+ const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddressForGas);
162
+ const nativeAmount = yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas);
163
+ console.log([
164
+ tokenAddr,
165
+ bridgeAmount,
166
+ universalPayload,
167
+ revertCFG,
168
+ '0x',
169
+ ]);
170
+ const ueaAddress = this.computeUEAOffchain();
171
+ if (execute.to.toLowerCase() === ueaAddress.toLowerCase()) {
172
+ txHash = yield evmClient.writeContract({
173
+ abi: abi_1.UNIVERSAL_GATEWAY_V0,
174
+ address: gatewayAddress,
175
+ functionName: 'sendFunds',
176
+ args: [recipient, bridgeToken, bridgeAmount, revertCFG],
177
+ signer: this.universalSigner,
178
+ value: isNative ? bridgeAmount : BigInt(0),
179
+ });
180
+ }
181
+ else {
182
+ txHash = yield evmClient.writeContract({
183
+ abi: abi_1.UNIVERSAL_GATEWAY_V0,
184
+ address: gatewayAddress,
185
+ functionName: 'sendTxWithFunds_new',
186
+ args: [
187
+ tokenAddr,
188
+ bridgeAmount,
189
+ universalPayload,
190
+ revertCFG,
191
+ '0x',
192
+ ],
193
+ signer: this.universalSigner,
194
+ value: nativeAmount,
195
+ });
196
+ }
151
197
  }
152
198
  catch (err) {
153
199
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_04);
@@ -156,10 +202,12 @@ class Orchestrator {
156
202
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
157
203
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol);
158
204
  yield this.waitForEvmConfirmationsWithCountdown(evmClient, txHash, 4, 210000);
159
- // After origin confirmations, query Push Chain for UniversalTx status
160
- yield this.queryUniversalTxStatusFromGatewayTx(evmClient, gatewayAddress, txHash, 'sendFunds');
161
- const tx = yield evmClient.getTransaction(txHash);
162
- return yield this.transformToUniversalTxResponse(tx);
205
+ const pushChainUniversalTx = yield this.queryUniversalTxStatusFromGatewayTx(evmClient, gatewayAddress, txHash, execute.to === ueaAddress ? 'sendFunds' : 'sendTxWithFunds');
206
+ const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
207
+ const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
208
+ const response = yield this.transformToUniversalTxResponse(tx);
209
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [response]);
210
+ return response;
163
211
  }
164
212
  else {
165
213
  // SVM path (Solana Devnet)
@@ -185,29 +233,55 @@ class Orchestrator {
185
233
  // Native SOL funds-only
186
234
  // Compute a local whitelist PDA to avoid TS scope issues
187
235
  const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
188
- txSignature = yield svmClient.writeContract({
189
- abi: abi_1.SVM_GATEWAY_IDL,
190
- address: programId.toBase58(),
191
- functionName: 'sendFunds', // -> unified sendFunds(recipient, bridge_token, bridge_amount, revert_cfg)
192
- args: [
193
- recipientEvm20,
194
- web3_js_1.PublicKey.default,
236
+ //////// @@@@@@@
237
+ //////// @@@@@@@
238
+ //////// @@@@@@@
239
+ //////// @@@@@@@
240
+ //////// @@@@@@@
241
+ //////// @@@@@@@
242
+ //////// @@@@@@@
243
+ //////// @@@@@@@
244
+ //////// @@@@@@@
245
+ // DO THE SAME AS FOR BELOW, BUT NOW FOR NATIVE.
246
+ // for sendTxWithFunds multicall
247
+ const ueaAddress = this.computeUEAOffchain();
248
+ if (execute.to === ueaAddress) {
249
+ txSignature = yield svmClient.writeContract({
250
+ abi: abi_1.SVM_GATEWAY_IDL,
251
+ address: programId.toBase58(),
252
+ functionName: 'sendFunds', // -> unified sendFunds(recipient, bridge_token, bridge_amount, revert_cfg)
253
+ args: [
254
+ recipientEvm20,
255
+ web3_js_1.PublicKey.default,
256
+ bridgeAmount,
257
+ revertSvm,
258
+ ],
259
+ signer: this.universalSigner,
260
+ accounts: {
261
+ config: configPda,
262
+ vault: vaultPda,
263
+ user: userPk,
264
+ tokenWhitelist: whitelistPdaLocal,
265
+ userTokenAccount: userPk,
266
+ gatewayTokenAccount: vaultPda,
267
+ bridgeToken: web3_js_1.PublicKey.default,
268
+ tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
269
+ systemProgram: web3_js_1.SystemProgram.programId,
270
+ },
271
+ });
272
+ }
273
+ else {
274
+ const { nonce } = yield this.getUeaStatusAndNonce();
275
+ const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', execute.funds.amount);
276
+ const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddress);
277
+ txSignature = yield this._sendSVMTxWithFunds({
278
+ execute,
279
+ mechanism: execute.funds.token.mechanism,
280
+ universalPayload,
195
281
  bridgeAmount,
196
- revertSvm,
197
- ],
198
- signer: this.universalSigner,
199
- accounts: {
200
- config: configPda,
201
- vault: vaultPda,
202
- user: userPk,
203
- tokenWhitelist: whitelistPdaLocal,
204
- userTokenAccount: userPk,
205
- gatewayTokenAccount: vaultPda,
206
- bridgeToken: web3_js_1.PublicKey.default,
207
- tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
208
- systemProgram: web3_js_1.SystemProgram.programId,
209
- },
210
- });
282
+ nativeAmount: yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas),
283
+ });
284
+ }
211
285
  }
212
286
  else if (execute.funds.token.mechanism === 'approve') {
213
287
  // SPL token funds-only (requires pre-existing ATAs)
@@ -225,24 +299,40 @@ class Orchestrator {
225
299
  TOKEN_PROGRAM_ID.toBuffer(),
226
300
  mintPk.toBuffer(),
227
301
  ], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
228
- txSignature = yield svmClient.writeContract({
229
- abi: abi_1.SVM_GATEWAY_IDL,
230
- address: programId.toBase58(),
231
- functionName: 'sendFunds',
232
- args: [recipientEvm20, mintPk, bridgeAmount, revertSvm],
233
- signer: this.universalSigner,
234
- accounts: {
235
- config: configPda,
236
- vault: vaultPda,
237
- tokenWhitelist: whitelistPda,
238
- userTokenAccount: userAta,
239
- gatewayTokenAccount: vaultAta,
240
- user: userPk,
241
- bridgeToken: mintPk,
242
- tokenProgram: TOKEN_PROGRAM_ID,
243
- systemProgram: web3_js_1.SystemProgram.programId,
244
- },
245
- });
302
+ const ueaAddress = this.computeUEAOffchain();
303
+ if (execute.to === ueaAddress) {
304
+ // vitalik
305
+ txSignature = yield svmClient.writeContract({
306
+ abi: abi_1.SVM_GATEWAY_IDL,
307
+ address: programId.toBase58(),
308
+ functionName: 'sendFunds',
309
+ args: [recipientEvm20, mintPk, bridgeAmount, revertSvm],
310
+ signer: this.universalSigner,
311
+ accounts: {
312
+ config: configPda,
313
+ vault: vaultPda,
314
+ tokenWhitelist: whitelistPda,
315
+ userTokenAccount: userAta,
316
+ gatewayTokenAccount: vaultAta,
317
+ user: userPk,
318
+ bridgeToken: mintPk,
319
+ tokenProgram: TOKEN_PROGRAM_ID,
320
+ systemProgram: web3_js_1.SystemProgram.programId,
321
+ },
322
+ });
323
+ }
324
+ else {
325
+ const { nonce } = yield this.getUeaStatusAndNonce();
326
+ const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', execute.funds.amount);
327
+ const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddress);
328
+ txSignature = yield this._sendSVMTxWithFunds({
329
+ execute,
330
+ mechanism: execute.funds.token.mechanism,
331
+ universalPayload,
332
+ bridgeAmount,
333
+ nativeAmount: yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas),
334
+ });
335
+ }
246
336
  }
247
337
  else {
248
338
  throw new Error('Unsupported token mechanism on Solana');
@@ -255,61 +345,13 @@ class Orchestrator {
255
345
  timeoutMs: 300000,
256
346
  });
257
347
  // After origin confirmations, query Push Chain for UniversalTx status (SVM)
258
- yield this.queryUniversalTxStatusFromGatewayTx(undefined, undefined, txSignature, 'sendFunds');
348
+ const pushChainUniversalTx = yield this.queryUniversalTxStatusFromGatewayTx(undefined, undefined, txSignature, 'sendFunds');
259
349
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
260
- // Build a minimal UniversalTxResponse for SVM origin
261
- const chainId = chain_1.CHAIN_INFO[chain].chainId;
262
- const origin = `${chain_1.VM_NAMESPACE[vm]}:${chainId}:${this.universalSigner.account.address}`;
263
- const universalTxResponse = {
264
- hash: txSignature,
265
- origin,
266
- blockNumber: BigInt(0),
267
- blockHash: '',
268
- transactionIndex: 0,
269
- chainId,
270
- from: this.universalSigner.account.address,
271
- to: '0x0000000000000000000000000000000000000000',
272
- nonce: 0,
273
- data: '0x',
274
- value: BigInt(0),
275
- gasLimit: BigInt(0),
276
- gasPrice: undefined,
277
- maxFeePerGas: undefined,
278
- maxPriorityFeePerGas: undefined,
279
- accessList: [],
280
- wait: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
281
- return ({
282
- hash: txSignature,
283
- blockNumber: BigInt(0),
284
- blockHash: '',
285
- transactionIndex: 0,
286
- from: this.universalSigner.account.address,
287
- to: '0x0000000000000000000000000000000000000000',
288
- contractAddress: null,
289
- gasPrice: BigInt(0),
290
- gasUsed: BigInt(0),
291
- cumulativeGasUsed: BigInt(0),
292
- logs: [],
293
- logsBloom: '0x',
294
- status: 1,
295
- raw: {
296
- from: this.universalSigner.account.address,
297
- to: '0x0000000000000000000000000000000000000000',
298
- },
299
- });
300
- }),
301
- type: '99',
302
- typeVerbose: 'universal',
303
- signature: { r: '0x0', s: '0x0', v: 0 },
304
- raw: {
305
- from: this.universalSigner.account.address,
306
- to: '0x0000000000000000000000000000000000000000',
307
- nonce: 0,
308
- data: '0x',
309
- value: BigInt(0),
310
- },
311
- };
312
- return universalTxResponse;
350
+ const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
351
+ const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
352
+ const response = yield this.transformToUniversalTxResponse(tx);
353
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [response]);
354
+ return response;
313
355
  }
314
356
  }
315
357
  else {
@@ -333,7 +375,7 @@ class Orchestrator {
333
375
  }
334
376
  const mechanism = execute.funds.token.mechanism;
335
377
  const { deployed, nonce } = yield this.getUeaStatusAndNonce();
336
- const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce);
378
+ const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendTxWithFunds', execute.funds.amount);
337
379
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_01);
338
380
  // Compute required gas funding on Push Chain and current UEA balance
339
381
  const gasEstimate = execute.gasLimit || BigInt(1e7);
@@ -426,14 +468,24 @@ class Orchestrator {
426
468
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_02, ueaAddress, deployed);
427
469
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_01);
428
470
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_02);
429
- const ueaVersion = yield this.fetchUEAVersion();
430
- const eip712Signature = yield this.signUniversalPayload(universalPayload, ueaAddress, ueaVersion);
431
471
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
432
- const eip712SignatureHex = typeof eip712Signature === 'string'
433
- ? eip712Signature
434
- : (0, viem_1.bytesToHex)(eip712Signature);
435
472
  const evmClientEvm = evmClient;
436
473
  const gatewayAddressEvm = gatewayAddress;
474
+ // @@@@@@@@@@@@
475
+ // txHash = await evmClientEvm.writeContract({
476
+ // abi: UNIVERSAL_GATEWAY_V0 as unknown as Abi,
477
+ // address: gatewayAddressEvm,
478
+ // functionName: 'sendTxWithFunds',
479
+ // args: [
480
+ // tokenAddr,
481
+ // bridgeAmount,
482
+ // universalPayload,
483
+ // revertCFG,
484
+ // '0x',
485
+ // ],
486
+ // signer: this.universalSigner,
487
+ // value: nativeAmount,
488
+ // });
437
489
  // New behavior: if user provided a gasTokenAddress, pay gas in that token via Uniswap quote
438
490
  // Determine pay-with token address, min-out and slippage
439
491
  const payWith = execute.payGasWith;
@@ -469,7 +521,7 @@ class Orchestrator {
469
521
  txHash = yield evmClientEvm.writeContract({
470
522
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
471
523
  address: gatewayAddressEvm,
472
- functionName: 'sendTxWithFunds',
524
+ functionName: 'sendTxWithFunds_new',
473
525
  args: [
474
526
  tokenAddr,
475
527
  bridgeAmount,
@@ -479,7 +531,7 @@ class Orchestrator {
479
531
  deadline,
480
532
  universalPayload,
481
533
  revertCFG,
482
- eip712SignatureHex,
534
+ '0x',
483
535
  ],
484
536
  signer: this.universalSigner,
485
537
  });
@@ -489,13 +541,13 @@ class Orchestrator {
489
541
  txHash = yield evmClientEvm.writeContract({
490
542
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
491
543
  address: gatewayAddressEvm,
492
- functionName: 'sendTxWithFunds',
544
+ functionName: 'sendTxWithFunds_new',
493
545
  args: [
494
546
  tokenAddr,
495
547
  bridgeAmount,
496
548
  universalPayload,
497
549
  revertCFG,
498
- eip712SignatureHex,
550
+ '0x',
499
551
  ],
500
552
  signer: this.universalSigner,
501
553
  value: nativeAmount,
@@ -503,103 +555,13 @@ class Orchestrator {
503
555
  }
504
556
  }
505
557
  else {
506
- // SVM funds+payload path
507
- const svmClient = new svm_client_1.SvmClient({
508
- rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
509
- chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
558
+ txHash = yield this._sendSVMTxWithFunds({
559
+ execute,
560
+ mechanism,
561
+ universalPayload,
562
+ bridgeAmount,
563
+ nativeAmount,
510
564
  });
511
- const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
512
- const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
513
- const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
514
- // whitelistPda already computed above
515
- const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
516
- const priceUpdatePk = new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
517
- // pay-with-token gas abstraction is not supported on Solana
518
- if (execute.payGasWith !== undefined) {
519
- throw new Error('Pay-with token is not supported on Solana');
520
- }
521
- const isNative = mechanism === 'native' || execute.funds.token.symbol === 'SOL';
522
- const revertSvm2 = {
523
- fundRecipient: userPk,
524
- revertMsg: Buffer.from([]),
525
- };
526
- // Compute signature for universal payload on SVM
527
- const ueaAddressSvm = this.computeUEAOffchain();
528
- const ueaVersion = yield this.fetchUEAVersion();
529
- const svmSignature = yield this.signUniversalPayload(universalPayload, ueaAddressSvm, ueaVersion);
530
- if (isNative) {
531
- // Native SOL as bridge + gas
532
- const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
533
- txHash = yield svmClient.writeContract({
534
- abi: abi_1.SVM_GATEWAY_IDL,
535
- address: programId.toBase58(),
536
- functionName: 'sendTxWithFunds',
537
- args: [
538
- web3_js_1.PublicKey.default, // bridge_token = default for native SOL
539
- bridgeAmount,
540
- universalPayload,
541
- revertSvm2,
542
- nativeAmount,
543
- Buffer.from(svmSignature),
544
- ],
545
- signer: this.universalSigner,
546
- accounts: {
547
- config: configPda,
548
- vault: vaultPda,
549
- tokenWhitelist: whitelistPdaLocal,
550
- userTokenAccount: userPk, // for native SOL, can be any valid account
551
- gatewayTokenAccount: vaultPda, // for native SOL, can be any valid account
552
- user: userPk,
553
- priceUpdate: priceUpdatePk,
554
- bridgeToken: web3_js_1.PublicKey.default,
555
- tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
556
- systemProgram: web3_js_1.SystemProgram.programId,
557
- },
558
- });
559
- }
560
- else {
561
- // SPL token as bridge + native SOL lamports as gas_amount
562
- const mintPk = new web3_js_1.PublicKey(execute.funds.token.address);
563
- const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
564
- const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
565
- const userAta = web3_js_1.PublicKey.findProgramAddressSync([
566
- userPk.toBuffer(),
567
- TOKEN_PROGRAM_ID.toBuffer(),
568
- mintPk.toBuffer(),
569
- ], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
570
- const vaultAta = web3_js_1.PublicKey.findProgramAddressSync([
571
- vaultPda.toBuffer(),
572
- TOKEN_PROGRAM_ID.toBuffer(),
573
- mintPk.toBuffer(),
574
- ], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
575
- const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
576
- txHash = yield svmClient.writeContract({
577
- abi: abi_1.SVM_GATEWAY_IDL,
578
- address: programId.toBase58(),
579
- functionName: 'sendTxWithFunds',
580
- args: [
581
- mintPk,
582
- bridgeAmount,
583
- universalPayload,
584
- revertSvm2,
585
- nativeAmount,
586
- Buffer.from(svmSignature),
587
- ],
588
- signer: this.universalSigner,
589
- accounts: {
590
- config: configPda,
591
- vault: vaultPda,
592
- tokenWhitelist: whitelistPdaLocal,
593
- userTokenAccount: userAta,
594
- gatewayTokenAccount: vaultAta,
595
- user: userPk,
596
- priceUpdate: priceUpdatePk,
597
- bridgeToken: mintPk,
598
- tokenProgram: TOKEN_PROGRAM_ID,
599
- systemProgram: web3_js_1.SystemProgram.programId,
600
- },
601
- });
602
- }
603
565
  }
604
566
  }
605
567
  catch (err) {
@@ -638,23 +600,22 @@ class Orchestrator {
638
600
  const txs = yield this.sendUniversalTx(deployed, feeLockTxHash);
639
601
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
640
602
  // After sending Cosmos tx to Push Chain, query UniversalTx status
603
+ let pushChainUniversalTx;
641
604
  if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
642
605
  const evmClientEvm = evmClient;
643
606
  const gatewayAddressEvm = gatewayAddress;
644
- yield this.queryUniversalTxStatusFromGatewayTx(evmClientEvm, gatewayAddressEvm, txHash, 'sendTxWithFunds');
607
+ pushChainUniversalTx =
608
+ yield this.queryUniversalTxStatusFromGatewayTx(evmClientEvm, gatewayAddressEvm, txHash, 'sendTxWithFunds');
645
609
  }
646
610
  else {
647
- yield this.queryUniversalTxStatusFromGatewayTx(undefined, undefined, txHash, 'sendTxWithFunds');
648
- }
649
- if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
650
- const evmClientEvm = evmClient;
651
- const evmTx = yield evmClientEvm.getTransaction(txHash);
652
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_07, bridgeAmount, execute.funds.token.decimals, symbol);
653
- return yield this.transformToUniversalTxResponse(evmTx);
654
- }
655
- else {
656
- return txs[txs.length - 1];
611
+ pushChainUniversalTx =
612
+ yield this.queryUniversalTxStatusFromGatewayTx(undefined, undefined, txHash, 'sendTxWithFunds');
657
613
  }
614
+ const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
615
+ const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
616
+ const response = yield this.transformToUniversalTxResponse(tx);
617
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [response]);
618
+ return response;
658
619
  }
659
620
  }
660
621
  // Set default value for value if undefined
@@ -705,59 +666,39 @@ class Orchestrator {
705
666
  }
706
667
  // Fee locking is required if UEA is not deployed OR insufficient funds
707
668
  const feeLockingRequired = (!isUEADeployed || funds < requiredFunds) && !feeLockTxHash;
669
+ // const feeLockingRequired = true;
708
670
  // Support multicall payload encoding when execute.data is an array
709
671
  let payloadData;
672
+ let payloadTo;
710
673
  if (Array.isArray(execute.data)) {
711
- // Gate multicall to supported testnets
712
- const allowedChains = [
713
- enums_1.CHAIN.ETHEREUM_SEPOLIA,
714
- enums_1.CHAIN.ARBITRUM_SEPOLIA,
715
- enums_1.CHAIN.BASE_SEPOLIA,
716
- enums_1.CHAIN.SOLANA_DEVNET,
717
- enums_1.CHAIN.BNB_TESTNET,
718
- ];
719
- if (!allowedChains.includes(this.universalSigner.account.chain)) {
720
- throw new Error('Multicall is only enabled for Ethereum Sepolia, Arbitrum Sepolia, Base Sepolia, and Solana Devnet');
721
- }
722
- // For multicall, `to` must be the executor account (UEA) of the sender
723
- // i.e., PushChain.universal.account
724
- const expectedUea = this.computeUEAOffchain();
725
- const toAddr = (0, viem_1.getAddress)(execute.to);
726
- if (toAddr !== (0, viem_1.getAddress)(expectedUea)) {
727
- throw new Error('Multicall requires `to` to be the executor account (UEA) of the sender.');
728
- }
729
- // Normalize and validate calls
730
- const normalizedCalls = execute.data.map((c) => ({
731
- to: (0, viem_1.getAddress)(c.to),
732
- value: c.value,
733
- data: c.data,
734
- }));
735
- // bytes4(keccak256("UEA_MULTICALL")) selector, e.g., 0x4e2d2ff6-like prefix
736
- const selector = (0, viem_1.keccak256)((0, viem_1.toBytes)('UEA_MULTICALL')).slice(0, 10);
737
- // abi.encode(Call[]), where Call = { address to; uint256 value; bytes data; }
738
- const encodedCalls = (0, viem_1.encodeAbiParameters)([
739
- {
740
- type: 'tuple[]',
741
- components: [
742
- { name: 'to', type: 'address' },
743
- { name: 'value', type: 'uint256' },
744
- { name: 'data', type: 'bytes' },
745
- ],
746
- },
747
- ], [normalizedCalls]);
748
- // Concatenate prefix selector with encodedCalls without 0x
749
- payloadData = (selector + encodedCalls.slice(2));
674
+ // payloadData = this._buildMulticallPayloadData(execute.to, execute.data);
675
+ // Normal multicall. We replace the `to` to zeroAddress. Then console.warn to let user know that it should be
676
+ // passed as zeroAddress in the future.
677
+ // execute.to = zeroAddress;
678
+ payloadTo = viem_1.zeroAddress;
679
+ console.warn(`Multicalls should have execute.to as ${viem_1.zeroAddress}`);
680
+ payloadData = this._buildMulticallPayloadData(execute.to, (0, payload_builders_1.buildExecuteMulticall)({ execute, ueaAddress: UEA }));
750
681
  }
751
682
  else {
752
- payloadData = (execute.data || '0x');
683
+ // payloadData = (execute.data || '0x') as `0x${string}`;
684
+ if (execute.to.toLowerCase() !== UEA.toLowerCase()) {
685
+ payloadTo = viem_1.zeroAddress;
686
+ payloadData = this._buildMulticallPayloadData(execute.to, (0, payload_builders_1.buildExecuteMulticall)({ execute, ueaAddress: UEA }));
687
+ }
688
+ else {
689
+ // For value only we don't check below. Only if there is payload to be executed
690
+ if (execute.data && execute.to.toLowerCase() === UEA.toLowerCase()) {
691
+ throw new Error(`You can't execute data on the UEA address`);
692
+ }
693
+ payloadTo = execute.to;
694
+ payloadData = execute.data || '0x';
695
+ }
753
696
  }
754
- // Determine payload `to` value. For multicall, `to` must be UEA, pass-through as-is.
755
- const payloadTo = execute.to;
756
697
  const universalPayload = JSON.parse(JSON.stringify({
757
698
  to: payloadTo,
758
699
  value: execute.value,
759
700
  data: payloadData,
760
- gasLimit: execute.gasLimit || BigInt(1e7),
701
+ gasLimit: execute.gasLimit || BigInt(5e7),
761
702
  maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
762
703
  maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
763
704
  nonce,
@@ -793,30 +734,43 @@ class Orchestrator {
793
734
  }
794
735
  else {
795
736
  /**
796
- * Fee Locking
737
+ * Fee Locking - For all chains, EVM and Solana
797
738
  */
798
739
  const fundDifference = requiredFunds - funds;
799
740
  const fixedPushAmount = push_chain_1.PushChain.utils.helpers.parseUnits('0.001', 18); // Minimum lock 0.001 Push tokens
800
741
  const lockAmount = funds < requiredFunds ? fundDifference : fixedPushAmount;
801
742
  const lockAmountInUSD = this.pushClient.pushToUSDC(lockAmount);
802
743
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_01, lockAmount);
803
- const feeLockTxHashBytes = yield this.lockFee(lockAmountInUSD, executionHash);
744
+ const feeLockTxHashBytes = yield this.lockFee(lockAmountInUSD, universalPayload);
804
745
  feeLockTxHash = (0, viem_1.bytesToHex)(feeLockTxHashBytes);
805
746
  verificationData = (0, viem_1.bytesToHex)(feeLockTxHashBytes);
806
- /**
807
- * Waiting for Confirmations
808
- */
809
747
  const { vm } = chain_1.CHAIN_INFO[chain];
810
748
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_02, vm === enums_1.VM.SVM
811
749
  ? anchor_1.utils.bytes.bs58.encode(feeLockTxHashBytes)
812
750
  : feeLockTxHash, chain_1.CHAIN_INFO[chain].confirmations);
751
+ // Waiting for blocks confirmations
813
752
  yield this.waitForLockerFeeConfirmation(feeLockTxHashBytes);
814
753
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_03);
754
+ // Query nodes via gRPC for Push Chain transaction
755
+ const { defaultRPC, lockerContract } = chain_1.CHAIN_INFO[chain];
756
+ const pushChainUniversalTx = yield this.queryUniversalTxStatusFromGatewayTx(new evm_client_1.EvmClient({ rpcUrls: this.rpcUrls[chain] || defaultRPC }), lockerContract, feeLockTxHash, 'sendTxWithGas');
757
+ /**
758
+ * Return response directly (skip sendUniversalTx for sendTxWithGas flow)
759
+ * Note: queryTx may be undefined since validators don't recognize new UniversalTx event yet
760
+ */
761
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06);
762
+ // Transform to UniversalTxResponse (follow sendFunds pattern)
763
+ const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
764
+ const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
765
+ const response = yield this.transformToUniversalTxResponse(tx);
766
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [response]);
767
+ return response;
815
768
  }
816
769
  /**
817
- * Broadcasting Tx to PC
770
+ * Non-fee-locking path: Broadcasting Tx to PC via sendUniversalTx
818
771
  */
819
772
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06);
773
+ // We don't need to query via gRPC the PC transaction since it's getting returned it here already.
820
774
  const transactions = yield this.sendUniversalTx(isUEADeployed, feeLockTxHash, universalPayload, verificationData);
821
775
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, transactions);
822
776
  return transactions[transactions.length - 1];
@@ -844,11 +798,11 @@ class Orchestrator {
844
798
  *
845
799
  * @param amount - Fee amount in USDC (8 Decimals)
846
800
  * @param executionHash - Optional execution payload hash (default: zeroHash)
847
- * @returns Transaction hash of the locking transaction
801
+ * @returns Transaction hash bytes
848
802
  */
849
- lockFee(amount_1) {
850
- return tslib_1.__awaiter(this, arguments, void 0, function* (amount, // USD with 8 decimals
851
- executionHash = viem_1.zeroHash) {
803
+ lockFee(amount, // USD with 8 decimals
804
+ universalPayload) {
805
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
852
806
  const chain = this.universalSigner.account.chain;
853
807
  const { lockerContract, vm, defaultRPC } = chain_1.CHAIN_INFO[chain];
854
808
  if (!lockerContract) {
@@ -863,35 +817,88 @@ class Orchestrator {
863
817
  Promise.resolve(new evm_client_1.EvmClient({ rpcUrls })),
864
818
  ]);
865
819
  const nativeDecimals = 18; // ETH, MATIC, etc.
866
- const nativeAmount = (amount * BigInt(Math.pow(10, nativeDecimals))) / nativeTokenUsdPrice;
820
+ // Ensure deposit respects gateway USD caps (min $1, max $10) and avoid rounding below min
821
+ const oneUsd = push_chain_1.PushChain.utils.helpers.parseUnits('1', 8);
822
+ const tenUsd = push_chain_1.PushChain.utils.helpers.parseUnits('10', 8);
823
+ let depositUsd = amount < oneUsd ? oneUsd : amount;
824
+ if (depositUsd > tenUsd)
825
+ depositUsd = tenUsd;
826
+ // Ceil division to avoid falling below on-chain min due to rounding, then add 1 wei safety
827
+ let nativeAmount = (depositUsd * BigInt(Math.pow(10, nativeDecimals)) +
828
+ (nativeTokenUsdPrice - BigInt(1))) /
829
+ nativeTokenUsdPrice;
830
+ nativeAmount = nativeAmount + BigInt(1);
831
+ // Deposit-only funding via UniversalGatewayV0 (no payload execution)
832
+ const revertCFG = {
833
+ fundRecipient: this.universalSigner.account.address,
834
+ revertMsg: '0x',
835
+ };
836
+ // Sign the universal payload
837
+ const ueaAddress = this.computeUEAOffchain();
838
+ const ueaVersion = yield this.fetchUEAVersion();
839
+ const eip712Signature = yield this.signUniversalPayload(universalPayload, ueaAddress, ueaVersion);
840
+ const eip712SignatureHex = typeof eip712Signature === 'string'
841
+ ? eip712Signature
842
+ : (0, viem_1.bytesToHex)(eip712Signature);
867
843
  const txHash = yield evmClient.writeContract({
868
- abi: abi_1.FEE_LOCKER_EVM,
844
+ abi: abi_1.UNIVERSAL_GATEWAY_V0,
869
845
  address: lockerContract,
870
- functionName: 'addFunds',
871
- args: [executionHash],
846
+ functionName: 'sendTxWithGas',
847
+ args: [universalPayload, revertCFG, '0x'],
872
848
  signer: this.universalSigner,
873
849
  value: nativeAmount,
874
850
  });
875
851
  return (0, viem_1.hexToBytes)(txHash);
876
852
  }
877
853
  case enums_1.VM.SVM: {
878
- // Run price fetching, client creation, and PDA computation in parallel
879
- const [nativeTokenUsdPrice, svmClient, [lockerPda]] = yield Promise.all([
854
+ // Run price fetching and client creation in parallel
855
+ const [nativeTokenUsdPrice, svmClient] = yield Promise.all([
880
856
  new price_fetch_1.PriceFetch(this.rpcUrls).getPrice(chain), // 8 decimals
881
857
  Promise.resolve(new svm_client_1.SvmClient({ rpcUrls })),
882
- Promise.resolve(anchor.web3.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('locker')], new web3_js_1.PublicKey(lockerContract))),
883
858
  ]);
859
+ // Ensure deposit respects gateway USD caps (min $1, max $10) and avoid rounding below min
884
860
  const nativeDecimals = 9; // SOL lamports
885
- const nativeAmount = (amount * BigInt(Math.pow(10, nativeDecimals))) / nativeTokenUsdPrice;
861
+ const oneUsd = push_chain_1.PushChain.utils.helpers.parseUnits('1', 8);
862
+ const tenUsd = push_chain_1.PushChain.utils.helpers.parseUnits('10', 8);
863
+ let depositUsd = amount < oneUsd ? oneUsd : amount;
864
+ if (depositUsd > tenUsd)
865
+ depositUsd = tenUsd;
866
+ // Ceil division to avoid falling below on-chain min due to rounding, then add 1 lamport safety
867
+ let nativeAmount = (depositUsd * BigInt(Math.pow(10, nativeDecimals)) +
868
+ (nativeTokenUsdPrice - BigInt(1))) /
869
+ nativeTokenUsdPrice;
870
+ nativeAmount = nativeAmount + BigInt(1);
871
+ // Program & PDAs
872
+ const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
873
+ const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
874
+ const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
875
+ const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
876
+ const revertSvm = {
877
+ fundRecipient: userPk,
878
+ revertMsg: Buffer.from([]),
879
+ };
880
+ // const ueaAddressSvm = this.computeUEAOffchain();
881
+ // const ueaVersion = await this.fetchUEAVersion();
882
+ // const svmSignature = await this.signUniversalPayload(
883
+ // universalPayload,
884
+ // ueaAddressSvm,
885
+ // ueaVersion
886
+ // );
886
887
  const txHash = yield svmClient.writeContract({
887
- abi: abi_1.FEE_LOCKER_SVM,
888
- address: lockerContract,
889
- functionName: 'addFunds',
890
- args: [nativeAmount, (0, viem_1.toBytes)(executionHash)],
888
+ abi: abi_1.SVM_GATEWAY_IDL,
889
+ address: programId.toBase58(),
890
+ functionName: 'sendTxWithGas',
891
+ args: [
892
+ universalPayload,
893
+ revertSvm,
894
+ new anchor.BN(nativeAmount.toString()),
895
+ '0x',
896
+ ],
891
897
  signer: this.universalSigner,
892
898
  accounts: {
893
- locker: lockerPda,
894
- user: new web3_js_1.PublicKey(this.universalSigner.account.address),
899
+ config: configPda,
900
+ vault: vaultPda,
901
+ user: userPk,
895
902
  priceUpdate: new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE'),
896
903
  systemProgram: web3_js_1.SystemProgram.programId,
897
904
  },
@@ -1140,6 +1147,148 @@ class Orchestrator {
1140
1147
  return { address: computedAddress, deployed: byteCode !== undefined };
1141
1148
  });
1142
1149
  }
1150
+ _buildMulticallPayloadData(to, data) {
1151
+ const allowedChains = [
1152
+ enums_1.CHAIN.ETHEREUM_SEPOLIA,
1153
+ enums_1.CHAIN.ARBITRUM_SEPOLIA,
1154
+ enums_1.CHAIN.BASE_SEPOLIA,
1155
+ enums_1.CHAIN.SOLANA_DEVNET,
1156
+ enums_1.CHAIN.BNB_TESTNET,
1157
+ ];
1158
+ if (!allowedChains.includes(this.universalSigner.account.chain)) {
1159
+ throw new Error('Multicall is only enabled for Ethereum Sepolia, Arbitrum Sepolia, Base Sepolia, Binance Smart Chain and Solana Devnet');
1160
+ }
1161
+ // For multicall, `to` must be the executor account (UEA) of the sender
1162
+ // i.e., PushChain.universal.account
1163
+ const expectedUea = this.computeUEAOffchain();
1164
+ const toAddr = (0, viem_1.getAddress)(to);
1165
+ // if (toAddr !== getAddress(expectedUea)) {
1166
+ // throw new Error(
1167
+ // 'Multicall requires `to` to be the executor account (UEA) of the sender.'
1168
+ // );
1169
+ // }
1170
+ // Normalize and validate calls
1171
+ const normalizedCalls = data.map((c) => ({
1172
+ to: (0, viem_1.getAddress)(c.to),
1173
+ value: c.value,
1174
+ data: c.data,
1175
+ }));
1176
+ // bytes4(keccak256("UEA_MULTICALL")) selector, e.g., 0x4e2d2ff6-like prefix
1177
+ const selector = (0, viem_1.keccak256)((0, viem_1.toBytes)('UEA_MULTICALL')).slice(0, 10);
1178
+ // abi.encode(Call[]), where Call = { address to; uint256 value; bytes data; }
1179
+ const encodedCalls = (0, viem_1.encodeAbiParameters)([
1180
+ {
1181
+ type: 'tuple[]',
1182
+ components: [
1183
+ { name: 'to', type: 'address' },
1184
+ { name: 'value', type: 'uint256' },
1185
+ { name: 'data', type: 'bytes' },
1186
+ ],
1187
+ },
1188
+ ], [normalizedCalls]);
1189
+ // Concatenate prefix selector with encodedCalls without 0x
1190
+ return (selector + encodedCalls.slice(2));
1191
+ }
1192
+ _sendSVMTxWithFunds(_a) {
1193
+ return tslib_1.__awaiter(this, arguments, void 0, function* ({ execute, mechanism, universalPayload, bridgeAmount, nativeAmount, }) {
1194
+ var _b, _c, _d, _e;
1195
+ // SVM funds+payload path
1196
+ const svmClient = new svm_client_1.SvmClient({
1197
+ rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
1198
+ chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
1199
+ });
1200
+ const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
1201
+ const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
1202
+ const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
1203
+ // whitelistPda already computed above
1204
+ const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
1205
+ const priceUpdatePk = new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
1206
+ // pay-with-token gas abstraction is not supported on Solana
1207
+ if (execute.payGasWith !== undefined) {
1208
+ throw new Error('Pay-with token is not supported on Solana');
1209
+ }
1210
+ if (!((_c = (_b = execute.funds) === null || _b === void 0 ? void 0 : _b.token) === null || _c === void 0 ? void 0 : _c.address)) {
1211
+ throw new Error('Token address is required for bridge path');
1212
+ }
1213
+ const isNative = mechanism === 'native' || execute.funds.token.symbol === 'SOL';
1214
+ const revertSvm2 = {
1215
+ fundRecipient: userPk,
1216
+ revertMsg: Buffer.from([]),
1217
+ };
1218
+ // Compute signature for universal payload on SVM
1219
+ const ueaAddressSvm = this.computeUEAOffchain();
1220
+ const ueaVersion = yield this.fetchUEAVersion();
1221
+ const svmSignature = yield this.signUniversalPayload(universalPayload, ueaAddressSvm, ueaVersion);
1222
+ if (isNative) {
1223
+ // Native SOL as bridge + gas
1224
+ const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
1225
+ return yield svmClient.writeContract({
1226
+ abi: abi_1.SVM_GATEWAY_IDL,
1227
+ address: programId.toBase58(),
1228
+ functionName: 'sendTxWithFunds',
1229
+ args: [
1230
+ web3_js_1.PublicKey.default, // bridge_token = default for native SOL
1231
+ bridgeAmount,
1232
+ universalPayload,
1233
+ revertSvm2,
1234
+ nativeAmount,
1235
+ Buffer.from(svmSignature),
1236
+ ],
1237
+ signer: this.universalSigner,
1238
+ accounts: {
1239
+ config: configPda,
1240
+ vault: vaultPda,
1241
+ tokenWhitelist: whitelistPdaLocal,
1242
+ userTokenAccount: userPk, // for native SOL, can be any valid account
1243
+ gatewayTokenAccount: vaultPda, // for native SOL, can be any valid account
1244
+ user: userPk,
1245
+ priceUpdate: priceUpdatePk,
1246
+ bridgeToken: web3_js_1.PublicKey.default,
1247
+ tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
1248
+ systemProgram: web3_js_1.SystemProgram.programId,
1249
+ },
1250
+ });
1251
+ }
1252
+ else {
1253
+ // SPL token as bridge + native SOL lamports as gas_amount
1254
+ if (!((_e = (_d = execute.funds) === null || _d === void 0 ? void 0 : _d.token) === null || _e === void 0 ? void 0 : _e.address)) {
1255
+ throw new Error('Token address is required for SPL bridge path');
1256
+ }
1257
+ const mintPk = new web3_js_1.PublicKey(execute.funds.token.address);
1258
+ const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
1259
+ const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
1260
+ const userAta = web3_js_1.PublicKey.findProgramAddressSync([userPk.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintPk.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
1261
+ const vaultAta = web3_js_1.PublicKey.findProgramAddressSync([vaultPda.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintPk.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
1262
+ const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
1263
+ return yield svmClient.writeContract({
1264
+ abi: abi_1.SVM_GATEWAY_IDL,
1265
+ address: programId.toBase58(),
1266
+ functionName: 'sendTxWithFunds',
1267
+ args: [
1268
+ mintPk,
1269
+ bridgeAmount,
1270
+ universalPayload,
1271
+ revertSvm2,
1272
+ nativeAmount,
1273
+ Buffer.from(svmSignature),
1274
+ ],
1275
+ signer: this.universalSigner,
1276
+ accounts: {
1277
+ config: configPda,
1278
+ vault: vaultPda,
1279
+ tokenWhitelist: whitelistPdaLocal,
1280
+ userTokenAccount: userAta,
1281
+ gatewayTokenAccount: vaultAta,
1282
+ user: userPk,
1283
+ priceUpdate: priceUpdatePk,
1284
+ bridgeToken: mintPk,
1285
+ tokenProgram: TOKEN_PROGRAM_ID,
1286
+ systemProgram: web3_js_1.SystemProgram.programId,
1287
+ },
1288
+ });
1289
+ }
1290
+ });
1291
+ }
1143
1292
  computeUEAOffchain() {
1144
1293
  const { chain, address } = this.universalSigner.account;
1145
1294
  const { vm, chainId } = chain_1.CHAIN_INFO[chain];
@@ -1230,20 +1379,12 @@ class Orchestrator {
1230
1379
  switch (vm) {
1231
1380
  case enums_1.VM.EVM: {
1232
1381
  const evmClient = new evm_client_1.EvmClient({ rpcUrls });
1233
- yield evmClient.waitForConfirmations({
1234
- txHash: (0, viem_1.bytesToHex)(txHashBytes),
1235
- confirmations,
1236
- timeoutMs: timeout,
1237
- });
1382
+ yield this.waitForEvmConfirmationsWithCountdown(evmClient, (0, viem_1.bytesToHex)(txHashBytes), confirmations, timeout);
1238
1383
  return;
1239
1384
  }
1240
1385
  case enums_1.VM.SVM: {
1241
1386
  const svmClient = new svm_client_1.SvmClient({ rpcUrls });
1242
- yield svmClient.waitForConfirmations({
1243
- txSignature: anchor_1.utils.bytes.bs58.encode(txHashBytes),
1244
- confirmations,
1245
- timeoutMs: timeout,
1246
- });
1387
+ yield this.waitForSvmConfirmationsWithCountdown(svmClient, anchor_1.utils.bytes.bs58.encode(txHashBytes), confirmations, timeout);
1247
1388
  return;
1248
1389
  }
1249
1390
  default:
@@ -1473,26 +1614,68 @@ class Orchestrator {
1473
1614
  });
1474
1615
  }
1475
1616
  /**
1476
- * Builds UniversalPayload for the gateway and computes the native gas deposit.
1617
+ * For sendFunds, we will call internally the sendTxWithFunds.
1477
1618
  */
1478
- buildGatewayPayloadAndGas(execute, nonce) {
1619
+ buildGatewayPayloadAndGas(execute, nonce, type, fundsValue) {
1479
1620
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
1480
- var _a, _b;
1621
+ var _a, _b, _c, _d, _e;
1481
1622
  const gasEstimate = execute.gasLimit || BigInt(1e7);
1482
- const payloadValue = (_a = execute.value) !== null && _a !== void 0 ? _a : BigInt(0);
1483
- const gasAmount = (_b = execute.value) !== null && _b !== void 0 ? _b : BigInt(0);
1484
- const universalPayload = {
1485
- to: execute.to,
1486
- value: payloadValue,
1487
- data: execute.data || '0x',
1488
- gasLimit: gasEstimate,
1489
- maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
1490
- maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
1491
- nonce,
1492
- deadline: execute.deadline || BigInt(9999999999),
1493
- vType: tx_1.VerificationType.signedVerification,
1494
- };
1495
- return { payload: universalPayload, gasAmount };
1623
+ const gasAmount = (_a = execute.value) !== null && _a !== void 0 ? _a : BigInt(0);
1624
+ if (type === 'sendTxWithFunds') {
1625
+ if (!((_b = execute.funds) === null || _b === void 0 ? void 0 : _b.token))
1626
+ throw new Error(`Invalid ${(_c = execute.funds) === null || _c === void 0 ? void 0 : _c.token}`);
1627
+ const multicallData = (0, payload_builders_1.buildExecuteMulticall)({
1628
+ execute,
1629
+ ueaAddress: this.computeUEAOffchain(),
1630
+ });
1631
+ // THIS ABOVE WILL CHANGE WHEN FUNDS ARE PASSED
1632
+ const universalPayload = {
1633
+ to: viem_1.zeroAddress,
1634
+ value: (_d = execute.value) !== null && _d !== void 0 ? _d : BigInt(0),
1635
+ // data: execute.data || '0x',
1636
+ data: this._buildMulticallPayloadData(execute.to, multicallData),
1637
+ gasLimit: gasEstimate,
1638
+ maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
1639
+ maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
1640
+ nonce,
1641
+ deadline: execute.deadline || BigInt(9999999999),
1642
+ vType: tx_1.VerificationType.universalTxVerification,
1643
+ };
1644
+ return { payload: universalPayload, gasAmount };
1645
+ }
1646
+ else {
1647
+ if (!fundsValue)
1648
+ throw new Error('fundsValue property must not be empty');
1649
+ const multicallData = (0, payload_builders_1.buildExecuteMulticall)({
1650
+ execute,
1651
+ ueaAddress: this.computeUEAOffchain(),
1652
+ });
1653
+ // // The data will be the abi-encoded transfer function from erc-20 function. The recipient will be `execute.to`, the value
1654
+ // // will be the fundsValue property.
1655
+ // const data = encodeFunctionData({
1656
+ // abi: ERC20_EVM,
1657
+ // functionName: 'transfer',
1658
+ // args: [execute.to, fundsValue],
1659
+ // });
1660
+ // const pushChainTo = PushChain.utils.tokens.toSyntheticAddress(
1661
+ // execute.funds!.token as MoveableToken
1662
+ // );
1663
+ const universalPayload = {
1664
+ to: viem_1.zeroAddress, // We can't simply do `0x` because we will get an error when eip712 signing the transaction.
1665
+ value: (_e = execute.value) !== null && _e !== void 0 ? _e : BigInt(0),
1666
+ data: this._buildMulticallPayloadData(execute.to, multicallData),
1667
+ // data: this._buildMulticallPayloadData(execute.to, [
1668
+ // { to: pushChainTo, value: execute.value ?? BigInt(0), data },
1669
+ // ]),
1670
+ gasLimit: gasEstimate,
1671
+ maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
1672
+ maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
1673
+ nonce,
1674
+ deadline: execute.deadline || BigInt(9999999999),
1675
+ vType: tx_1.VerificationType.universalTxVerification,
1676
+ };
1677
+ return { payload: universalPayload, gasAmount };
1678
+ }
1496
1679
  });
1497
1680
  }
1498
1681
  /********************************** HELPER FUNCTIONS **************************************************/
@@ -1738,15 +1921,16 @@ class Orchestrator {
1738
1921
  continue;
1739
1922
  const discriminatorHex = (0, viem_1.bytesToHex)(decoded.slice(0, 8)).slice(2);
1740
1923
  // Skip add_funds discriminator; return the first other Program data event
1741
- if (discriminatorHex === '7f1f6cffbb134644')
1742
- continue;
1743
- return i;
1924
+ // if (discriminatorHex === '7f1f6cffbb134644') continue;
1925
+ if (discriminatorHex === '6c9ad829b5ea1d7c')
1926
+ return i;
1927
+ // return i;
1744
1928
  }
1745
1929
  // Fallback to first log
1746
1930
  return 0;
1747
1931
  }
1748
1932
  // Query Push Chain for UniversalTx status given an origin gateway tx (EVM or SVM)
1749
- queryUniversalTxStatusFromGatewayTx(evmClient, gatewayAddress, txHash, fromBranch) {
1933
+ queryUniversalTxStatusFromGatewayTx(evmClient, gatewayAddress, txHash, evmGatewayMethod) {
1750
1934
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
1751
1935
  var _a, _b;
1752
1936
  try {
@@ -1757,11 +1941,22 @@ class Orchestrator {
1757
1941
  if (vm === enums_1.VM.EVM) {
1758
1942
  if (!evmClient || !gatewayAddress)
1759
1943
  throw new Error('Missing EVM context');
1760
- const receipt = yield evmClient.publicClient.getTransactionReceipt({
1761
- hash: txHash,
1762
- });
1944
+ let receipt;
1945
+ try {
1946
+ receipt = yield evmClient.publicClient.getTransactionReceipt({
1947
+ hash: txHash,
1948
+ });
1949
+ }
1950
+ catch (_c) {
1951
+ // Receipt might not be indexed yet on this RPC; wait briefly for it
1952
+ receipt = yield evmClient.publicClient.waitForTransactionReceipt({
1953
+ hash: txHash,
1954
+ confirmations: 0,
1955
+ timeout: chain_1.CHAIN_INFO[chain].timeout,
1956
+ });
1957
+ }
1763
1958
  const gatewayLogs = (receipt.logs || []).filter((l) => (l.address || '').toLowerCase() === gatewayAddress.toLowerCase());
1764
- const logIndexToUse = fromBranch === 'sendTxWithFunds' ? 1 : 0;
1959
+ const logIndexToUse = evmGatewayMethod === 'sendTxWithFunds' ? 1 : 0;
1765
1960
  const firstLog = (gatewayLogs[logIndexToUse] ||
1766
1961
  ((_a = receipt.logs) === null || _a === void 0 ? void 0 : _a[logIndexToUse]));
1767
1962
  const logIndexVal = (_b = firstLog === null || firstLog === void 0 ? void 0 : firstLog.logIndex) !== null && _b !== void 0 ? _b : 0;
@@ -1800,10 +1995,13 @@ class Orchestrator {
1800
1995
  const idHex = (0, viem_1.sha256)((0, viem_1.stringToBytes)(idInput)).slice(2);
1801
1996
  // Fetch UniversalTx via gRPC with a brief retry window
1802
1997
  let universalTxObj;
1803
- for (let attempt = 0; attempt < 10; attempt++) {
1998
+ for (let attempt = 0; attempt < 15; attempt++) {
1804
1999
  try {
1805
2000
  const universalTxResp = yield this.pushClient.getUniversalTxById(idHex);
1806
2001
  universalTxObj = universalTxResp === null || universalTxResp === void 0 ? void 0 : universalTxResp.universalTx;
2002
+ console.log('@@@@@');
2003
+ console.log(universalTxObj);
2004
+ console.log('@@@@@');
1807
2005
  if (universalTxObj)
1808
2006
  break;
1809
2007
  }
@@ -1829,7 +2027,7 @@ class Orchestrator {
1829
2027
  // );
1830
2028
  return universalTxObj;
1831
2029
  }
1832
- catch (_c) {
2030
+ catch (_d) {
1833
2031
  // Best-effort; do not fail flow if PC query is unavailable
1834
2032
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
1835
2033
  return undefined;
@@ -1847,15 +2045,31 @@ class Orchestrator {
1847
2045
  hash: txHash,
1848
2046
  });
1849
2047
  const targetBlock = receipt.blockNumber + BigInt(confirmations);
2048
+ // Track last emitted confirmation to avoid duplicates
2049
+ let lastEmitted = 0;
1850
2050
  // Poll blocks and emit remaining confirmations
1851
2051
  // eslint-disable-next-line no-constant-condition
1852
2052
  while (true) {
1853
2053
  const currentBlock = yield evmClient.publicClient.getBlockNumber();
1854
- if (currentBlock >= targetBlock)
2054
+ // If already confirmed, emit progress for final confirmation
2055
+ if (currentBlock >= targetBlock) {
2056
+ // Only emit if we haven't already shown this confirmation
2057
+ if (lastEmitted < confirmations) {
2058
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, confirmations, confirmations);
2059
+ }
1855
2060
  return;
2061
+ }
1856
2062
  const remaining = Number(targetBlock - currentBlock);
1857
2063
  const completed = Math.max(1, confirmations - remaining + 1);
1858
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, completed, confirmations);
2064
+ // Only emit if this is a new confirmation count
2065
+ if (completed > lastEmitted) {
2066
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, completed, confirmations);
2067
+ lastEmitted = completed;
2068
+ // If we've reached required confirmations, we're done
2069
+ if (completed >= confirmations) {
2070
+ return;
2071
+ }
2072
+ }
1859
2073
  if (Date.now() - start > timeoutMs) {
1860
2074
  throw new Error(`Timeout: transaction ${txHash} not confirmed with ${confirmations} confirmations within ${timeoutMs} ms`);
1861
2075
  }
@@ -1863,6 +2077,44 @@ class Orchestrator {
1863
2077
  }
1864
2078
  });
1865
2079
  }
2080
+ // Emit countdown updates while waiting for SVM confirmations
2081
+ waitForSvmConfirmationsWithCountdown(svmClient, txSignature, confirmations, timeoutMs) {
2082
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
2083
+ var _a;
2084
+ // initial emit
2085
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03, confirmations);
2086
+ const start = Date.now();
2087
+ // Poll for confirmations and emit progress
2088
+ let lastConfirmed = 0;
2089
+ // eslint-disable-next-line no-constant-condition
2090
+ while (true) {
2091
+ const connection = svmClient.connections[svmClient.currentConnectionIndex];
2092
+ const { value } = yield connection.getSignatureStatuses([txSignature]);
2093
+ const status = value[0];
2094
+ if (status) {
2095
+ const currentConfirms = (_a = status.confirmations) !== null && _a !== void 0 ? _a : 0;
2096
+ const hasEnoughConfirmations = currentConfirms >= confirmations;
2097
+ const isSuccessfullyFinalized = status.err === null && status.confirmationStatus !== null;
2098
+ // Emit progress if we have more confirmations than before OR if finalized
2099
+ if (currentConfirms > lastConfirmed ||
2100
+ (isSuccessfullyFinalized && lastConfirmed === 0)) {
2101
+ const confirmCount = isSuccessfullyFinalized && currentConfirms === 0
2102
+ ? confirmations
2103
+ : currentConfirms;
2104
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, Math.max(1, confirmCount), confirmations);
2105
+ lastConfirmed = currentConfirms;
2106
+ }
2107
+ if (hasEnoughConfirmations || isSuccessfullyFinalized) {
2108
+ return;
2109
+ }
2110
+ }
2111
+ if (Date.now() - start > timeoutMs) {
2112
+ throw new Error(`Timeout: transaction ${txSignature} not confirmed with ${confirmations} confirmations within ${timeoutMs} ms`);
2113
+ }
2114
+ yield new Promise((r) => setTimeout(r, 500));
2115
+ }
2116
+ });
2117
+ }
1866
2118
  // Fetch and cache UEA version from the contract on Push Chain
1867
2119
  fetchUEAVersion() {
1868
2120
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
@@ -1928,6 +2180,63 @@ class Orchestrator {
1928
2180
  return { gasAmount };
1929
2181
  });
1930
2182
  }
2183
+ calculateNativeAmountForDeposit(chain, requiredFunds, ueaBalance) {
2184
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
2185
+ var _a, _b;
2186
+ // Determine USD to deposit via gateway (8 decimals) with caps: min=$1, max=$10
2187
+ const oneUsd = push_chain_1.PushChain.utils.helpers.parseUnits('1', 8);
2188
+ const tenUsd = push_chain_1.PushChain.utils.helpers.parseUnits('10', 8);
2189
+ const deficit = requiredFunds > ueaBalance ? requiredFunds - ueaBalance : BigInt(0);
2190
+ let depositUsd = deficit > BigInt(0) ? this.pushClient.pushToUSDC(deficit) : oneUsd;
2191
+ if (depositUsd < oneUsd)
2192
+ depositUsd = oneUsd;
2193
+ if (depositUsd > tenUsd)
2194
+ throw new Error('Deposit value exceeds max $10 worth of native token');
2195
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_02, depositUsd);
2196
+ // If SVM, clamp depositUsd to on-chain Config caps
2197
+ if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM) {
2198
+ const svmClient = new svm_client_1.SvmClient({
2199
+ rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
2200
+ chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
2201
+ });
2202
+ const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
2203
+ const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
2204
+ try {
2205
+ const cfg = yield svmClient.readContract({
2206
+ abi: abi_1.SVM_GATEWAY_IDL,
2207
+ address: abi_1.SVM_GATEWAY_IDL.address,
2208
+ functionName: 'config',
2209
+ args: [configPda.toBase58()],
2210
+ });
2211
+ const minField = (_a = cfg.minCapUniversalTxUsd) !== null && _a !== void 0 ? _a : cfg.min_cap_universal_tx_usd;
2212
+ const maxField = (_b = cfg.maxCapUniversalTxUsd) !== null && _b !== void 0 ? _b : cfg.max_cap_universal_tx_usd;
2213
+ const minCapUsd = BigInt(minField.toString());
2214
+ const maxCapUsd = BigInt(maxField.toString());
2215
+ if (depositUsd < minCapUsd)
2216
+ depositUsd = minCapUsd;
2217
+ // Add 20% safety margin to avoid BelowMinCap due to price drift
2218
+ const withMargin = (minCapUsd * BigInt(12)) / BigInt(10);
2219
+ if (depositUsd < withMargin)
2220
+ depositUsd = withMargin;
2221
+ if (depositUsd > maxCapUsd)
2222
+ depositUsd = maxCapUsd;
2223
+ }
2224
+ catch (_c) {
2225
+ // best-effort; fallback to previous bounds if read fails
2226
+ }
2227
+ }
2228
+ // Convert USD(8) -> native units using pricing path
2229
+ const nativeTokenUsdPrice = yield new price_fetch_1.PriceFetch(this.rpcUrls).getPrice(chain); // 8 decimals
2230
+ const nativeDecimals = chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM ? 9 : 18;
2231
+ const oneNativeUnit = push_chain_1.PushChain.utils.helpers.parseUnits('1', nativeDecimals);
2232
+ // Ceil division to avoid rounding below min USD on-chain
2233
+ let nativeAmount = (depositUsd * oneNativeUnit + (nativeTokenUsdPrice - BigInt(1))) /
2234
+ nativeTokenUsdPrice;
2235
+ // Add 1 unit safety to avoid BelowMinCap from rounding differences
2236
+ nativeAmount = nativeAmount + BigInt(1);
2237
+ return nativeAmount;
2238
+ });
2239
+ }
1931
2240
  }
1932
2241
  exports.Orchestrator = Orchestrator;
1933
2242
  //# sourceMappingURL=orchestrator.js.map