@pushchain/core 2.0.2 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/lib/constants/abi/erc20.evm.d.ts +36 -0
- package/src/lib/constants/abi/erc20.evm.js +26 -0
- package/src/lib/constants/abi/erc20.evm.js.map +1 -0
- package/src/lib/constants/abi/index.d.ts +3 -0
- package/src/lib/constants/abi/index.js +7 -1
- package/src/lib/constants/abi/index.js.map +1 -1
- package/src/lib/constants/abi/pushsolanagateway.json +1004 -0
- package/src/lib/constants/abi/universalGatewayV0.evm.d.ts +31 -0
- package/src/lib/constants/abi/universalGatewayV0.evm.js +141 -0
- package/src/lib/constants/abi/universalGatewayV0.evm.js.map +1 -0
- package/src/lib/constants/index.d.ts +1 -0
- package/src/lib/constants/index.js.map +1 -1
- package/src/lib/constants/tokens.d.ts +50 -0
- package/src/lib/constants/tokens.js +167 -0
- package/src/lib/constants/tokens.js.map +1 -0
- package/src/lib/generated/uexecutor/v1/query.d.ts +23 -0
- package/src/lib/generated/uexecutor/v1/query.js +79 -0
- package/src/lib/generated/uexecutor/v1/query.js.map +1 -0
- package/src/lib/generated/uexecutor/v1/types.d.ts +91 -0
- package/src/lib/generated/uexecutor/v1/types.js +856 -0
- package/src/lib/generated/uexecutor/v1/types.js.map +1 -0
- package/src/lib/generated/v1/tx.d.ts +4 -4
- package/src/lib/generated/v1/tx.js +1 -1
- package/src/lib/index.d.ts +1 -0
- package/src/lib/index.js.map +1 -1
- package/src/lib/orchestrator/orchestrator.d.ts +18 -0
- package/src/lib/orchestrator/orchestrator.js +712 -1
- package/src/lib/orchestrator/orchestrator.js.map +1 -1
- package/src/lib/orchestrator/orchestrator.types.d.ts +13 -0
- package/src/lib/progress-hook/progress-hook.js +66 -0
- package/src/lib/progress-hook/progress-hook.js.map +1 -1
- package/src/lib/progress-hook/progress-hook.types.d.ts +9 -0
- package/src/lib/progress-hook/progress-hook.types.js +12 -0
- package/src/lib/progress-hook/progress-hook.types.js.map +1 -1
- package/src/lib/push-chain/push-chain.d.ts +17 -0
- package/src/lib/push-chain/push-chain.js +190 -0
- package/src/lib/push-chain/push-chain.js.map +1 -1
- package/src/lib/push-client/push-client.d.ts +5 -0
- package/src/lib/push-client/push-client.js +15 -0
- package/src/lib/push-client/push-client.js.map +1 -1
- package/src/lib/utils.d.ts +98 -2
- package/src/lib/utils.js +264 -8
- package/src/lib/utils.js.map +1 -1
|
@@ -18,6 +18,7 @@ const anchor_1 = require("@coral-xyz/anchor");
|
|
|
18
18
|
const progress_hook_types_1 = require("../progress-hook/progress-hook.types");
|
|
19
19
|
const progress_hook_1 = tslib_1.__importDefault(require("../progress-hook/progress-hook"));
|
|
20
20
|
const uea_evm_1 = require("../constants/abi/uea.evm");
|
|
21
|
+
const tokens_1 = require("../constants/tokens");
|
|
21
22
|
class Orchestrator {
|
|
22
23
|
constructor(universalSigner, pushNetwork, rpcUrls = {}, printTraces = false, progressHook) {
|
|
23
24
|
this.universalSigner = universalSigner;
|
|
@@ -62,7 +63,555 @@ class Orchestrator {
|
|
|
62
63
|
*/
|
|
63
64
|
execute(execute) {
|
|
64
65
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
var _a, _b, _c;
|
|
65
67
|
try {
|
|
68
|
+
// FUNDS_TX short-circuit: Bridge tokens from origin chain to Push Chain
|
|
69
|
+
// - EVM (Sepolia): UniversalGatewayV0
|
|
70
|
+
// - SVM (Solana Devnet): pushsolanagateway
|
|
71
|
+
if (execute.funds) {
|
|
72
|
+
if (!execute.data || execute.data === '0x') {
|
|
73
|
+
// Disallow user-provided `value` for funds-only bridging. The SDK derives
|
|
74
|
+
// origin-chain msg.value automatically from the funds input:
|
|
75
|
+
// - Native path: msg.value = bridgeAmount
|
|
76
|
+
// - ERC-20 path: msg.value = 0
|
|
77
|
+
if (execute.value !== undefined && execute.value !== BigInt(0)) {
|
|
78
|
+
throw new Error('Do not set `value` when using funds bridging; the SDK sets origin msg.value from `funds.amount` automatically');
|
|
79
|
+
}
|
|
80
|
+
const chain = this.universalSigner.account.chain;
|
|
81
|
+
const { vm } = chain_1.CHAIN_INFO[chain];
|
|
82
|
+
if (!(chain === enums_1.CHAIN.ETHEREUM_SEPOLIA)) {
|
|
83
|
+
throw new Error('Funds bridging is only supported on Ethereum Sepolia for now');
|
|
84
|
+
}
|
|
85
|
+
// Progress: Origin chain detected
|
|
86
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_01, chain);
|
|
87
|
+
const { defaultRPC, lockerContract } = chain_1.CHAIN_INFO[chain];
|
|
88
|
+
const rpcUrls = this.rpcUrls[chain] || defaultRPC;
|
|
89
|
+
// Resolve token: default to native token based on VM (ETH for EVM, SOL for SVM)
|
|
90
|
+
if (!execute.funds.token) {
|
|
91
|
+
const available = tokens_1.MOVEABLE_TOKENS[chain] || [];
|
|
92
|
+
const vm = chain_1.CHAIN_INFO[chain].vm;
|
|
93
|
+
const preferredSymbol = vm === enums_1.VM.EVM ? 'ETH' : vm === enums_1.VM.SVM ? 'SOL' : undefined;
|
|
94
|
+
const nativeToken = preferredSymbol
|
|
95
|
+
? available.find((t) => t.symbol === preferredSymbol)
|
|
96
|
+
: undefined;
|
|
97
|
+
if (!nativeToken) {
|
|
98
|
+
throw new Error('Native token not configured for this chain');
|
|
99
|
+
}
|
|
100
|
+
execute.funds.token = nativeToken;
|
|
101
|
+
}
|
|
102
|
+
const amount = execute.funds.amount;
|
|
103
|
+
const symbol = execute.funds.token.symbol;
|
|
104
|
+
// Funds Flow: Preparing funds transfer
|
|
105
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_01, amount, execute.funds.token.decimals, symbol);
|
|
106
|
+
if (vm === enums_1.VM.EVM) {
|
|
107
|
+
const evmClient = new evm_client_1.EvmClient({ rpcUrls });
|
|
108
|
+
const gatewayAddress = lockerContract;
|
|
109
|
+
const tokenAddr = execute.funds.token.address;
|
|
110
|
+
// Approve gateway to pull tokens if ERC-20 (not native sentinel)
|
|
111
|
+
if (execute.funds.token.mechanism === 'approve') {
|
|
112
|
+
yield this.ensureErc20Allowance(evmClient, tokenAddr, gatewayAddress, amount);
|
|
113
|
+
}
|
|
114
|
+
else if (execute.funds.token.mechanism === 'permit2') {
|
|
115
|
+
throw new Error('Permit2 is not supported yet');
|
|
116
|
+
}
|
|
117
|
+
else if (execute.funds.token.mechanism === 'native') {
|
|
118
|
+
// Native flow uses msg.value == bridgeAmount and bridgeToken = address(0)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const bridgeAmount = amount;
|
|
122
|
+
const revertCFG = {
|
|
123
|
+
fundRecipient: this.universalSigner.account
|
|
124
|
+
.address,
|
|
125
|
+
revertMsg: '0x',
|
|
126
|
+
}; // typed by viem via ABI
|
|
127
|
+
if (vm === enums_1.VM.EVM) {
|
|
128
|
+
const evmClient = new evm_client_1.EvmClient({ rpcUrls });
|
|
129
|
+
const gatewayAddress = lockerContract;
|
|
130
|
+
const tokenAddr = execute.funds.token.address;
|
|
131
|
+
// Call UniversalGatewayV0.sendFunds(recipient, bridgeToken, bridgeAmount, revertCFG)
|
|
132
|
+
const recipient = execute.to; // funds to recipient on Push Chain
|
|
133
|
+
const isNative = execute.funds.token.mechanism === 'native';
|
|
134
|
+
const bridgeToken = execute.funds.token.mechanism === 'approve'
|
|
135
|
+
? tokenAddr
|
|
136
|
+
: '0x0000000000000000000000000000000000000000';
|
|
137
|
+
let txHash;
|
|
138
|
+
try {
|
|
139
|
+
txHash = yield evmClient.writeContract({
|
|
140
|
+
abi: abi_1.UNIVERSAL_GATEWAY_V0,
|
|
141
|
+
address: gatewayAddress,
|
|
142
|
+
functionName: 'sendFunds',
|
|
143
|
+
args: [recipient, bridgeToken, bridgeAmount, revertCFG],
|
|
144
|
+
signer: this.universalSigner,
|
|
145
|
+
value: isNative ? bridgeAmount : BigInt(0),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_04);
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
|
|
153
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol);
|
|
154
|
+
yield this.waitForEvmConfirmationsWithCountdown(evmClient, txHash, 14, 210000);
|
|
155
|
+
// After origin confirmations, query Push Chain for UniversalTx status
|
|
156
|
+
try {
|
|
157
|
+
const receipt = yield evmClient.publicClient.getTransactionReceipt({
|
|
158
|
+
hash: txHash,
|
|
159
|
+
});
|
|
160
|
+
const gatewayLogs = (receipt.logs || []).filter((l) => (l.address || '').toLowerCase() ===
|
|
161
|
+
gatewayAddress.toLowerCase());
|
|
162
|
+
const firstLog = (gatewayLogs[0] || ((_a = receipt.logs) === null || _a === void 0 ? void 0 : _a[0]));
|
|
163
|
+
const logIndexVal = (_b = firstLog === null || firstLog === void 0 ? void 0 : firstLog.logIndex) !== null && _b !== void 0 ? _b : 0;
|
|
164
|
+
const logIndexStr = typeof logIndexVal === 'bigint'
|
|
165
|
+
? logIndexVal.toString()
|
|
166
|
+
: String(logIndexVal);
|
|
167
|
+
const sourceChain = `${chain_1.VM_NAMESPACE[vm]}:${chain_1.CHAIN_INFO[this.universalSigner.account.chain].chainId}`;
|
|
168
|
+
// ID = sha256("${sourceChain}:${txHash}:${logIndex}") as hex string (no 0x)
|
|
169
|
+
const idInput = `${sourceChain}:${txHash}:${logIndexStr}`;
|
|
170
|
+
const idHex = (0, viem_1.sha256)((0, viem_1.stringToBytes)(idInput)).slice(2);
|
|
171
|
+
// Fetch UniversalTx via gRPC with a brief retry window
|
|
172
|
+
let universalTxObj;
|
|
173
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
174
|
+
try {
|
|
175
|
+
const universalTxResp = yield this.pushClient.getUniversalTxById(idHex);
|
|
176
|
+
universalTxObj = universalTxResp === null || universalTxResp === void 0 ? void 0 : universalTxResp.universalTx;
|
|
177
|
+
if (universalTxObj)
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
catch (_d) {
|
|
181
|
+
// ignore and retry
|
|
182
|
+
}
|
|
183
|
+
yield new Promise((r) => setTimeout(r, 1500));
|
|
184
|
+
}
|
|
185
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06, (universalTxObj === null || universalTxObj === void 0 ? void 0 : universalTxObj.universalStatus) ||
|
|
186
|
+
(universalTxObj === null || universalTxObj === void 0 ? void 0 : universalTxObj.universal_status));
|
|
187
|
+
}
|
|
188
|
+
catch (_e) {
|
|
189
|
+
// Best-effort; do not fail flow if PC query is unavailable
|
|
190
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
|
|
191
|
+
}
|
|
192
|
+
const tx = yield evmClient.getTransaction(txHash);
|
|
193
|
+
return yield this.transformToUniversalTxResponse(tx);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// SVM path (Solana Devnet)
|
|
197
|
+
const svmClient = new svm_client_1.SvmClient({ rpcUrls });
|
|
198
|
+
const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.metadata.address);
|
|
199
|
+
const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
|
|
200
|
+
const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
|
|
201
|
+
const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
|
|
202
|
+
let txSignature;
|
|
203
|
+
// SVM-specific RevertSettings: bytes must be a Buffer
|
|
204
|
+
const revertSvm = {
|
|
205
|
+
fundRecipient: userPk,
|
|
206
|
+
revertMsg: Buffer.alloc(0),
|
|
207
|
+
};
|
|
208
|
+
if (execute.funds.token.mechanism === 'native') {
|
|
209
|
+
// Native SOL funds-only
|
|
210
|
+
const recipientPk = userPk; // must be non-default per program checks
|
|
211
|
+
console.log('recipientPk', recipientPk);
|
|
212
|
+
console.log('bridgeAmount', bridgeAmount);
|
|
213
|
+
console.log('userPk', userPk);
|
|
214
|
+
console.log('configPda', configPda);
|
|
215
|
+
console.log('vaultPda', vaultPda);
|
|
216
|
+
console.log('systemProgram', web3_js_1.SystemProgram.programId);
|
|
217
|
+
console.log('programId', programId.toBase58());
|
|
218
|
+
console.log('SVM_GATEWAY_IDL', abi_1.SVM_GATEWAY_IDL);
|
|
219
|
+
console.log('sendFundsNative', 'sendFundsNative');
|
|
220
|
+
console.log('args', [
|
|
221
|
+
recipientPk,
|
|
222
|
+
bridgeAmount,
|
|
223
|
+
{ fundRecipient: userPk, revertMsg: new Uint8Array([]) },
|
|
224
|
+
]);
|
|
225
|
+
console.log('signer', this.universalSigner);
|
|
226
|
+
console.log('accounts', {
|
|
227
|
+
config: configPda,
|
|
228
|
+
vault: vaultPda,
|
|
229
|
+
user: userPk,
|
|
230
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
231
|
+
});
|
|
232
|
+
txSignature = yield svmClient.writeContract({
|
|
233
|
+
abi: abi_1.SVM_GATEWAY_IDL,
|
|
234
|
+
address: programId.toBase58(),
|
|
235
|
+
functionName: 'sendFundsNative',
|
|
236
|
+
args: [recipientPk, bridgeAmount, revertSvm],
|
|
237
|
+
signer: this.universalSigner,
|
|
238
|
+
accounts: {
|
|
239
|
+
config: configPda,
|
|
240
|
+
vault: vaultPda,
|
|
241
|
+
user: userPk,
|
|
242
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
else if (execute.funds.token.mechanism === 'approve') {
|
|
247
|
+
// SPL token funds-only (requires pre-existing ATAs)
|
|
248
|
+
const mintPk = new web3_js_1.PublicKey(execute.funds.token.address);
|
|
249
|
+
const [whitelistPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
|
|
250
|
+
// Associated Token Accounts
|
|
251
|
+
const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
|
|
252
|
+
const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
|
|
253
|
+
const userAta = web3_js_1.PublicKey.findProgramAddressSync([
|
|
254
|
+
userPk.toBuffer(),
|
|
255
|
+
TOKEN_PROGRAM_ID.toBuffer(),
|
|
256
|
+
mintPk.toBuffer(),
|
|
257
|
+
], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
|
|
258
|
+
const vaultAta = web3_js_1.PublicKey.findProgramAddressSync([
|
|
259
|
+
vaultPda.toBuffer(),
|
|
260
|
+
TOKEN_PROGRAM_ID.toBuffer(),
|
|
261
|
+
mintPk.toBuffer(),
|
|
262
|
+
], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
|
|
263
|
+
const recipientPk = userPk; // must be non-default per program checks
|
|
264
|
+
txSignature = yield svmClient.writeContract({
|
|
265
|
+
abi: abi_1.SVM_GATEWAY_IDL,
|
|
266
|
+
address: programId.toBase58(),
|
|
267
|
+
functionName: 'sendFunds',
|
|
268
|
+
args: [recipientPk, mintPk, bridgeAmount, revertSvm],
|
|
269
|
+
signer: this.universalSigner,
|
|
270
|
+
accounts: {
|
|
271
|
+
config: configPda,
|
|
272
|
+
vault: vaultPda,
|
|
273
|
+
tokenWhitelist: whitelistPda,
|
|
274
|
+
userTokenAccount: userAta,
|
|
275
|
+
gatewayTokenAccount: vaultAta,
|
|
276
|
+
user: userPk,
|
|
277
|
+
bridgeToken: mintPk,
|
|
278
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
279
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
throw new Error('Unsupported token mechanism on Solana');
|
|
285
|
+
}
|
|
286
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
|
|
287
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txSignature, bridgeAmount, execute.funds.token.decimals, symbol);
|
|
288
|
+
yield svmClient.waitForConfirmations({
|
|
289
|
+
txSignature,
|
|
290
|
+
confirmations: chain_1.CHAIN_INFO[chain].confirmations,
|
|
291
|
+
timeoutMs: chain_1.CHAIN_INFO[chain].timeout,
|
|
292
|
+
});
|
|
293
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
|
|
294
|
+
// Build a minimal UniversalTxResponse for SVM origin
|
|
295
|
+
const chainId = chain_1.CHAIN_INFO[chain].chainId;
|
|
296
|
+
const origin = `${chain_1.VM_NAMESPACE[vm]}:${chainId}:${this.universalSigner.account.address}`;
|
|
297
|
+
const universalTxResponse = {
|
|
298
|
+
hash: txSignature,
|
|
299
|
+
origin,
|
|
300
|
+
blockNumber: BigInt(0),
|
|
301
|
+
blockHash: '',
|
|
302
|
+
transactionIndex: 0,
|
|
303
|
+
chainId,
|
|
304
|
+
from: this.universalSigner.account.address,
|
|
305
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
306
|
+
nonce: 0,
|
|
307
|
+
data: '0x',
|
|
308
|
+
value: BigInt(0),
|
|
309
|
+
gasLimit: BigInt(0),
|
|
310
|
+
gasPrice: undefined,
|
|
311
|
+
maxFeePerGas: undefined,
|
|
312
|
+
maxPriorityFeePerGas: undefined,
|
|
313
|
+
accessList: [],
|
|
314
|
+
wait: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
315
|
+
return ({
|
|
316
|
+
hash: txSignature,
|
|
317
|
+
blockNumber: BigInt(0),
|
|
318
|
+
blockHash: '',
|
|
319
|
+
transactionIndex: 0,
|
|
320
|
+
from: this.universalSigner.account.address,
|
|
321
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
322
|
+
contractAddress: null,
|
|
323
|
+
gasPrice: BigInt(0),
|
|
324
|
+
gasUsed: BigInt(0),
|
|
325
|
+
cumulativeGasUsed: BigInt(0),
|
|
326
|
+
logs: [],
|
|
327
|
+
logsBloom: '0x',
|
|
328
|
+
status: 1,
|
|
329
|
+
raw: {
|
|
330
|
+
from: this.universalSigner.account.address,
|
|
331
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
}),
|
|
335
|
+
type: '99',
|
|
336
|
+
typeVerbose: 'universal',
|
|
337
|
+
signature: { r: '0x0', s: '0x0', v: 0 },
|
|
338
|
+
raw: {
|
|
339
|
+
from: this.universalSigner.account.address,
|
|
340
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
341
|
+
nonce: 0,
|
|
342
|
+
data: '0x',
|
|
343
|
+
value: BigInt(0),
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
return universalTxResponse;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
// Bridge funds + execute payload. Support:
|
|
351
|
+
// - EVM (Sepolia): ERC-20 approve path + native gas via msg.value
|
|
352
|
+
// - SVM (Solana Devnet): SPL or native SOL with gas_amount
|
|
353
|
+
const { chain, evmClient, gatewayAddress } = this.ensureSepoliaGateway();
|
|
354
|
+
// Default token to native ETH if none provided
|
|
355
|
+
if (!execute.funds.token) {
|
|
356
|
+
const available = tokens_1.MOVEABLE_TOKENS[chain] || [];
|
|
357
|
+
const vm = chain_1.CHAIN_INFO[chain].vm;
|
|
358
|
+
const preferredSymbol = vm === enums_1.VM.EVM ? 'ETH' : vm === enums_1.VM.SVM ? 'SOL' : undefined;
|
|
359
|
+
const nativeToken = preferredSymbol
|
|
360
|
+
? available.find((t) => t.symbol === preferredSymbol)
|
|
361
|
+
: undefined;
|
|
362
|
+
if (!nativeToken) {
|
|
363
|
+
throw new Error('Native token not configured for this chain');
|
|
364
|
+
}
|
|
365
|
+
execute.funds.token = nativeToken;
|
|
366
|
+
}
|
|
367
|
+
const mechanism = execute.funds.token.mechanism;
|
|
368
|
+
const { deployed, nonce } = yield this.getUeaStatusAndNonce();
|
|
369
|
+
const { payload: universalPayload } = yield this.buildGatewayPayloadAndGas(execute, nonce);
|
|
370
|
+
// Compute required gas funding on Push Chain and current UEA balance
|
|
371
|
+
const gasEstimate = execute.gasLimit || BigInt(1e7);
|
|
372
|
+
const gasPrice = yield this.pushClient.getGasPrice();
|
|
373
|
+
const requiredGasFee = gasEstimate * gasPrice;
|
|
374
|
+
const payloadValue = (_c = execute.value) !== null && _c !== void 0 ? _c : BigInt(0);
|
|
375
|
+
const requiredFunds = requiredGasFee + payloadValue;
|
|
376
|
+
const ueaAddress = this.computeUEAOffchain();
|
|
377
|
+
const [ueaBalance] = yield Promise.all([
|
|
378
|
+
this.pushClient.getBalance(ueaAddress),
|
|
379
|
+
]);
|
|
380
|
+
// Determine USD to deposit via gateway (8 decimals) with caps: min=$1, max=$10
|
|
381
|
+
const oneUsd = push_chain_1.PushChain.utils.helpers.parseUnits('1', 8);
|
|
382
|
+
const tenUsd = push_chain_1.PushChain.utils.helpers.parseUnits('10', 8);
|
|
383
|
+
const deficit = requiredFunds > ueaBalance ? requiredFunds - ueaBalance : BigInt(0);
|
|
384
|
+
let depositUsd = deficit > BigInt(0) ? this.pushClient.pushToUSDC(deficit) : oneUsd;
|
|
385
|
+
if (depositUsd < oneUsd)
|
|
386
|
+
depositUsd = oneUsd;
|
|
387
|
+
if (depositUsd > tenUsd)
|
|
388
|
+
throw new Error('Deposit value exceeds max $10 worth of native token');
|
|
389
|
+
// Convert USD(8) -> native wei using the same pricing path as fee locking
|
|
390
|
+
const nativeTokenUsdPrice = yield new price_fetch_1.PriceFetch(this.rpcUrls).getPrice(chain); // 8 decimals
|
|
391
|
+
const oneEthWei = push_chain_1.PushChain.utils.helpers.parseUnits('1', 18);
|
|
392
|
+
const nativeAmount = (depositUsd * oneEthWei) / nativeTokenUsdPrice;
|
|
393
|
+
const revertCFG = {
|
|
394
|
+
fundRecipient: this.universalSigner.account
|
|
395
|
+
.address,
|
|
396
|
+
revertMsg: '0x',
|
|
397
|
+
};
|
|
398
|
+
const bridgeAmount = execute.funds.amount;
|
|
399
|
+
const symbol = execute.funds.token.symbol;
|
|
400
|
+
// Funds Flow: Preparing funds transfer
|
|
401
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_01, bridgeAmount, execute.funds.token.decimals, symbol);
|
|
402
|
+
if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
|
|
403
|
+
const tokenAddr = execute.funds.token.address;
|
|
404
|
+
if (mechanism !== 'approve') {
|
|
405
|
+
throw new Error('Only ERC-20 tokens are supported for funds+payload on EVM; native and permit2 are not supported yet');
|
|
406
|
+
}
|
|
407
|
+
yield this.ensureErc20Allowance(evmClient, tokenAddr, gatewayAddress, bridgeAmount);
|
|
408
|
+
}
|
|
409
|
+
let txHash;
|
|
410
|
+
try {
|
|
411
|
+
if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
|
|
412
|
+
const tokenAddr = execute.funds.token.address;
|
|
413
|
+
// Compute EIP-712 signature for the universal payload and hash to bytes32
|
|
414
|
+
const ueaAddress = this.computeUEAOffchain();
|
|
415
|
+
const eip712Signature = yield this.signUniversalPayload(universalPayload,
|
|
416
|
+
// execute.to
|
|
417
|
+
ueaAddress);
|
|
418
|
+
const eip712SignatureHex = typeof eip712Signature === 'string'
|
|
419
|
+
? eip712Signature
|
|
420
|
+
: (0, viem_1.bytesToHex)(eip712Signature);
|
|
421
|
+
const signatureData = (0, viem_1.keccak256)(eip712SignatureHex);
|
|
422
|
+
txHash = yield evmClient.writeContract({
|
|
423
|
+
abi: abi_1.UNIVERSAL_GATEWAY_V0,
|
|
424
|
+
address: gatewayAddress,
|
|
425
|
+
functionName: 'sendTxWithFunds',
|
|
426
|
+
args: [
|
|
427
|
+
tokenAddr,
|
|
428
|
+
bridgeAmount,
|
|
429
|
+
universalPayload,
|
|
430
|
+
revertCFG,
|
|
431
|
+
signatureData,
|
|
432
|
+
],
|
|
433
|
+
signer: this.universalSigner,
|
|
434
|
+
value: nativeAmount,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
// SVM funds+payload path
|
|
439
|
+
const svmClient = new svm_client_1.SvmClient({
|
|
440
|
+
rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
|
|
441
|
+
chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
|
|
442
|
+
});
|
|
443
|
+
const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.metadata.address);
|
|
444
|
+
const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
|
|
445
|
+
const [vaultPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('vault')], programId);
|
|
446
|
+
const [whitelistPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('whitelist')], programId);
|
|
447
|
+
const userPk = new web3_js_1.PublicKey(this.universalSigner.account.address);
|
|
448
|
+
const priceUpdatePk = new web3_js_1.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
|
|
449
|
+
const isNative = mechanism === 'native' || execute.funds.token.symbol === 'SOL';
|
|
450
|
+
const revertSvm2 = {
|
|
451
|
+
fundRecipient: userPk,
|
|
452
|
+
revertMsg: Buffer.alloc(0),
|
|
453
|
+
};
|
|
454
|
+
if (isNative) {
|
|
455
|
+
// Native SOL as bridge + gas
|
|
456
|
+
txHash = yield svmClient.writeContract({
|
|
457
|
+
abi: abi_1.SVM_GATEWAY_IDL,
|
|
458
|
+
address: programId.toBase58(),
|
|
459
|
+
functionName: 'sendTxWithFunds',
|
|
460
|
+
args: [
|
|
461
|
+
web3_js_1.PublicKey.default, // bridge_token = default for native SOL
|
|
462
|
+
bridgeAmount,
|
|
463
|
+
universalPayload,
|
|
464
|
+
revertSvm2,
|
|
465
|
+
nativeAmount,
|
|
466
|
+
Buffer.alloc(32),
|
|
467
|
+
],
|
|
468
|
+
signer: this.universalSigner,
|
|
469
|
+
accounts: {
|
|
470
|
+
config: configPda,
|
|
471
|
+
vault: vaultPda,
|
|
472
|
+
tokenWhitelist: whitelistPda,
|
|
473
|
+
userTokenAccount: web3_js_1.PublicKey.default, // not used for native
|
|
474
|
+
gatewayTokenAccount: web3_js_1.PublicKey.default, // not used for native
|
|
475
|
+
user: userPk,
|
|
476
|
+
priceUpdate: priceUpdatePk,
|
|
477
|
+
bridgeToken: web3_js_1.PublicKey.default,
|
|
478
|
+
tokenProgram: new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
|
|
479
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
// SPL token as bridge + native SOL lamports as gas_amount
|
|
485
|
+
const mintPk = new web3_js_1.PublicKey(execute.funds.token.address);
|
|
486
|
+
const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
|
|
487
|
+
const ASSOCIATED_TOKEN_PROGRAM_ID = new web3_js_1.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
|
|
488
|
+
const userAta = web3_js_1.PublicKey.findProgramAddressSync([
|
|
489
|
+
userPk.toBuffer(),
|
|
490
|
+
TOKEN_PROGRAM_ID.toBuffer(),
|
|
491
|
+
mintPk.toBuffer(),
|
|
492
|
+
], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
|
|
493
|
+
const vaultAta = web3_js_1.PublicKey.findProgramAddressSync([
|
|
494
|
+
vaultPda.toBuffer(),
|
|
495
|
+
TOKEN_PROGRAM_ID.toBuffer(),
|
|
496
|
+
mintPk.toBuffer(),
|
|
497
|
+
], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
|
|
498
|
+
txHash = yield svmClient.writeContract({
|
|
499
|
+
abi: abi_1.SVM_GATEWAY_IDL,
|
|
500
|
+
address: programId.toBase58(),
|
|
501
|
+
functionName: 'sendTxWithFunds',
|
|
502
|
+
args: [
|
|
503
|
+
mintPk,
|
|
504
|
+
bridgeAmount,
|
|
505
|
+
universalPayload,
|
|
506
|
+
revertSvm2,
|
|
507
|
+
nativeAmount,
|
|
508
|
+
Buffer.alloc(32),
|
|
509
|
+
],
|
|
510
|
+
signer: this.universalSigner,
|
|
511
|
+
accounts: {
|
|
512
|
+
config: configPda,
|
|
513
|
+
vault: vaultPda,
|
|
514
|
+
tokenWhitelist: whitelistPda,
|
|
515
|
+
userTokenAccount: userAta,
|
|
516
|
+
gatewayTokenAccount: vaultAta,
|
|
517
|
+
user: userPk,
|
|
518
|
+
priceUpdate: priceUpdatePk,
|
|
519
|
+
bridgeToken: mintPk,
|
|
520
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
521
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
522
|
+
},
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
catch (err) {
|
|
528
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_04);
|
|
529
|
+
throw err;
|
|
530
|
+
}
|
|
531
|
+
// Payload Flow: Verification Success
|
|
532
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_04_03);
|
|
533
|
+
// Funds Flow: Funds lock submitted
|
|
534
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_02, txHash, bridgeAmount, execute.funds.token.decimals, symbol);
|
|
535
|
+
// Awaiting confirmations
|
|
536
|
+
if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
|
|
537
|
+
yield this.waitForEvmConfirmationsWithCountdown(evmClient, txHash, 14, 300000);
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
const svmClient = new svm_client_1.SvmClient({
|
|
541
|
+
rpcUrls: this.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
|
|
542
|
+
chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
|
|
543
|
+
});
|
|
544
|
+
yield svmClient.waitForConfirmations({
|
|
545
|
+
txSignature: txHash,
|
|
546
|
+
confirmations: chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].confirmations,
|
|
547
|
+
timeoutMs: chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].timeout,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
// Funds Flow: Confirmed on origin
|
|
551
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_06);
|
|
552
|
+
// If UEA is not deployed yet, deploy it now using the gateway tx hash
|
|
553
|
+
yield this.sendUniversalTx(deployed, txHash);
|
|
554
|
+
if (chain_1.CHAIN_INFO[this.universalSigner.account.chain].vm === enums_1.VM.EVM) {
|
|
555
|
+
const evmTx = yield evmClient.getTransaction(txHash);
|
|
556
|
+
return yield this.transformToUniversalTxResponse(evmTx);
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
const chainId = chain_1.CHAIN_INFO[chain].chainId;
|
|
560
|
+
const vm = chain_1.CHAIN_INFO[chain].vm;
|
|
561
|
+
const origin = `${chain_1.VM_NAMESPACE[vm]}:${chainId}:${this.universalSigner.account.address}`;
|
|
562
|
+
const universalTxResponse = {
|
|
563
|
+
hash: txHash,
|
|
564
|
+
origin,
|
|
565
|
+
blockNumber: BigInt(0),
|
|
566
|
+
blockHash: '',
|
|
567
|
+
transactionIndex: 0,
|
|
568
|
+
chainId,
|
|
569
|
+
from: this.universalSigner.account.address,
|
|
570
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
571
|
+
nonce: 0,
|
|
572
|
+
data: '0x',
|
|
573
|
+
value: BigInt(0),
|
|
574
|
+
gasLimit: BigInt(0),
|
|
575
|
+
gasPrice: undefined,
|
|
576
|
+
maxFeePerGas: undefined,
|
|
577
|
+
maxPriorityFeePerGas: undefined,
|
|
578
|
+
accessList: [],
|
|
579
|
+
wait: () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
580
|
+
return ({
|
|
581
|
+
hash: txHash,
|
|
582
|
+
blockNumber: BigInt(0),
|
|
583
|
+
blockHash: '',
|
|
584
|
+
transactionIndex: 0,
|
|
585
|
+
from: this.universalSigner.account.address,
|
|
586
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
587
|
+
contractAddress: null,
|
|
588
|
+
gasPrice: BigInt(0),
|
|
589
|
+
gasUsed: BigInt(0),
|
|
590
|
+
cumulativeGasUsed: BigInt(0),
|
|
591
|
+
logs: [],
|
|
592
|
+
logsBloom: '0x',
|
|
593
|
+
status: 1,
|
|
594
|
+
raw: {
|
|
595
|
+
from: this.universalSigner.account.address,
|
|
596
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
}),
|
|
600
|
+
type: '99',
|
|
601
|
+
typeVerbose: 'universal',
|
|
602
|
+
signature: { r: '0x0', s: '0x0', v: 0 },
|
|
603
|
+
raw: {
|
|
604
|
+
from: this.universalSigner.account.address,
|
|
605
|
+
to: '0x0000000000000000000000000000000000000000',
|
|
606
|
+
nonce: 0,
|
|
607
|
+
data: '0x',
|
|
608
|
+
value: BigInt(0),
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
return universalTxResponse;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
66
615
|
// Set default value for value if undefined
|
|
67
616
|
if (execute.value === undefined) {
|
|
68
617
|
execute.value = BigInt(0);
|
|
@@ -224,7 +773,19 @@ class Orchestrator {
|
|
|
224
773
|
return transactions[transactions.length - 1];
|
|
225
774
|
}
|
|
226
775
|
catch (err) {
|
|
227
|
-
|
|
776
|
+
const errMessage = err instanceof Error
|
|
777
|
+
? err.message
|
|
778
|
+
: typeof err === 'string'
|
|
779
|
+
? err
|
|
780
|
+
: (() => {
|
|
781
|
+
try {
|
|
782
|
+
return JSON.stringify(err);
|
|
783
|
+
}
|
|
784
|
+
catch (_a) {
|
|
785
|
+
return 'Unknown error';
|
|
786
|
+
}
|
|
787
|
+
})();
|
|
788
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_02, errMessage);
|
|
228
789
|
throw err;
|
|
229
790
|
}
|
|
230
791
|
});
|
|
@@ -370,6 +931,7 @@ class Orchestrator {
|
|
|
370
931
|
universalAccountId,
|
|
371
932
|
txHash: feeLockTxHash,
|
|
372
933
|
}));
|
|
934
|
+
// TODO: pchaind q uexecutor all-universal-tx --node https://rpc-testnet-donut-node1.push.org/
|
|
373
935
|
}
|
|
374
936
|
if (feeLockTxHash) {
|
|
375
937
|
msgs.push(this.pushClient.createMsgMintPC({
|
|
@@ -640,6 +1202,129 @@ class Orchestrator {
|
|
|
640
1202
|
}
|
|
641
1203
|
});
|
|
642
1204
|
}
|
|
1205
|
+
ensureErc20Allowance(evmClient, tokenAddress, spender, requiredAmount) {
|
|
1206
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1207
|
+
const chain = this.universalSigner.account.chain;
|
|
1208
|
+
const owner = this.universalSigner.account.address;
|
|
1209
|
+
const currentAllowance = yield evmClient.readContract({
|
|
1210
|
+
abi: abi_1.ERC20_EVM,
|
|
1211
|
+
address: tokenAddress,
|
|
1212
|
+
functionName: 'allowance',
|
|
1213
|
+
args: [owner, spender],
|
|
1214
|
+
});
|
|
1215
|
+
if (currentAllowance >= requiredAmount)
|
|
1216
|
+
return;
|
|
1217
|
+
// Some ERC-20s like USDT require setting allowance to 0 before changing
|
|
1218
|
+
// an existing non-zero allowance to a different non-zero value.
|
|
1219
|
+
if (currentAllowance > BigInt(0)) {
|
|
1220
|
+
this.printLog(`Resetting existing allowance from ${currentAllowance.toString()} to 0 for spender ${spender}`);
|
|
1221
|
+
const resetTxHash = yield evmClient.writeContract({
|
|
1222
|
+
abi: abi_1.ERC20_EVM,
|
|
1223
|
+
address: tokenAddress,
|
|
1224
|
+
functionName: 'approve',
|
|
1225
|
+
args: [spender, BigInt(0)],
|
|
1226
|
+
signer: this.universalSigner,
|
|
1227
|
+
});
|
|
1228
|
+
yield evmClient.waitForConfirmations({
|
|
1229
|
+
txHash: resetTxHash,
|
|
1230
|
+
confirmations: 1,
|
|
1231
|
+
timeoutMs: chain_1.CHAIN_INFO[chain].timeout,
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
const setTxHash = yield evmClient.writeContract({
|
|
1235
|
+
abi: abi_1.ERC20_EVM,
|
|
1236
|
+
address: tokenAddress,
|
|
1237
|
+
functionName: 'approve',
|
|
1238
|
+
args: [spender, requiredAmount],
|
|
1239
|
+
signer: this.universalSigner,
|
|
1240
|
+
});
|
|
1241
|
+
yield evmClient.waitForConfirmations({
|
|
1242
|
+
txHash: setTxHash,
|
|
1243
|
+
confirmations: 1,
|
|
1244
|
+
timeoutMs: chain_1.CHAIN_INFO[chain].timeout,
|
|
1245
|
+
});
|
|
1246
|
+
try {
|
|
1247
|
+
const updated = yield evmClient.readContract({
|
|
1248
|
+
abi: abi_1.ERC20_EVM,
|
|
1249
|
+
address: tokenAddress,
|
|
1250
|
+
functionName: 'allowance',
|
|
1251
|
+
args: [owner, spender],
|
|
1252
|
+
});
|
|
1253
|
+
if (updated < requiredAmount) {
|
|
1254
|
+
this.printLog('Warning: allowance not updated yet; proceeding');
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
catch (_a) {
|
|
1258
|
+
// ignore
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Ensures we're on Sepolia, returns EVM client and gateway address.
|
|
1264
|
+
*/
|
|
1265
|
+
ensureSepoliaGateway() {
|
|
1266
|
+
const chain = this.universalSigner.account.chain;
|
|
1267
|
+
if (chain !== enums_1.CHAIN.ETHEREUM_SEPOLIA) {
|
|
1268
|
+
throw new Error('Funds + payload bridging is only supported on Ethereum Sepolia for now');
|
|
1269
|
+
}
|
|
1270
|
+
const { defaultRPC, lockerContract } = chain_1.CHAIN_INFO[chain];
|
|
1271
|
+
const rpcUrls = this.rpcUrls[chain] || defaultRPC;
|
|
1272
|
+
const evmClient = new evm_client_1.EvmClient({ rpcUrls });
|
|
1273
|
+
const gatewayAddress = lockerContract;
|
|
1274
|
+
if (!gatewayAddress) {
|
|
1275
|
+
throw new Error('Universal Gateway address not configured');
|
|
1276
|
+
}
|
|
1277
|
+
return { chain, evmClient, gatewayAddress };
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Computes UEA and fetches its nonce if deployed; returns 0 otherwise.
|
|
1281
|
+
*/
|
|
1282
|
+
getUeaNonceForExecution() {
|
|
1283
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1284
|
+
const UEA = this.computeUEAOffchain();
|
|
1285
|
+
const [code] = yield Promise.all([
|
|
1286
|
+
this.pushClient.publicClient.getCode({ address: UEA }),
|
|
1287
|
+
]);
|
|
1288
|
+
return code !== undefined ? yield this.getUEANonce(UEA) : BigInt(0);
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Returns UEA deployment status and nonce (0 if not deployed).
|
|
1293
|
+
*/
|
|
1294
|
+
getUeaStatusAndNonce() {
|
|
1295
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1296
|
+
const UEA = this.computeUEAOffchain();
|
|
1297
|
+
const [code] = yield Promise.all([
|
|
1298
|
+
this.pushClient.publicClient.getCode({ address: UEA }),
|
|
1299
|
+
]);
|
|
1300
|
+
const deployed = code !== undefined;
|
|
1301
|
+
const nonce = deployed ? yield this.getUEANonce(UEA) : BigInt(0);
|
|
1302
|
+
return { deployed, nonce };
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Builds UniversalPayload for the gateway and computes the native gas deposit.
|
|
1307
|
+
*/
|
|
1308
|
+
buildGatewayPayloadAndGas(execute, nonce) {
|
|
1309
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1310
|
+
var _a, _b;
|
|
1311
|
+
const gasEstimate = execute.gasLimit || BigInt(1e7);
|
|
1312
|
+
const payloadValue = (_a = execute.value) !== null && _a !== void 0 ? _a : BigInt(0);
|
|
1313
|
+
const gasAmount = (_b = execute.value) !== null && _b !== void 0 ? _b : BigInt(0);
|
|
1314
|
+
const universalPayload = {
|
|
1315
|
+
to: execute.to,
|
|
1316
|
+
value: payloadValue,
|
|
1317
|
+
data: execute.data || '0x',
|
|
1318
|
+
gasLimit: gasEstimate,
|
|
1319
|
+
maxFeePerGas: execute.maxFeePerGas || BigInt(1e10),
|
|
1320
|
+
maxPriorityFeePerGas: execute.maxPriorityFeePerGas || BigInt(0),
|
|
1321
|
+
nonce,
|
|
1322
|
+
deadline: execute.deadline || BigInt(9999999999),
|
|
1323
|
+
vType: tx_1.VerificationType.universalTxVerification,
|
|
1324
|
+
};
|
|
1325
|
+
return { payload: universalPayload, gasAmount };
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
643
1328
|
/********************************** HELPER FUNCTIONS **************************************************/
|
|
644
1329
|
/**
|
|
645
1330
|
* Transforms a TransactionReceipt to UniversalTxReceipt format
|
|
@@ -860,6 +1545,32 @@ class Orchestrator {
|
|
|
860
1545
|
// invoke the user-provided callback
|
|
861
1546
|
this.progressHook(hookPayload);
|
|
862
1547
|
}
|
|
1548
|
+
// Emit countdown updates while waiting for EVM confirmations
|
|
1549
|
+
waitForEvmConfirmationsWithCountdown(evmClient, txHash, confirmations, timeoutMs) {
|
|
1550
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1551
|
+
// initial emit
|
|
1552
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03, confirmations);
|
|
1553
|
+
const start = Date.now();
|
|
1554
|
+
// Wait for receipt to get included block
|
|
1555
|
+
const receipt = yield evmClient.publicClient.waitForTransactionReceipt({
|
|
1556
|
+
hash: txHash,
|
|
1557
|
+
});
|
|
1558
|
+
const targetBlock = receipt.blockNumber + BigInt(confirmations);
|
|
1559
|
+
// Poll blocks and emit remaining confirmations
|
|
1560
|
+
// eslint-disable-next-line no-constant-condition
|
|
1561
|
+
while (true) {
|
|
1562
|
+
const currentBlock = yield evmClient.publicClient.getBlockNumber();
|
|
1563
|
+
if (currentBlock >= targetBlock)
|
|
1564
|
+
return;
|
|
1565
|
+
const remaining = Number(targetBlock - currentBlock);
|
|
1566
|
+
this.executeProgressHook(progress_hook_types_1.PROGRESS_HOOK.SEND_TX_06_03, remaining);
|
|
1567
|
+
if (Date.now() - start > timeoutMs) {
|
|
1568
|
+
throw new Error(`Timeout: transaction ${txHash} not confirmed with ${confirmations} confirmations within ${timeoutMs} ms`);
|
|
1569
|
+
}
|
|
1570
|
+
yield new Promise((r) => setTimeout(r, 12000));
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
863
1574
|
}
|
|
864
1575
|
exports.Orchestrator = Orchestrator;
|
|
865
1576
|
//# sourceMappingURL=orchestrator.js.map
|