@pushchain/core 3.0.8 → 4.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.
@@ -2,24 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Orchestrator = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const anchor_1 = require("@coral-xyz/anchor");
6
+ const web3_js_1 = require("@solana/web3.js");
5
7
  const viem_1 = require("viem");
6
- const push_chain_1 = require("../push-chain/push-chain");
7
- const enums_1 = require("../constants/enums");
8
- const payload_builders_1 = require("./payload-builders");
9
- const evm_client_1 = require("../vm-client/evm-client");
10
- const chain_1 = require("../constants/chain");
11
8
  const abi_1 = require("../constants/abi");
12
- const push_client_1 = require("../push-client/push-client");
13
- const svm_client_1 = require("../vm-client/svm-client");
14
- const web3_js_1 = require("@solana/web3.js");
15
- const anchor = tslib_1.__importStar(require("@coral-xyz/anchor"));
9
+ const uea_evm_1 = require("../constants/abi/uea.evm");
10
+ const chain_1 = require("../constants/chain");
11
+ const enums_1 = require("../constants/enums");
12
+ const tokens_1 = require("../constants/tokens");
16
13
  const tx_1 = require("../generated/v1/tx");
17
14
  const price_fetch_1 = require("../price-fetch/price-fetch");
18
- const anchor_1 = require("@coral-xyz/anchor");
19
- const progress_hook_types_1 = require("../progress-hook/progress-hook.types");
20
15
  const progress_hook_1 = tslib_1.__importDefault(require("../progress-hook/progress-hook"));
21
- const uea_evm_1 = require("../constants/abi/uea.evm");
22
- const tokens_1 = require("../constants/tokens");
16
+ const progress_hook_types_1 = require("../progress-hook/progress-hook.types");
17
+ const push_chain_1 = require("../push-chain/push-chain");
18
+ const push_client_1 = require("../push-client/push-client");
19
+ const evm_client_1 = require("../vm-client/evm-client");
20
+ const svm_client_1 = require("../vm-client/svm-client");
21
+ const payload_builders_1 = require("./payload-builders");
23
22
  class Orchestrator {
24
23
  constructor(universalSigner, pushNetwork, rpcUrls = {}, printTraces = false, progressHook) {
25
24
  this.universalSigner = universalSigner;
@@ -66,26 +65,8 @@ class Orchestrator {
66
65
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
67
66
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
68
67
  try {
69
- // FUNDS_TX short-circuit: Bridge tokens from origin chain to Push Chain
70
- // - EVM (Sepolia): UniversalGatewayV0
71
- // - SVM (Solana Devnet): pushsolanagateway
72
68
  if (execute.funds) {
73
69
  if (!execute.data || execute.data === '0x') {
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
- // }
89
70
  const chain = this.universalSigner.account.chain;
90
71
  const { vm } = chain_1.CHAIN_INFO[chain];
91
72
  if (!(chain === enums_1.CHAIN.ETHEREUM_SEPOLIA ||
@@ -96,7 +77,7 @@ class Orchestrator {
96
77
  throw new Error('Funds bridging is only supported on Ethereum Sepolia, Arbitrum Sepolia, Base Sepolia, BNB Testnet, and Solana Devnet for now');
97
78
  }
98
79
  // Progress: Origin chain detected
99
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain);
80
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain, this.universalSigner.account.address);
100
81
  const { defaultRPC, lockerContract } = chain_1.CHAIN_INFO[chain];
101
82
  const rpcUrls = this.rpcUrls[chain] || defaultRPC;
102
83
  // Resolve token: default to native token based on VM (ETH for EVM, SOL for SVM)
@@ -114,23 +95,6 @@ class Orchestrator {
114
95
  }
115
96
  const amount = execute.funds.amount;
116
97
  const symbol = execute.funds.token.symbol;
117
- // Funds Flow: Preparing funds transfer
118
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_01, amount, execute.funds.token.decimals, symbol);
119
- if (vm === enums_1.VM.EVM) {
120
- const evmClient = new evm_client_1.EvmClient({ rpcUrls });
121
- const gatewayAddress = lockerContract;
122
- const tokenAddr = execute.funds.token.address;
123
- // Approve gateway to pull tokens if ERC-20 (not native sentinel)
124
- if (execute.funds.token.mechanism === 'approve') {
125
- yield this.ensureErc20Allowance(evmClient, tokenAddr, gatewayAddress, amount);
126
- }
127
- else if (execute.funds.token.mechanism === 'permit2') {
128
- throw new Error('Permit2 is not supported yet');
129
- }
130
- else if (execute.funds.token.mechanism === 'native') {
131
- // Native flow uses msg.value == bridgeAmount and bridgeToken = address(0)
132
- }
133
- }
134
98
  const bridgeAmount = amount;
135
99
  const revertCFG = {
136
100
  fundRecipient: this.universalSigner.account
@@ -141,48 +105,85 @@ class Orchestrator {
141
105
  const evmClient = new evm_client_1.EvmClient({ rpcUrls });
142
106
  const gatewayAddress = lockerContract;
143
107
  const tokenAddr = execute.funds.token.address;
144
- // Call UniversalGatewayV0.sendFunds(recipient, bridgeToken, bridgeAmount, revertCFG)
145
108
  const recipient = execute.to; // funds to recipient on Push Chain
146
109
  const isNative = execute.funds.token.mechanism === 'native';
147
110
  const bridgeToken = execute.funds.token.mechanism === 'approve'
148
111
  ? tokenAddr
149
112
  : '0x0000000000000000000000000000000000000000';
150
- const { nonce } = yield this.getUeaStatusAndNonce();
151
- const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', bridgeAmount);
152
- // Get UEA info
113
+ const { nonce, deployed } = yield this.getUeaStatusAndNonce();
114
+ const { payload: universalPayload, req } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', bridgeAmount);
153
115
  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);
116
+ // Compute minimal native amount to deposit for gas on Push Chain
117
+ const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddress);
118
+ const nativeAmount = yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas);
119
+ // We log the SEND_TX_03_01 here because the progress hook for gas estimation should arrive before the resolving of UEA.
120
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_01);
121
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_02, ueaAddress, deployed);
122
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_01, amount, execute.funds.token.decimals, symbol);
123
+ if (vm === enums_1.VM.EVM) {
124
+ const evmClient = new evm_client_1.EvmClient({ rpcUrls });
125
+ const gatewayAddress = lockerContract;
126
+ const tokenAddr = execute.funds.token.address;
127
+ // Approve gateway to pull tokens if ERC-20 (not native sentinel)
128
+ if (execute.funds.token.mechanism === 'approve') {
129
+ yield this.ensureErc20Allowance(evmClient, tokenAddr, gatewayAddress, amount);
130
+ }
131
+ else if (execute.funds.token.mechanism === 'permit2') {
132
+ throw new Error('Permit2 is not supported yet');
133
+ }
134
+ else if (execute.funds.token.mechanism === 'native') {
135
+ // Native flow uses msg.value == bridgeAmount and bridgeToken = address(0)
136
+ }
137
+ }
157
138
  let txHash;
158
139
  try {
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
- const ueaAddress = this.computeUEAOffchain();
140
+ // FUNDS ONLY SELF
164
141
  if (execute.to.toLowerCase() === ueaAddress.toLowerCase()) {
142
+ // const payloadBytes = this.encodeUniversalPayload(
143
+ // universalPayload as unknown as UniversalPayload
144
+ // );
145
+ // const req = this._buildUniversalTxRequest({
146
+ // recipient: zeroAddress,
147
+ // token: bridgeToken,
148
+ // amount: bridgeAmount,
149
+ // payload: '0x',
150
+ // });
151
+ // const req: UniversalTxRequest = {
152
+ // recipient: zeroAddress,
153
+ // token: bridgeToken,
154
+ // amount: bridgeAmount,
155
+ // payload: '0x',
156
+ // // payload: payloadBytes,
157
+ // revertInstruction: revertCFG,
158
+ // signatureData: '0x',
159
+ // } as unknown as never;
165
160
  txHash = yield evmClient.writeContract({
166
161
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
167
162
  address: gatewayAddress,
168
- functionName: 'sendFunds',
169
- args: [recipient, bridgeToken, bridgeAmount, revertCFG],
163
+ functionName: 'sendUniversalTx',
164
+ args: [req],
170
165
  signer: this.universalSigner,
171
166
  value: isNative ? bridgeAmount : BigInt(0),
172
167
  });
173
168
  }
174
169
  else {
170
+ // FUNDS ONLY OTHER
171
+ // const payloadBytes = this.encodeUniversalPayload(
172
+ // universalPayload as unknown as UniversalPayload
173
+ // );
174
+ // const req: UniversalTxRequest = {
175
+ // recipient,
176
+ // token: bridgeToken,
177
+ // amount: bridgeAmount,
178
+ // payload: payloadBytes,
179
+ // revertInstruction: revertCFG,
180
+ // signatureData: '0x',
181
+ // } as unknown as never;
175
182
  txHash = yield evmClient.writeContract({
176
183
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
177
184
  address: gatewayAddress,
178
- functionName: 'sendTxWithFunds_new',
179
- args: [
180
- tokenAddr,
181
- bridgeAmount,
182
- universalPayload,
183
- revertCFG,
184
- '0x',
185
- ],
185
+ functionName: 'sendUniversalTx',
186
+ args: [req],
186
187
  signer: this.universalSigner,
187
188
  value: nativeAmount,
188
189
  });
@@ -192,13 +193,16 @@ class Orchestrator {
192
193
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_04);
193
194
  throw err;
194
195
  }
195
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
196
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol);
196
+ const originTx = yield this.fetchOriginChainTransactionForProgress(chain, txHash, txHash);
197
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol, originTx);
197
198
  yield this.waitForEvmConfirmationsWithCountdown(evmClient, txHash, 4, 210000);
198
199
  const pushChainUniversalTx = yield this.queryUniversalTxStatusFromGatewayTx(evmClient, gatewayAddress, txHash, execute.to === ueaAddress ? 'sendFunds' : 'sendTxWithFunds');
200
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04);
199
201
  const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
200
202
  const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
201
203
  const response = yield this.transformToUniversalTxResponse(tx);
204
+ // Funds Flow: Funds credited on Push Chain
205
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_05, bridgeAmount, execute.funds.token.decimals, symbol);
202
206
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [response]);
203
207
  return response;
204
208
  }
@@ -209,7 +213,9 @@ class Orchestrator {
209
213
  const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
210
214
  const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
211
215
  const [whitelistPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
216
+ const [rateLimitConfigPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit_config')], programId);
212
217
  const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
218
+ const priceUpdatePk = new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
213
219
  // pay-with-token gas abstraction is not supported on Solana
214
220
  if (execute.payGasWith !== undefined) {
215
221
  throw new Error('Pay-with token is not supported on Solana');
@@ -222,59 +228,43 @@ class Orchestrator {
222
228
  };
223
229
  // New gateway expects EVM recipient as [u8; 20]
224
230
  const recipientEvm20 = Array.from(Buffer.from(execute.to.slice(2).padStart(40, '0'), 'hex').subarray(0, 20));
231
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_01);
232
+ const ueaAddress = this.computeUEAOffchain();
233
+ const { nonce, deployed } = yield this.getUeaStatusAndNonce();
234
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_02, ueaAddress, deployed);
225
235
  if (execute.funds.token.mechanism === 'native') {
226
236
  // Native SOL funds-only
227
- // Compute a local whitelist PDA to avoid TS scope issues
228
- const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
229
- //////// @@@@@@@
230
- //////// @@@@@@@
231
- //////// @@@@@@@
232
- //////// @@@@@@@
233
- //////// @@@@@@@
234
- //////// @@@@@@@
235
- //////// @@@@@@@
236
- //////// @@@@@@@
237
- //////// @@@@@@@
238
- // DO THE SAME AS FOR BELOW, BUT NOW FOR NATIVE.
239
- // for sendTxWithFunds multicall
240
- const ueaAddress = this.computeUEAOffchain();
241
- if (execute.to === ueaAddress) {
242
- txSignature = yield svmClient.writeContract({
243
- abi: abi_1.SVM_GATEWAY_IDL,
244
- address: programId.toBase58(),
245
- functionName: 'sendFunds', // -> unified sendFunds(recipient, bridge_token, bridge_amount, revert_cfg)
246
- args: [
247
- recipientEvm20,
248
- web3_js_1.PublicKey.default,
249
- bridgeAmount,
250
- revertSvm,
251
- ],
252
- signer: this.universalSigner,
253
- accounts: {
254
- config: configPda,
255
- vault: vaultPda,
256
- user: userPk,
257
- tokenWhitelist: whitelistPdaLocal,
258
- userTokenAccount: userPk,
259
- gatewayTokenAccount: vaultPda,
260
- bridgeToken: web3_js_1.PublicKey.default,
261
- tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
262
- systemProgram: web3_js_1.SystemProgram.programId,
263
- },
264
- });
265
- }
266
- else {
267
- const { nonce } = yield this.getUeaStatusAndNonce();
268
- const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', execute.funds.amount);
269
- const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddress);
270
- txSignature = yield this._sendSVMTxWithFunds({
271
- execute,
272
- mechanism: execute.funds.token.mechanism,
273
- universalPayload,
274
- bridgeAmount,
275
- nativeAmount: yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas),
276
- });
277
- }
237
+ const [tokenRateLimitPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit'), web3_js_1.PublicKey.default.toBuffer()], programId);
238
+ const recipientNative = execute.to === ueaAddress
239
+ ? Array.from(Buffer.alloc(20, 0))
240
+ : recipientEvm20;
241
+ const reqNative = this._buildSvmUniversalTxRequest({
242
+ recipient: recipientNative,
243
+ token: web3_js_1.PublicKey.default,
244
+ amount: bridgeAmount,
245
+ payload: '0x',
246
+ fundRecipient: userPk,
247
+ signatureData: '0x',
248
+ });
249
+ txSignature = yield svmClient.writeContract({
250
+ abi: abi_1.SVM_GATEWAY_IDL,
251
+ address: programId.toBase58(),
252
+ functionName: 'sendUniversalTx',
253
+ args: [reqNative, bridgeAmount],
254
+ signer: this.universalSigner,
255
+ accounts: {
256
+ config: configPda,
257
+ vault: vaultPda,
258
+ userTokenAccount: vaultPda,
259
+ gatewayTokenAccount: vaultPda,
260
+ user: userPk,
261
+ priceUpdate: priceUpdatePk,
262
+ rateLimitConfig: rateLimitConfigPda,
263
+ tokenRateLimit: tokenRateLimitPda,
264
+ tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
265
+ systemProgram: web3_js_1.SystemProgram.programId,
266
+ },
267
+ });
278
268
  }
279
269
  else if (execute.funds.token.mechanism === 'approve') {
280
270
  // SPL token funds-only (requires pre-existing ATAs)
@@ -292,57 +282,83 @@ class Orchestrator {
292
282
  TOKEN_PROGRAM_ID.toBuffer(),
293
283
  mintPk.toBuffer(),
294
284
  ], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
295
- const ueaAddress = this.computeUEAOffchain();
285
+ const [tokenRateLimitPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit'), mintPk.toBuffer()], programId);
296
286
  if (execute.to === ueaAddress) {
297
- // vitalik
287
+ const recipientSpl = Array.from(Buffer.alloc(20, 0));
288
+ const reqSpl = this._buildSvmUniversalTxRequest({
289
+ recipient: recipientSpl,
290
+ token: mintPk,
291
+ amount: bridgeAmount,
292
+ payload: '0x',
293
+ fundRecipient: userPk,
294
+ signatureData: '0x',
295
+ });
298
296
  txSignature = yield svmClient.writeContract({
299
297
  abi: abi_1.SVM_GATEWAY_IDL,
300
298
  address: programId.toBase58(),
301
- functionName: 'sendFunds',
302
- args: [recipientEvm20, mintPk, bridgeAmount, revertSvm],
299
+ functionName: 'sendUniversalTx',
300
+ args: [reqSpl, BigInt(0)],
303
301
  signer: this.universalSigner,
304
302
  accounts: {
305
303
  config: configPda,
306
304
  vault: vaultPda,
307
- tokenWhitelist: whitelistPda,
308
305
  userTokenAccount: userAta,
309
306
  gatewayTokenAccount: vaultAta,
310
307
  user: userPk,
311
- bridgeToken: mintPk,
312
308
  tokenProgram: TOKEN_PROGRAM_ID,
309
+ priceUpdate: priceUpdatePk,
310
+ rateLimitConfig: rateLimitConfigPda,
311
+ tokenRateLimit: tokenRateLimitPda,
313
312
  systemProgram: web3_js_1.SystemProgram.programId,
314
313
  },
315
314
  });
316
315
  }
317
316
  else {
318
- const { nonce } = yield this.getUeaStatusAndNonce();
319
- const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendFunds', execute.funds.amount);
320
- const ueaBalanceForGas = yield this.pushClient.getBalance(ueaAddress);
321
- txSignature = yield this._sendSVMTxWithFunds({
322
- execute,
323
- mechanism: execute.funds.token.mechanism,
324
- universalPayload,
325
- bridgeAmount,
326
- nativeAmount: yield this.calculateNativeAmountForDeposit(chain, BigInt(0), ueaBalanceForGas),
317
+ const recipientSpl = recipientEvm20;
318
+ // vitalik
319
+ const reqSpl = this._buildSvmUniversalTxRequest({
320
+ recipient: recipientSpl,
321
+ token: mintPk,
322
+ amount: bridgeAmount,
323
+ payload: '0x',
324
+ fundRecipient: userPk,
325
+ signatureData: '0x',
326
+ });
327
+ txSignature = yield svmClient.writeContract({
328
+ abi: abi_1.SVM_GATEWAY_IDL,
329
+ address: programId.toBase58(),
330
+ functionName: 'sendUniversalTx',
331
+ args: [reqSpl, BigInt(0)],
332
+ signer: this.universalSigner,
333
+ accounts: {
334
+ config: configPda,
335
+ vault: vaultPda,
336
+ userTokenAccount: userAta,
337
+ gatewayTokenAccount: vaultAta,
338
+ user: userPk,
339
+ tokenProgram: TOKEN_PROGRAM_ID,
340
+ priceUpdate: priceUpdatePk,
341
+ rateLimitConfig: rateLimitConfigPda,
342
+ tokenRateLimit: tokenRateLimitPda,
343
+ systemProgram: web3_js_1.SystemProgram.programId,
344
+ },
327
345
  });
328
346
  }
329
347
  }
330
348
  else {
331
349
  throw new Error('Unsupported token mechanism on Solana');
332
350
  }
333
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
334
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txSignature, bridgeAmount, execute.funds.token.decimals, symbol);
335
- yield svmClient.waitForConfirmations({
336
- txSignature,
337
- confirmations: 25,
338
- timeoutMs: 300000,
339
- });
351
+ const originTx = yield this.fetchOriginChainTransactionForProgress(chain, '0x', txSignature);
352
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txSignature, bridgeAmount, execute.funds.token.decimals, symbol, originTx);
353
+ yield this.waitForSvmConfirmationsWithCountdown(svmClient, txSignature, 25, 300000);
340
354
  // After origin confirmations, query Push Chain for UniversalTx status (SVM)
341
355
  const pushChainUniversalTx = yield this.queryUniversalTxStatusFromGatewayTx(undefined, undefined, txSignature, 'sendFunds');
342
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
356
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04);
343
357
  const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
344
358
  const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
345
359
  const response = yield this.transformToUniversalTxResponse(tx);
360
+ // Funds Flow: Funds credited on Push Chain
361
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_05, bridgeAmount, execute.funds.token.decimals, symbol);
346
362
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [response]);
347
363
  return response;
348
364
  }
@@ -352,7 +368,7 @@ class Orchestrator {
352
368
  // - EVM (Sepolia): ERC-20 approve path + native gas via msg.value
353
369
  // - SVM (Solana Devnet): SPL or native SOL with gas_amount
354
370
  const { chain, evmClient, gatewayAddress } = this.getOriginGatewayContext();
355
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain);
371
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain, this.universalSigner.account.address);
356
372
  // Default token to native ETH if none provided
357
373
  if (!execute.funds.token) {
358
374
  const available = tokens_1.MOVEABLE_TOKENS[chain] || [];
@@ -368,7 +384,7 @@ class Orchestrator {
368
384
  }
369
385
  const mechanism = execute.funds.token.mechanism;
370
386
  const { deployed, nonce } = yield this.getUeaStatusAndNonce();
371
- const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendTxWithFunds', execute.funds.amount);
387
+ const { payload: universalPayload, req } = yield this.buildGatewayPayloadAndGas(execute, nonce, 'sendTxWithFunds', execute.funds.amount);
372
388
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_01);
373
389
  // Compute required gas funding on Push Chain and current UEA balance
374
390
  const gasEstimate = execute.gasLimit || BigInt(1e7);
@@ -455,7 +471,6 @@ class Orchestrator {
455
471
  try {
456
472
  if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
457
473
  const tokenAddr = execute.funds.token.address;
458
- // Compute EIP-712 signature for the universal payload and hash to bytes32
459
474
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_01);
460
475
  const ueaAddress = this.computeUEAOffchain();
461
476
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_02, ueaAddress, deployed);
@@ -464,21 +479,7 @@ class Orchestrator {
464
479
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
465
480
  const evmClientEvm = evmClient;
466
481
  const gatewayAddressEvm = gatewayAddress;
467
- // @@@@@@@@@@@@
468
- // txHash = await evmClientEvm.writeContract({
469
- // abi: UNIVERSAL_GATEWAY_V0 as unknown as Abi,
470
- // address: gatewayAddressEvm,
471
- // functionName: 'sendTxWithFunds',
472
- // args: [
473
- // tokenAddr,
474
- // bridgeAmount,
475
- // universalPayload,
476
- // revertCFG,
477
- // '0x',
478
- // ],
479
- // signer: this.universalSigner,
480
- // value: nativeAmount,
481
- // });
482
+ const payloadBytes = this.encodeUniversalPayload(universalPayload);
482
483
  // New behavior: if user provided a gasTokenAddress, pay gas in that token via Uniswap quote
483
484
  // Determine pay-with token address, min-out and slippage
484
485
  const payWith = execute.payGasWith;
@@ -511,37 +512,51 @@ class Orchestrator {
511
512
  // Approve gas token to gateway
512
513
  yield this.ensureErc20Allowance(evmClientEvm, gasTokenAddress, gatewayAddressEvm, gasAmount);
513
514
  // Approve bridge token already done above; now call new gateway signature (nonpayable)
515
+ // const reqToken: UniversalTokenTxRequest = {
516
+ // recipient: zeroAddress,
517
+ // token: tokenAddr,
518
+ // amount: bridgeAmount,
519
+ // gasToken: gasTokenAddress,
520
+ // gasAmount,
521
+ // payload: payloadBytes,
522
+ // revertInstruction: revertCFG,
523
+ // signatureData: '0x',
524
+ // amountOutMinETH,
525
+ // deadline,
526
+ // } as unknown as never;
527
+ const reqToken = Object.assign(Object.assign({}, req), { gasToken: gasTokenAddress, gasAmount,
528
+ amountOutMinETH,
529
+ deadline });
514
530
  txHash = yield evmClientEvm.writeContract({
515
531
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
516
532
  address: gatewayAddressEvm,
517
- functionName: 'sendTxWithFunds_new',
518
- args: [
519
- tokenAddr,
520
- bridgeAmount,
521
- gasTokenAddress,
522
- gasAmount,
523
- amountOutMinETH,
524
- deadline,
525
- universalPayload,
526
- revertCFG,
527
- '0x',
528
- ],
533
+ functionName: 'sendUniversalTx',
534
+ args: [reqToken],
529
535
  signer: this.universalSigner,
530
536
  });
531
537
  }
532
538
  else {
533
539
  // Existing native-ETH value path
540
+ // const req: UniversalTxRequest = {
541
+ // recipient: zeroAddress,
542
+ // token: tokenAddr,
543
+ // amount: bridgeAmount,
544
+ // payload: payloadBytes,
545
+ // revertInstruction: revertCFG,
546
+ // signatureData: '0x',
547
+ // };
548
+ // const req = this._buildUniversalTxRequest({
549
+ // recipient: zeroAddress,
550
+ // token: tokenAddr,
551
+ // amount: bridgeAmount,
552
+ // payload: this.encodeUniversalPayload(universalPayload),
553
+ // });
554
+ // VALUE + PAYLOAD + FUNDS && PAYLOAD + FUNDS
534
555
  txHash = yield evmClientEvm.writeContract({
535
556
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
536
557
  address: gatewayAddressEvm,
537
- functionName: 'sendTxWithFunds_new',
538
- args: [
539
- tokenAddr,
540
- bridgeAmount,
541
- universalPayload,
542
- revertCFG,
543
- '0x',
544
- ],
558
+ functionName: 'sendUniversalTx',
559
+ args: [req],
545
560
  signer: this.universalSigner,
546
561
  value: nativeAmount,
547
562
  });
@@ -554,6 +569,7 @@ class Orchestrator {
554
569
  universalPayload,
555
570
  bridgeAmount,
556
571
  nativeAmount,
572
+ req,
557
573
  });
558
574
  }
559
575
  }
@@ -575,11 +591,7 @@ class Orchestrator {
575
591
  rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
576
592
  chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
577
593
  });
578
- yield svmClient.waitForConfirmations({
579
- txSignature: txHash,
580
- confirmations: 25,
581
- timeoutMs: 300000,
582
- });
594
+ yield this.waitForSvmConfirmationsWithCountdown(svmClient, txHash, 25, 300000);
583
595
  }
584
596
  // Funds Flow: Confirmed on origin
585
597
  let feeLockTxHash = txHash;
@@ -590,12 +602,14 @@ class Orchestrator {
590
602
  feeLockTxHash = (0, viem_1.bytesToHex)(new Uint8Array(decoded));
591
603
  }
592
604
  }
593
- if (chain === enums_1.CHAIN.SOLANA_DEVNET ||
594
- chain === enums_1.CHAIN.SOLANA_TESTNET ||
595
- chain === enums_1.CHAIN.SOLANA_MAINNET) {
596
- yield this.sendUniversalTx(deployed, feeLockTxHash);
597
- }
598
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
605
+ // if (
606
+ // chain === CHAIN.SOLANA_DEVNET ||
607
+ // chain === CHAIN.SOLANA_TESTNET ||
608
+ // chain === CHAIN.SOLANA_MAINNET
609
+ // ) {
610
+ // await this.sendUniversalTx(deployed, feeLockTxHash);
611
+ // }
612
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04);
599
613
  // After sending Cosmos tx to Push Chain, query UniversalTx status
600
614
  let pushChainUniversalTx;
601
615
  if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
@@ -620,13 +634,13 @@ class Orchestrator {
620
634
  execute.value = BigInt(0);
621
635
  }
622
636
  const chain = this.universalSigner.account.chain;
623
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain);
637
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain, this.universalSigner.account.address);
624
638
  this.validateMainnetConnection(chain);
625
639
  /**
626
640
  * Push to Push Tx
627
641
  */
628
642
  if (this.isPushChain(chain)) {
629
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06);
643
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_07);
630
644
  const tx = yield this.sendPushTx(execute);
631
645
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, [tx]);
632
646
  return tx;
@@ -667,6 +681,8 @@ class Orchestrator {
667
681
  // Support multicall payload encoding when execute.data is an array
668
682
  let payloadData;
669
683
  let payloadTo;
684
+ let req;
685
+ // Here is only value and payload. No funds here
670
686
  if (Array.isArray(execute.data)) {
671
687
  // payloadData = this._buildMulticallPayloadData(execute.to, execute.data);
672
688
  // Normal multicall. We replace the `to` to zeroAddress. Then console.warn to let user know that it should be
@@ -675,19 +691,54 @@ class Orchestrator {
675
691
  payloadTo = viem_1.zeroAddress;
676
692
  console.warn(`Multicalls should have execute.to as ${viem_1.zeroAddress}`);
677
693
  payloadData = this._buildMulticallPayloadData(execute.to, (0, payload_builders_1.buildExecuteMulticall)({ execute, ueaAddress: UEA }));
694
+ req = this._buildUniversalTxRequest({
695
+ recipient: viem_1.zeroAddress,
696
+ token: viem_1.zeroAddress,
697
+ amount: BigInt(0),
698
+ payload: payloadData,
699
+ });
678
700
  }
679
701
  else {
680
702
  if (execute.to.toLowerCase() !== UEA.toLowerCase()) {
681
703
  // For Payload + Value we don't do multicall anymore.
682
704
  // Multicall is only when Payload + Value;
683
705
  // Payload + Value + Funds -> Multicall
706
+ // TODO: Check but I beleive this code section is never reached.
684
707
  if (execute.funds) {
685
708
  payloadTo = viem_1.zeroAddress;
686
709
  payloadData = this._buildMulticallPayloadData(execute.to, (0, payload_builders_1.buildExecuteMulticall)({ execute, ueaAddress: UEA }));
710
+ req = this._buildUniversalTxRequest({
711
+ recipient: viem_1.zeroAddress,
712
+ token: viem_1.zeroAddress,
713
+ amount: BigInt(0),
714
+ payload: payloadData,
715
+ });
687
716
  }
688
717
  else {
718
+ // VALUE ONLY OTHER
719
+ // VALUE + PAYLOAD ONLY OTHER
689
720
  payloadTo = execute.to;
690
721
  payloadData = execute.data || '0x';
722
+ const reqData = this._buildMulticallPayloadData(execute.to, (0, payload_builders_1.buildExecuteMulticall)({ execute, ueaAddress: UEA }));
723
+ const universalPayload = JSON.parse(JSON.stringify({
724
+ to: viem_1.zeroAddress,
725
+ value: execute.value,
726
+ data: reqData,
727
+ gasLimit: execute.gasLimit || BigInt(5e7),
728
+ maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
729
+ maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
730
+ nonce,
731
+ deadline: execute.deadline || BigInt(9999999999),
732
+ vType: feeLockingRequired
733
+ ? tx_1.VerificationType.universalTxVerification
734
+ : tx_1.VerificationType.signedVerification,
735
+ }, this.bigintReplacer));
736
+ req = this._buildUniversalTxRequest({
737
+ recipient: viem_1.zeroAddress,
738
+ token: viem_1.zeroAddress,
739
+ amount: BigInt(0),
740
+ payload: this.encodeUniversalPayload(universalPayload),
741
+ });
691
742
  }
692
743
  }
693
744
  else {
@@ -695,8 +746,16 @@ class Orchestrator {
695
746
  if (execute.data && execute.to.toLowerCase() === UEA.toLowerCase()) {
696
747
  throw new Error(`You can't execute data on the UEA address`);
697
748
  }
749
+ // VALUE ONLY SELF
698
750
  payloadTo = execute.to;
699
751
  payloadData = execute.data || '0x';
752
+ req = this._buildUniversalTxRequest({
753
+ // recipient: execute.to,
754
+ recipient: viem_1.zeroAddress,
755
+ token: viem_1.zeroAddress,
756
+ amount: BigInt(0),
757
+ payload: payloadData,
758
+ });
700
759
  }
701
760
  }
702
761
  const universalPayload = JSON.parse(JSON.stringify({
@@ -712,12 +771,6 @@ class Orchestrator {
712
771
  ? tx_1.VerificationType.universalTxVerification
713
772
  : tx_1.VerificationType.signedVerification,
714
773
  }, this.bigintReplacer));
715
- const ueaVersion = yield this.fetchUEAVersion();
716
- const executionHash = this.computeExecutionHash({
717
- verifyingContract: UEA,
718
- payload: universalPayload,
719
- version: ueaVersion,
720
- });
721
774
  /**
722
775
  * Prepare verification data by either signature or fund locking
723
776
  */
@@ -729,13 +782,14 @@ class Orchestrator {
729
782
  * 4. UEA not deployed + insufficient funds: Lock requiredFunds
730
783
  */
731
784
  if (!feeLockingRequired) {
785
+ const ueaVersion = yield this.fetchUEAVersion();
732
786
  /**
733
787
  * Sign Universal Payload
734
788
  */
735
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_01, executionHash);
789
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_02);
736
790
  const signature = yield this.signUniversalPayload(universalPayload, UEA, ueaVersion);
737
791
  verificationData = (0, viem_1.bytesToHex)(signature);
738
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_02, verificationData);
792
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
739
793
  }
740
794
  else {
741
795
  /**
@@ -745,17 +799,20 @@ class Orchestrator {
745
799
  const fixedPushAmount = push_chain_1.PushChain.utils.helpers.parseUnits('0.001', 18); // Minimum lock 0.001 Push tokens
746
800
  const lockAmount = funds < requiredFunds ? fundDifference : fixedPushAmount;
747
801
  const lockAmountInUSD = this.pushClient.pushToUSDC(lockAmount);
748
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_01, lockAmount);
749
- const feeLockTxHashBytes = yield this.lockFee(lockAmountInUSD, universalPayload);
802
+ const feeLockTxHashBytes = yield this.lockFee(lockAmountInUSD, universalPayload, req);
750
803
  feeLockTxHash = (0, viem_1.bytesToHex)(feeLockTxHashBytes);
751
804
  verificationData = (0, viem_1.bytesToHex)(feeLockTxHashBytes);
752
805
  const { vm } = chain_1.CHAIN_INFO[chain];
753
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_02, vm === enums_1.VM.SVM
806
+ const feeLockTxHashDisplay = vm === enums_1.VM.SVM
754
807
  ? anchor_1.utils.bytes.bs58.encode(feeLockTxHashBytes)
755
- : feeLockTxHash, chain_1.CHAIN_INFO[chain].confirmations);
808
+ : feeLockTxHash;
809
+ // Gas Flow: Gas funding in progress (with full origin tx when available)
810
+ const originTx = yield this.fetchOriginChainTransactionForProgress(chain, feeLockTxHash, feeLockTxHashDisplay);
811
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_01, feeLockTxHashDisplay, originTx);
756
812
  // Waiting for blocks confirmations
757
813
  yield this.waitForLockerFeeConfirmation(feeLockTxHashBytes);
758
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_03);
814
+ // Gas Flow: Gas funding confirmed
815
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_05_02);
759
816
  // Query nodes via gRPC for Push Chain transaction
760
817
  const { defaultRPC, lockerContract } = chain_1.CHAIN_INFO[chain];
761
818
  const pushChainUniversalTx = yield this.queryUniversalTxStatusFromGatewayTx(new evm_client_1.EvmClient({ rpcUrls: this.rpcUrls[chain] || defaultRPC }), lockerContract, feeLockTxHash, 'sendTxWithGas');
@@ -763,7 +820,6 @@ class Orchestrator {
763
820
  * Return response directly (skip sendUniversalTx for sendTxWithGas flow)
764
821
  * Note: queryTx may be undefined since validators don't recognize new UniversalTx event yet
765
822
  */
766
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06);
767
823
  // Transform to UniversalTxResponse (follow sendFunds pattern)
768
824
  const lastPcTransaction = pushChainUniversalTx === null || pushChainUniversalTx === void 0 ? void 0 : pushChainUniversalTx.pcTx.at(-1);
769
825
  const tx = yield this.pushClient.getTransaction(lastPcTransaction === null || lastPcTransaction === void 0 ? void 0 : lastPcTransaction.txHash);
@@ -774,7 +830,7 @@ class Orchestrator {
774
830
  /**
775
831
  * Non-fee-locking path: Broadcasting Tx to PC via sendUniversalTx
776
832
  */
777
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06);
833
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_07);
778
834
  // We don't need to query via gRPC the PC transaction since it's getting returned it here already.
779
835
  const transactions = yield this.sendUniversalTx(isUEADeployed, feeLockTxHash, universalPayload, verificationData);
780
836
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_01, transactions);
@@ -806,7 +862,7 @@ class Orchestrator {
806
862
  * @returns Transaction hash bytes
807
863
  */
808
864
  lockFee(amount, // USD with 8 decimals
809
- universalPayload) {
865
+ universalPayload, req) {
810
866
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
811
867
  const chain = this.universalSigner.account.chain;
812
868
  const { lockerContract, vm, defaultRPC } = chain_1.CHAIN_INFO[chain];
@@ -833,23 +889,19 @@ class Orchestrator {
833
889
  (nativeTokenUsdPrice - BigInt(1))) /
834
890
  nativeTokenUsdPrice;
835
891
  nativeAmount = nativeAmount + BigInt(1);
836
- // Deposit-only funding via UniversalGatewayV0 (no payload execution)
837
- const revertCFG = {
838
- fundRecipient: this.universalSigner.account.address,
839
- revertMsg: '0x',
840
- };
841
- // Sign the universal payload
842
- const ueaAddress = this.computeUEAOffchain();
843
- const ueaVersion = yield this.fetchUEAVersion();
844
- const eip712Signature = yield this.signUniversalPayload(universalPayload, ueaAddress, ueaVersion);
845
- const eip712SignatureHex = typeof eip712Signature === 'string'
846
- ? eip712Signature
847
- : (0, viem_1.bytesToHex)(eip712Signature);
892
+ // const req: UniversalTxRequest = {
893
+ // recipient: zeroAddress,
894
+ // token: zeroAddress,
895
+ // amount: BigInt(0),
896
+ // payload: payloadBytes,
897
+ // revertInstruction: revertCFG,
898
+ // signatureData: '0x',
899
+ // } as unknown as never;
848
900
  const txHash = yield evmClient.writeContract({
849
901
  abi: abi_1.UNIVERSAL_GATEWAY_V0,
850
902
  address: lockerContract,
851
- functionName: 'sendTxWithGas',
852
- args: [universalPayload, revertCFG, '0x'],
903
+ functionName: 'sendUniversalTx',
904
+ args: [req],
853
905
  signer: this.universalSigner,
854
906
  value: nativeAmount,
855
907
  });
@@ -877,44 +929,146 @@ class Orchestrator {
877
929
  const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
878
930
  const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
879
931
  const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
932
+ const [rateLimitConfigPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit_config')], programId);
933
+ const [tokenRateLimitPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit'), web3_js_1.PublicKey.default.toBuffer()], programId);
880
934
  const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
881
935
  const revertSvm = {
882
936
  fundRecipient: userPk,
883
937
  revertMsg: Buffer.from([]),
884
938
  };
885
- // const ueaAddressSvm = this.computeUEAOffchain();
886
- // const ueaVersion = await this.fetchUEAVersion();
887
- // const svmSignature = await this.signUniversalPayload(
888
- // universalPayload,
889
- // ueaAddressSvm,
890
- // ueaVersion
891
- // );
892
- const txHash = yield svmClient.writeContract({
893
- abi: abi_1.SVM_GATEWAY_IDL,
894
- address: programId.toBase58(),
895
- functionName: 'sendTxWithGas',
896
- args: [
897
- universalPayload,
898
- revertSvm,
899
- new anchor.BN(nativeAmount.toString()),
900
- '0x',
901
- ],
902
- signer: this.universalSigner,
903
- accounts: {
904
- config: configPda,
905
- vault: vaultPda,
906
- user: userPk,
907
- priceUpdate: new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE'),
908
- systemProgram: web3_js_1.SystemProgram.programId,
909
- },
910
- });
911
- return new Uint8Array(anchor_1.utils.bytes.bs58.decode(txHash));
939
+ const gasReq = this._buildSvmUniversalTxRequestFromReq(req, userPk);
940
+ try {
941
+ const txHash = yield svmClient.writeContract({
942
+ abi: abi_1.SVM_GATEWAY_IDL,
943
+ address: programId.toBase58(),
944
+ functionName: 'sendUniversalTx',
945
+ args: [gasReq, nativeAmount],
946
+ signer: this.universalSigner,
947
+ accounts: {
948
+ config: configPda,
949
+ vault: vaultPda,
950
+ userTokenAccount: vaultPda,
951
+ gatewayTokenAccount: vaultPda,
952
+ user: userPk,
953
+ priceUpdate: new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE'),
954
+ rateLimitConfig: rateLimitConfigPda,
955
+ tokenRateLimit: tokenRateLimitPda,
956
+ tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
957
+ systemProgram: web3_js_1.SystemProgram.programId,
958
+ },
959
+ });
960
+ return new Uint8Array(anchor_1.utils.bytes.bs58.decode(txHash));
961
+ }
962
+ catch (error) {
963
+ console.error('Error sending UniversalTx:', error);
964
+ throw error;
965
+ }
912
966
  }
913
967
  default:
914
968
  throw new Error(`Unsupported VM type: ${vm}`);
915
969
  }
916
970
  });
917
971
  }
972
+ _buildUniversalTxRequest({ recipient, token, amount, payload, }) {
973
+ const revertInstruction = {
974
+ fundRecipient: this.universalSigner.account.address,
975
+ revertMsg: '0x',
976
+ };
977
+ return {
978
+ recipient,
979
+ token,
980
+ amount,
981
+ payload,
982
+ revertInstruction,
983
+ signatureData: '0x',
984
+ };
985
+ }
986
+ /**
987
+ * Builds the SVM UniversalTxRequest object from an existing EVM-style UniversalTxRequest.
988
+ * This allows reusing the same request shape for both EVM and SVM while only translating
989
+ * field encodings (addresses, bytes) to the Solana program format.
990
+ */
991
+ _buildSvmUniversalTxRequestFromReq(req, fundRecipient, signatureDataOverride) {
992
+ // recipient in EVM is a 20-byte address; the SVM gateway expects this as [u8; 20]
993
+ const recipientBytes = (0, viem_1.hexToBytes)(req.recipient);
994
+ const recipient = Array.from(recipientBytes.subarray(0, 20));
995
+ // token in EVM is a 20-byte address. For zeroAddress or the Solana-native sentinel we map to
996
+ // PublicKey.default (all zeros), which mirrors the existing behavior for native SOL paths.
997
+ // For non-zero addresses we embed the 20-byte value into a 32-byte buffer (left-padded with
998
+ // zeros) to obtain a deterministic PublicKey representation.
999
+ const tokenAddress = req.token;
1000
+ let token;
1001
+ if (tokenAddress === viem_1.zeroAddress || tokenAddress === 'solana-native') {
1002
+ // Native SOL on SVM is represented by a sentinel string `solana-native` in token metadata.
1003
+ // The SVM gateway expects the "native" token to be encoded as the default (all-zero) Pubkey.
1004
+ token = web3_js_1.PublicKey.default;
1005
+ }
1006
+ else {
1007
+ if (!tokenAddress.startsWith('0x')) {
1008
+ throw new Error('Unsupported token format for SVM UniversalTxRequest: ' + tokenAddress);
1009
+ }
1010
+ const token20 = (0, viem_1.hexToBytes)(tokenAddress);
1011
+ const token32 = new Uint8Array(32);
1012
+ token32.set(token20, 12);
1013
+ token = new web3_js_1.PublicKey(token32);
1014
+ }
1015
+ return this._buildSvmUniversalTxRequest({
1016
+ recipient,
1017
+ token,
1018
+ amount: req.amount,
1019
+ payload: req.payload,
1020
+ fundRecipient,
1021
+ signatureData: signatureDataOverride !== null && signatureDataOverride !== void 0 ? signatureDataOverride : req.signatureData,
1022
+ });
1023
+ }
1024
+ /**
1025
+ * Builds the SVM UniversalTxRequest object expected by the Solana gateway program.
1026
+ * Shape mirrors the request used in `svm-gateway` tests.
1027
+ */
1028
+ _buildSvmUniversalTxRequest({ recipient, token, amount, payload, fundRecipient, signatureData, }) {
1029
+ const payloadBuf = typeof payload === 'string' && payload.startsWith('0x')
1030
+ ? (() => {
1031
+ const hex = payload.slice(2);
1032
+ if (!hex.length)
1033
+ return Buffer.alloc(0);
1034
+ const normalized = hex.length % 2 === 1 ? `0${hex}` : hex;
1035
+ return Buffer.from(normalized, 'hex');
1036
+ })()
1037
+ : Buffer.from(payload);
1038
+ let signatureBuf;
1039
+ if (!signatureData) {
1040
+ signatureBuf = Buffer.alloc(0);
1041
+ }
1042
+ else if (typeof signatureData === 'string' &&
1043
+ signatureData.startsWith('0x')) {
1044
+ const hex = signatureData.slice(2);
1045
+ if (!hex.length) {
1046
+ signatureBuf = Buffer.alloc(0);
1047
+ }
1048
+ else {
1049
+ const normalized = hex.length % 2 === 1 ? `0${hex}` : hex;
1050
+ signatureBuf = Buffer.from(normalized, 'hex');
1051
+ }
1052
+ }
1053
+ else {
1054
+ // vitalik
1055
+ // I'm testing to see if it's possible to pass 0x as signature, the same way we did for EVM.
1056
+ // @@@@
1057
+ signatureBuf = Buffer.from(signatureData);
1058
+ // signatureBuf = Buffer.alloc(0);
1059
+ }
1060
+ return {
1061
+ recipient,
1062
+ token,
1063
+ amount,
1064
+ payload: payloadBuf,
1065
+ revertInstruction: {
1066
+ fundRecipient,
1067
+ revertMsg: Buffer.alloc(0),
1068
+ },
1069
+ signatureData: signatureBuf,
1070
+ };
1071
+ }
918
1072
  signUniversalPayload(universalPayload, verifyingContract, version) {
919
1073
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
920
1074
  const chain = this.universalSigner.account.chain;
@@ -1111,6 +1265,118 @@ class Orchestrator {
1111
1265
  // 4. Final digest
1112
1266
  return (0, viem_1.keccak256)((0, viem_1.encodePacked)(['string', 'bytes32', 'bytes32'], ['\x19\x01', domainSeparator, structHash]));
1113
1267
  }
1268
+ /**
1269
+ * ABI-encodes a UniversalPayload struct to bytes, matching the Solidity layout.
1270
+ * This mirrors abi.encode(UniversalPayload) in the EVM contracts.
1271
+ */
1272
+ encodeUniversalPayload(payload) {
1273
+ return (0, viem_1.encodeAbiParameters)([
1274
+ { name: 'to', type: 'address' },
1275
+ { name: 'value', type: 'uint256' },
1276
+ { name: 'data', type: 'bytes' },
1277
+ { name: 'gasLimit', type: 'uint256' },
1278
+ { name: 'maxFeePerGas', type: 'uint256' },
1279
+ { name: 'maxPriorityFeePerGas', type: 'uint256' },
1280
+ { name: 'nonce', type: 'uint256' },
1281
+ { name: 'deadline', type: 'uint256' },
1282
+ { name: 'vType', type: 'uint8' },
1283
+ ], [
1284
+ payload.to,
1285
+ BigInt(payload.value),
1286
+ payload.data,
1287
+ BigInt(payload.gasLimit),
1288
+ BigInt(payload.maxFeePerGas),
1289
+ BigInt(payload.maxPriorityFeePerGas),
1290
+ BigInt(payload.nonce),
1291
+ BigInt(payload.deadline),
1292
+ Number(payload.vType),
1293
+ ]);
1294
+ }
1295
+ /**
1296
+ * Encodes a UniversalPayload into Borsh bytes for the SVM universal gateway.
1297
+ * Layout mirrors Rust `UniversalPayload`:
1298
+ * to: [u8; 20],
1299
+ * value: u64,
1300
+ * data: Vec<u8> (u32 LE len + bytes),
1301
+ * gas_limit: u64,
1302
+ * max_fee_per_gas: u64,
1303
+ * max_priority_fee_per_gas: u64,
1304
+ * nonce: u64,
1305
+ * deadline: i64,
1306
+ * v_type: u8 (0 = SignedVerification, 1 = UniversalTxVerification)
1307
+ */
1308
+ encodeUniversalPayloadSvm(payload) {
1309
+ const writeU64 = (val) => {
1310
+ const b = Buffer.alloc(8);
1311
+ const big = BigInt(val);
1312
+ b.writeBigUInt64LE(big, 0);
1313
+ return b;
1314
+ };
1315
+ const writeI64 = (val) => {
1316
+ const b = Buffer.alloc(8);
1317
+ const big = BigInt(val);
1318
+ b.writeBigInt64LE(big, 0);
1319
+ return b;
1320
+ };
1321
+ const writeVecU8 = (val) => {
1322
+ const bytes = Buffer.isBuffer(val)
1323
+ ? val
1324
+ : Buffer.from(val);
1325
+ const len = Buffer.alloc(4);
1326
+ len.writeUInt32LE(bytes.length, 0);
1327
+ return Buffer.concat([len, bytes]);
1328
+ };
1329
+ const writeU8 = (val) => Buffer.from([val]);
1330
+ // 1. to: address (20 bytes)
1331
+ const toBytes = (() => {
1332
+ // EVM-style 0x-address string
1333
+ const to = payload.to;
1334
+ const hex = to.slice(2).padStart(40, '0');
1335
+ return Buffer.from(hex, 'hex');
1336
+ })();
1337
+ // 2. value: u64
1338
+ const valueBytes = writeU64(payload.value);
1339
+ // 3. data: bytes -> Vec<u8>
1340
+ const dataBytes = (() => {
1341
+ const data = payload.data;
1342
+ const hex = data.slice(2);
1343
+ const buf = hex.length ? Buffer.from(hex, 'hex') : Buffer.alloc(0);
1344
+ return writeVecU8(buf);
1345
+ })();
1346
+ // 4. gasLimit: u64
1347
+ const gasLimitBytes = writeU64(payload.gasLimit);
1348
+ // 5. maxFeePerGas: u64
1349
+ const maxFeePerGasBytes = writeU64(payload.maxFeePerGas);
1350
+ // 6. maxPriorityFeePerGas: u64
1351
+ const maxPriorityFeePerGasBytes = writeU64(payload.maxPriorityFeePerGas);
1352
+ // 7. nonce: u64
1353
+ const nonceBytes = writeU64(payload.nonce);
1354
+ // 8. deadline: i64
1355
+ const deadlineBytes = writeI64(payload.deadline);
1356
+ // 9. vType: u8
1357
+ const vTypeVal = (() => {
1358
+ // When coming from EVM, vType is numeric (0/1) in most paths
1359
+ const v = payload.vType;
1360
+ if (typeof v === 'number')
1361
+ return v;
1362
+ if (typeof v === 'string')
1363
+ return Number(v);
1364
+ // Fallback: treat anything else as SignedVerification
1365
+ return 0;
1366
+ })();
1367
+ const vTypeBytes = writeU8(vTypeVal);
1368
+ return Buffer.concat([
1369
+ toBytes,
1370
+ valueBytes,
1371
+ dataBytes,
1372
+ gasLimitBytes,
1373
+ maxFeePerGasBytes,
1374
+ maxPriorityFeePerGasBytes,
1375
+ nonceBytes,
1376
+ deadlineBytes,
1377
+ vTypeBytes,
1378
+ ]);
1379
+ }
1114
1380
  /**
1115
1381
  * Computes UEA for given UniversalAccount
1116
1382
  * @dev - This fn calls a view fn of Factory Contract
@@ -1195,7 +1461,7 @@ class Orchestrator {
1195
1461
  return (selector + encodedCalls.slice(2));
1196
1462
  }
1197
1463
  _sendSVMTxWithFunds(_a) {
1198
- return tslib_1.__awaiter(this, arguments, void 0, function* ({ execute, mechanism, universalPayload, bridgeAmount, nativeAmount, }) {
1464
+ return tslib_1.__awaiter(this, arguments, void 0, function* ({ execute, mechanism, universalPayload, bridgeAmount, nativeAmount, req, }) {
1199
1465
  var _b, _c, _d, _e;
1200
1466
  // SVM funds+payload path
1201
1467
  const svmClient = new svm_client_1.SvmClient({
@@ -1205,9 +1471,9 @@ class Orchestrator {
1205
1471
  const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
1206
1472
  const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
1207
1473
  const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
1208
- // whitelistPda already computed above
1209
1474
  const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
1210
1475
  const priceUpdatePk = new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
1476
+ const [rateLimitConfigPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit_config')], programId);
1211
1477
  // pay-with-token gas abstraction is not supported on Solana
1212
1478
  if (execute.payGasWith !== undefined) {
1213
1479
  throw new Error('Pay-with token is not supported on Solana');
@@ -1227,29 +1493,32 @@ class Orchestrator {
1227
1493
  if (isNative) {
1228
1494
  // Native SOL as bridge + gas
1229
1495
  const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
1496
+ const [tokenRateLimitPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit'), web3_js_1.PublicKey.default.toBuffer()], programId);
1497
+ const nativeReq = this._buildSvmUniversalTxRequest({
1498
+ recipient: Array.from(Buffer.alloc(20, 0)),
1499
+ token: web3_js_1.PublicKey.default,
1500
+ amount: bridgeAmount,
1501
+ payload: Uint8Array.from(this.encodeUniversalPayloadSvm(universalPayload)),
1502
+ fundRecipient: userPk,
1503
+ signatureData: svmSignature,
1504
+ });
1230
1505
  return yield svmClient.writeContract({
1231
1506
  abi: abi_1.SVM_GATEWAY_IDL,
1232
1507
  address: programId.toBase58(),
1233
- functionName: 'sendTxWithFunds',
1234
- args: [
1235
- web3_js_1.PublicKey.default, // bridge_token = default for native SOL
1236
- bridgeAmount,
1237
- universalPayload,
1238
- revertSvm2,
1239
- nativeAmount,
1240
- Buffer.from(svmSignature),
1241
- ],
1508
+ functionName: 'sendUniversalTx',
1509
+ args: [nativeReq, nativeAmount],
1242
1510
  signer: this.universalSigner,
1243
1511
  accounts: {
1244
1512
  config: configPda,
1245
1513
  vault: vaultPda,
1246
1514
  tokenWhitelist: whitelistPdaLocal,
1247
- userTokenAccount: userPk, // for native SOL, can be any valid account
1248
- gatewayTokenAccount: vaultPda, // for native SOL, can be any valid account
1515
+ userTokenAccount: vaultPda, // dummy for native SOL
1516
+ gatewayTokenAccount: vaultPda, // dummy for native SOL
1249
1517
  user: userPk,
1250
1518
  priceUpdate: priceUpdatePk,
1251
- bridgeToken: web3_js_1.PublicKey.default,
1252
1519
  tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
1520
+ rateLimitConfig: rateLimitConfigPda,
1521
+ tokenRateLimit: tokenRateLimitPda,
1253
1522
  systemProgram: web3_js_1.SystemProgram.programId,
1254
1523
  },
1255
1524
  });
@@ -1265,18 +1534,20 @@ class Orchestrator {
1265
1534
  const userAta = web3_js_1.PublicKey.findProgramAddressSync([userPk.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintPk.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
1266
1535
  const vaultAta = web3_js_1.PublicKey.findProgramAddressSync([vaultPda.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mintPk.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
1267
1536
  const [whitelistPdaLocal] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
1537
+ const [tokenRateLimitPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('rate_limit'), mintPk.toBuffer()], programId);
1538
+ const splReq = this._buildSvmUniversalTxRequest({
1539
+ recipient: Array.from(Buffer.alloc(20, 0)),
1540
+ token: mintPk,
1541
+ amount: bridgeAmount,
1542
+ payload: Uint8Array.from(this.encodeUniversalPayloadSvm(universalPayload)),
1543
+ fundRecipient: userPk,
1544
+ signatureData: svmSignature,
1545
+ });
1268
1546
  return yield svmClient.writeContract({
1269
1547
  abi: abi_1.SVM_GATEWAY_IDL,
1270
1548
  address: programId.toBase58(),
1271
- functionName: 'sendTxWithFunds',
1272
- args: [
1273
- mintPk,
1274
- bridgeAmount,
1275
- universalPayload,
1276
- revertSvm2,
1277
- nativeAmount,
1278
- Buffer.from(svmSignature),
1279
- ],
1549
+ functionName: 'sendUniversalTx',
1550
+ args: [splReq, nativeAmount],
1280
1551
  signer: this.universalSigner,
1281
1552
  accounts: {
1282
1553
  config: configPda,
@@ -1286,8 +1557,9 @@ class Orchestrator {
1286
1557
  gatewayTokenAccount: vaultAta,
1287
1558
  user: userPk,
1288
1559
  priceUpdate: priceUpdatePk,
1289
- bridgeToken: mintPk,
1290
1560
  tokenProgram: TOKEN_PROGRAM_ID,
1561
+ rateLimitConfig: rateLimitConfigPda,
1562
+ tokenRateLimit: tokenRateLimitPda,
1291
1563
  systemProgram: web3_js_1.SystemProgram.programId,
1292
1564
  },
1293
1565
  });
@@ -1397,6 +1669,40 @@ class Orchestrator {
1397
1669
  }
1398
1670
  });
1399
1671
  }
1672
+ /**
1673
+ * Internal helper: fetches the full origin-chain transaction for a given hash,
1674
+ * used only for progress-hook context (EVM or Solana).
1675
+ */
1676
+ fetchOriginChainTransactionForProgress(chain, txHashHex, txHashDisplay) {
1677
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1678
+ const { vm, defaultRPC } = chain_1.CHAIN_INFO[chain];
1679
+ const rpcUrls = this.rpcUrls[chain] || defaultRPC;
1680
+ try {
1681
+ if (vm === enums_1.VM.EVM) {
1682
+ if (!txHashHex.startsWith('0x')) {
1683
+ throw new Error('EVM transaction hash must be 0x-prefixed');
1684
+ }
1685
+ const evmClient = new evm_client_1.EvmClient({ rpcUrls });
1686
+ const tx = yield evmClient.publicClient.getTransaction({
1687
+ hash: txHashHex,
1688
+ });
1689
+ return tx !== null && tx !== void 0 ? tx : undefined;
1690
+ }
1691
+ if (vm === enums_1.VM.SVM) {
1692
+ const connection = new web3_js_1.Connection(rpcUrls[0], 'confirmed');
1693
+ const tx = yield connection.getTransaction(txHashDisplay, {
1694
+ maxSupportedTransactionVersion: 0,
1695
+ commitment: 'confirmed',
1696
+ });
1697
+ return tx !== null && tx !== void 0 ? tx : undefined;
1698
+ }
1699
+ return undefined;
1700
+ }
1701
+ catch (_a) {
1702
+ return undefined;
1703
+ }
1704
+ });
1705
+ }
1400
1706
  /**
1401
1707
  * Quotes exact-output on Uniswap V3 for EVM origin chains using QuoterV2.
1402
1708
  * Returns the minimum required input (amountIn) to receive the target amountOut.
@@ -1623,7 +1929,7 @@ class Orchestrator {
1623
1929
  */
1624
1930
  buildGatewayPayloadAndGas(execute, nonce, type, fundsValue) {
1625
1931
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
1626
- var _a, _b, _c, _d, _e;
1932
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
1627
1933
  const gasEstimate = execute.gasLimit || BigInt(1e7);
1628
1934
  const gasAmount = (_a = execute.value) !== null && _a !== void 0 ? _a : BigInt(0);
1629
1935
  if (type === 'sendTxWithFunds') {
@@ -1646,7 +1952,19 @@ class Orchestrator {
1646
1952
  deadline: execute.deadline || BigInt(9999999999),
1647
1953
  vType: tx_1.VerificationType.universalTxVerification,
1648
1954
  };
1649
- return { payload: universalPayload, gasAmount };
1955
+ // Temporary while we don't change the native address from 0xeee... to 0x0000...
1956
+ let tokenAddress = (_f = (_e = execute.funds) === null || _e === void 0 ? void 0 : _e.token) === null || _f === void 0 ? void 0 : _f.address;
1957
+ if (((_h = (_g = execute.funds) === null || _g === void 0 ? void 0 : _g.token) === null || _h === void 0 ? void 0 : _h.address) ===
1958
+ '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') {
1959
+ tokenAddress = viem_1.zeroAddress;
1960
+ }
1961
+ const req = this._buildUniversalTxRequest({
1962
+ recipient: viem_1.zeroAddress,
1963
+ token: tokenAddress,
1964
+ amount: (_j = execute.funds) === null || _j === void 0 ? void 0 : _j.amount,
1965
+ payload: this.encodeUniversalPayload(universalPayload),
1966
+ });
1967
+ return { payload: universalPayload, gasAmount, req };
1650
1968
  }
1651
1969
  else {
1652
1970
  if (!fundsValue)
@@ -1662,12 +1980,12 @@ class Orchestrator {
1662
1980
  // functionName: 'transfer',
1663
1981
  // args: [execute.to, fundsValue],
1664
1982
  // });
1665
- // const pushChainTo = PushChain.utils.tokens.getPRC20Mapping(
1983
+ // const pushChainTo = PushChain.utils.tokens.getPRC20Address(
1666
1984
  // execute.funds!.token as MoveableToken
1667
1985
  // );
1668
1986
  const universalPayload = {
1669
1987
  to: viem_1.zeroAddress, // We can't simply do `0x` because we will get an error when eip712 signing the transaction.
1670
- value: (_e = execute.value) !== null && _e !== void 0 ? _e : BigInt(0),
1988
+ value: (_k = execute.value) !== null && _k !== void 0 ? _k : BigInt(0),
1671
1989
  data: this._buildMulticallPayloadData(execute.to, multicallData),
1672
1990
  // data: this._buildMulticallPayloadData(execute.to, [
1673
1991
  // { to: pushChainTo, value: execute.value ?? BigInt(0), data },
@@ -1679,7 +1997,19 @@ class Orchestrator {
1679
1997
  deadline: execute.deadline || BigInt(9999999999),
1680
1998
  vType: tx_1.VerificationType.universalTxVerification,
1681
1999
  };
1682
- return { payload: universalPayload, gasAmount };
2000
+ // Temporary while we don't change the native address from 0xeee... to 0x0000...
2001
+ let tokenAddress = (_m = (_l = execute.funds) === null || _l === void 0 ? void 0 : _l.token) === null || _m === void 0 ? void 0 : _m.address;
2002
+ if (((_p = (_o = execute.funds) === null || _o === void 0 ? void 0 : _o.token) === null || _p === void 0 ? void 0 : _p.address) ===
2003
+ '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') {
2004
+ tokenAddress = viem_1.zeroAddress;
2005
+ }
2006
+ const req = this._buildUniversalTxRequest({
2007
+ recipient: viem_1.zeroAddress,
2008
+ token: tokenAddress,
2009
+ amount: (_q = execute.funds) === null || _q === void 0 ? void 0 : _q.amount,
2010
+ payload: this.encodeUniversalPayload(universalPayload),
2011
+ });
2012
+ return { payload: universalPayload, gasAmount, req };
1683
2013
  }
1684
2014
  });
1685
2015
  }
@@ -1910,6 +2240,8 @@ class Orchestrator {
1910
2240
  if (!Array.isArray(logs) || logs.length === 0)
1911
2241
  return 0;
1912
2242
  const prefix = 'Program data: ';
2243
+ let matchCount = 0;
2244
+ let lastMatchIndex = -1;
1913
2245
  for (let i = 0; i < logs.length; i++) {
1914
2246
  const log = logs[i] || '';
1915
2247
  if (!log.startsWith(prefix))
@@ -1925,12 +2257,19 @@ class Orchestrator {
1925
2257
  if (!decoded || decoded.length < 8)
1926
2258
  continue;
1927
2259
  const discriminatorHex = (0, viem_1.bytesToHex)(decoded.slice(0, 8)).slice(2);
1928
- // Skip add_funds discriminator; return the first other Program data event
2260
+ // Skip add_funds discriminator; return the second matching Program data event
1929
2261
  // if (discriminatorHex === '7f1f6cffbb134644') continue;
1930
- if (discriminatorHex === '6c9ad829b5ea1d7c')
1931
- return i;
2262
+ if (discriminatorHex === '6c9ad829b5ea1d7c') {
2263
+ matchCount++;
2264
+ lastMatchIndex = i;
2265
+ if (matchCount === 2)
2266
+ return i;
2267
+ }
1932
2268
  // return i;
1933
2269
  }
2270
+ // If only one match was found, keep previous behavior and return that one.
2271
+ if (lastMatchIndex !== -1)
2272
+ return lastMatchIndex;
1934
2273
  // Fallback to first log
1935
2274
  return 0;
1936
2275
  }
@@ -2013,25 +2352,9 @@ class Orchestrator {
2013
2352
  }
2014
2353
  yield new Promise((r) => setTimeout(r, 1500));
2015
2354
  }
2016
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06, (universalTxObj === null || universalTxObj === void 0 ? void 0 : universalTxObj.universalStatus) || (universalTxObj === null || universalTxObj === void 0 ? void 0 : universalTxObj.universal_status));
2017
- // this.printLog(
2018
- // `UniversalTx fetched via gRPC: ${JSON.stringify(
2019
- // {
2020
- // gatewayTx: txHashHex,
2021
- // id: idHex,
2022
- // status:
2023
- // universalTxObj?.universalStatus ||
2024
- // universalTxObj?.universal_status,
2025
- // },
2026
- // this.bigintReplacer,
2027
- // 2
2028
- // )}`
2029
- // );
2030
2355
  return universalTxObj;
2031
2356
  }
2032
2357
  catch (_d) {
2033
- // Best-effort; do not fail flow if PC query is unavailable
2034
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
2035
2358
  return undefined;
2036
2359
  }
2037
2360
  });
@@ -2057,7 +2380,7 @@ class Orchestrator {
2057
2380
  if (currentBlock >= targetBlock) {
2058
2381
  // Only emit if we haven't already shown this confirmation
2059
2382
  if (lastEmitted < confirmations) {
2060
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, confirmations, confirmations);
2383
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_02, confirmations, confirmations);
2061
2384
  }
2062
2385
  return;
2063
2386
  }
@@ -2065,7 +2388,9 @@ class Orchestrator {
2065
2388
  const completed = Math.max(1, confirmations - remaining + 1);
2066
2389
  // Only emit if this is a new confirmation count
2067
2390
  if (completed > lastEmitted) {
2068
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, completed, confirmations);
2391
+ this.executeProgressHook(completed >= confirmations
2392
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_02
2393
+ : progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_01, completed, confirmations);
2069
2394
  lastEmitted = completed;
2070
2395
  // If we've reached required confirmations, we're done
2071
2396
  if (completed >= confirmations) {
@@ -2082,7 +2407,6 @@ class Orchestrator {
2082
2407
  // Emit countdown updates while waiting for SVM confirmations
2083
2408
  waitForSvmConfirmationsWithCountdown(svmClient, txSignature, confirmations, timeoutMs) {
2084
2409
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
2085
- var _a;
2086
2410
  // initial emit
2087
2411
  this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03, confirmations);
2088
2412
  const start = Date.now();
@@ -2094,19 +2418,35 @@ class Orchestrator {
2094
2418
  const { value } = yield connection.getSignatureStatuses([txSignature]);
2095
2419
  const status = value[0];
2096
2420
  if (status) {
2097
- const currentConfirms = (_a = status.confirmations) !== null && _a !== void 0 ? _a : 0;
2098
- const hasEnoughConfirmations = currentConfirms >= confirmations;
2099
- const isSuccessfullyFinalized = status.err === null && status.confirmationStatus !== null;
2100
- // Emit progress if we have more confirmations than before OR if finalized
2101
- if (currentConfirms > lastConfirmed ||
2102
- (isSuccessfullyFinalized && lastConfirmed === 0)) {
2103
- const confirmCount = isSuccessfullyFinalized && currentConfirms === 0
2104
- ? confirmations
2105
- : currentConfirms;
2106
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_04, Math.max(1, confirmCount), confirmations);
2421
+ // Surface transaction failures explicitly
2422
+ if (status.err) {
2423
+ throw new Error(`SVM transaction ${txSignature} failed: ${JSON.stringify(status.err)}`);
2424
+ }
2425
+ const rawConfirmations = status.confirmations;
2426
+ const hasNumericConfirmations = rawConfirmations != null;
2427
+ const currentConfirms = hasNumericConfirmations ? rawConfirmations : 0;
2428
+ // Align "finalized" semantics with SvmClient.waitForConfirmations:
2429
+ // treat either an explicit "finalized" status or a rooted tx
2430
+ // (confirmations === null) with no error as final.
2431
+ const isFinalized = status.err === null &&
2432
+ (status.confirmationStatus === 'finalized' ||
2433
+ status.confirmations === null);
2434
+ const hasEnoughConfirmations = hasNumericConfirmations && currentConfirms >= confirmations;
2435
+ // Emit progress only when the visible confirmation count increases.
2436
+ // We never "jump" straight to the requested confirmations unless
2437
+ // we're finalizing and haven't yet emitted a final step.
2438
+ if (currentConfirms > lastConfirmed) {
2439
+ const clamped = currentConfirms >= confirmations ? confirmations : currentConfirms;
2440
+ this.executeProgressHook(clamped >= confirmations
2441
+ ? progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_02
2442
+ : progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_01, Math.max(1, clamped), confirmations);
2107
2443
  lastConfirmed = currentConfirms;
2108
2444
  }
2109
- if (hasEnoughConfirmations || isSuccessfullyFinalized) {
2445
+ if (hasEnoughConfirmations || isFinalized) {
2446
+ // Ensure we emit a final "all confirmations" step if we haven't yet.
2447
+ if (lastConfirmed < confirmations) {
2448
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03_02, confirmations, confirmations);
2449
+ }
2110
2450
  return;
2111
2451
  }
2112
2452
  }
@@ -2185,6 +2525,7 @@ class Orchestrator {
2185
2525
  calculateNativeAmountForDeposit(chain, requiredFunds, ueaBalance) {
2186
2526
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
2187
2527
  var _a, _b;
2528
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_01);
2188
2529
  // Determine USD to deposit via gateway (8 decimals) with caps: min=$1, max=$10
2189
2530
  const oneUsd = push_chain_1.PushChain.utils.helpers.parseUnits('1', 8);
2190
2531
  const tenUsd = push_chain_1.PushChain.utils.helpers.parseUnits('10', 8);
@@ -2194,7 +2535,6 @@ class Orchestrator {
2194
2535
  depositUsd = oneUsd;
2195
2536
  if (depositUsd > tenUsd)
2196
2537
  throw new Error('Deposit value exceeds max $10 worth of native token');
2197
- this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_02, depositUsd);
2198
2538
  // If SVM, clamp depositUsd to on-chain Config caps
2199
2539
  if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM) {
2200
2540
  const svmClient = new svm_client_1.SvmClient({
@@ -2236,6 +2576,7 @@ class Orchestrator {
2236
2576
  nativeTokenUsdPrice;
2237
2577
  // Add 1 unit safety to avoid BelowMinCap from rounding differences
2238
2578
  nativeAmount = nativeAmount + BigInt(1);
2579
+ this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_02, nativeAmount);
2239
2580
  return nativeAmount;
2240
2581
  });
2241
2582
  }