@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.
- package/CHANGELOG.md +6 -0
- package/package.json +4 -3
- package/src/lib/constants/abi/erc20.evm.d.ts +33 -0
- package/src/lib/constants/abi/erc20.evm.js +19 -0
- package/src/lib/constants/abi/erc20.evm.js.map +1 -1
- package/src/lib/constants/abi/universalGatewayV0.evm.d.ts +56 -9
- package/src/lib/constants/abi/universalGatewayV0.evm.js +1023 -64
- package/src/lib/constants/abi/universalGatewayV0.evm.js.map +1 -1
- package/src/lib/constants/abi/universalGatewayV0.json +1223 -206
- package/src/lib/constants/chain.d.ts +4 -0
- package/src/lib/constants/chain.js +24 -2
- package/src/lib/constants/chain.js.map +1 -1
- package/src/lib/constants/tokens.d.ts +1 -0
- package/src/lib/constants/tokens.js +3 -0
- package/src/lib/constants/tokens.js.map +1 -1
- package/src/lib/generated/v1/tx.d.ts +1 -2
- package/src/lib/generated/v1/tx.js +2 -1
- package/src/lib/generated/v1/tx.js.map +1 -1
- package/src/lib/orchestrator/orchestrator.d.ts +6 -2
- package/src/lib/orchestrator/orchestrator.js +645 -336
- package/src/lib/orchestrator/orchestrator.js.map +1 -1
- package/src/lib/orchestrator/payload-builders.d.ts +5 -0
- package/src/lib/orchestrator/payload-builders.js +58 -0
- package/src/lib/orchestrator/payload-builders.js.map +1 -0
- package/src/lib/push-chain/helpers/abis.d.ts +31 -0
- package/src/lib/push-chain/helpers/abis.js +75 -0
- package/src/lib/push-chain/helpers/abis.js.map +1 -0
- package/src/lib/push-chain/helpers/addresses.d.ts +1 -0
- package/src/lib/push-chain/helpers/addresses.js +5 -0
- package/src/lib/push-chain/helpers/addresses.js.map +1 -0
- package/src/lib/utils.d.ts +9 -0
- package/src/lib/utils.js +73 -0
- package/src/lib/utils.js.map +1 -1
- package/src/lib/vm-client/svm-client.js +26 -3
- 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
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
const tx = yield
|
|
162
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
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: '
|
|
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
|
-
|
|
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: '
|
|
544
|
+
functionName: 'sendTxWithFunds_new',
|
|
493
545
|
args: [
|
|
494
546
|
tokenAddr,
|
|
495
547
|
bridgeAmount,
|
|
496
548
|
universalPayload,
|
|
497
549
|
revertCFG,
|
|
498
|
-
|
|
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
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
|
|
607
|
+
pushChainUniversalTx =
|
|
608
|
+
yield this.queryUniversalTxStatusFromGatewayTx(evmClientEvm, gatewayAddressEvm, txHash, 'sendTxWithFunds');
|
|
645
609
|
}
|
|
646
610
|
else {
|
|
647
|
-
|
|
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
|
-
//
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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(
|
|
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,
|
|
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
|
|
801
|
+
* @returns Transaction hash bytes
|
|
848
802
|
*/
|
|
849
|
-
lockFee(
|
|
850
|
-
|
|
851
|
-
|
|
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
|
-
|
|
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.
|
|
844
|
+
abi: abi_1.UNIVERSAL_GATEWAY_V0,
|
|
869
845
|
address: lockerContract,
|
|
870
|
-
functionName: '
|
|
871
|
-
args: [
|
|
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
|
|
879
|
-
const [nativeTokenUsdPrice, svmClient
|
|
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
|
|
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.
|
|
888
|
-
address:
|
|
889
|
-
functionName: '
|
|
890
|
-
args: [
|
|
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
|
-
|
|
894
|
-
|
|
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.
|
|
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.
|
|
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
|
-
*
|
|
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
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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
|
-
|
|
1743
|
-
|
|
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,
|
|
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
|
-
|
|
1761
|
-
|
|
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 =
|
|
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 <
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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
|