@pushchain/core 5.1.18 → 6.0.1
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 +1 -1
- package/src/lib/constants/abi/cea.evm.d.ts +52 -0
- package/src/lib/constants/abi/cea.evm.js +66 -1
- package/src/lib/constants/abi/prc20.evm.d.ts +117 -11
- package/src/lib/constants/abi/prc20.evm.js +38 -11
- package/src/lib/constants/abi/uea.evm.js +41 -0
- package/src/lib/constants/abi/universalGatewayPC.evm.d.ts +118 -2
- package/src/lib/constants/abi/universalGatewayPC.evm.js +41 -2
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.d.ts +2 -0
- package/src/lib/constants/chain.js +18 -14
- package/src/lib/constants/index.d.ts +1 -1
- package/src/lib/constants/tokens.d.ts +10 -1
- package/src/lib/constants/tokens.js +5 -2
- package/src/lib/formatters.d.ts +6 -0
- package/src/lib/formatters.js +14 -0
- package/src/lib/index.d.ts +2 -0
- package/src/lib/index.js +7 -1
- package/src/lib/orchestrator/internals/cascade.d.ts +3 -1
- package/src/lib/orchestrator/internals/cascade.js +189 -103
- package/src/lib/orchestrator/internals/errors.js +1 -1
- package/src/lib/orchestrator/internals/execute-funds-only.js +3 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +2 -1
- package/src/lib/orchestrator/internals/execute-standard.js +4 -4
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +1 -0
- package/src/lib/orchestrator/internals/gas-calculator.js +13 -11
- package/src/lib/orchestrator/internals/helpers.js +2 -0
- package/src/lib/orchestrator/internals/inbound-tracker.js +4 -2
- package/src/lib/orchestrator/internals/outbound-sync.js +73 -60
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +1 -1
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +4 -3
- package/src/lib/orchestrator/internals/preflight.d.ts +8 -5
- package/src/lib/orchestrator/internals/preflight.js +35 -21
- package/src/lib/orchestrator/internals/push-chain-tx.js +5 -1
- package/src/lib/orchestrator/internals/route-handlers.js +175 -202
- package/src/lib/orchestrator/internals/signing.js +7 -2
- package/src/lib/orchestrator/internals/svm-helpers.js +3 -3
- package/src/lib/orchestrator/internals/svm-rent.d.ts +42 -9
- package/src/lib/orchestrator/internals/svm-rent.js +157 -14
- package/src/lib/orchestrator/internals/tx-transformer.js +5 -2
- package/src/lib/orchestrator/max-pc-for-gas.d.ts +60 -0
- package/src/lib/orchestrator/max-pc-for-gas.js +66 -0
- package/src/lib/orchestrator/orchestrator.d.ts +6 -6
- package/src/lib/orchestrator/orchestrator.js +10 -3
- package/src/lib/orchestrator/orchestrator.types.d.ts +48 -10
- package/src/lib/orchestrator/payload-builders.d.ts +7 -6
- package/src/lib/orchestrator/payload-builders.js +19 -7
- package/src/lib/progress-hook/progress-hook.js +59 -27
- package/src/lib/progress-hook/progress-hook.types.d.ts +3 -3
- package/src/lib/progress-hook/progress-hook.types.js +4 -2
- package/src/lib/push-chain/push-chain.d.ts +10 -4
- package/src/lib/push-chain/push-chain.js +2 -2
- package/src/lib/universal-tx-detector/events.d.ts +3 -1
- package/src/lib/universal-tx-detector/events.js +3 -1
- package/src/lib/universal-tx-detector/svm-events.d.ts +1 -1
- package/src/lib/universal-tx-detector/svm-events.js +1 -1
- package/src/lib/utils.js +1 -1
|
@@ -112,6 +112,37 @@ function resolveR2Prc20TokenSvm(params, targetChain, pushNetwork, hasSvmExecute)
|
|
|
112
112
|
}
|
|
113
113
|
return { prc20Token, burnAmount };
|
|
114
114
|
}
|
|
115
|
+
function resolveR3SvmDrain(params, sourceChain, pushNetwork) {
|
|
116
|
+
var _a;
|
|
117
|
+
let drainAmount = BigInt(0);
|
|
118
|
+
let tokenMintHex;
|
|
119
|
+
let prc20Token = (0, helpers_1.getNativePRC20ForChain)(sourceChain, pushNetwork);
|
|
120
|
+
if (((_a = params.funds) === null || _a === void 0 ? void 0 : _a.amount) && params.funds.amount > BigInt(0)) {
|
|
121
|
+
drainAmount = params.funds.amount;
|
|
122
|
+
const token = params.funds.token;
|
|
123
|
+
if ((token === null || token === void 0 ? void 0 : token.mechanism) === 'approve') {
|
|
124
|
+
const mintPk = new web3_js_1.PublicKey(token.address);
|
|
125
|
+
tokenMintHex = ('0x' + Buffer.from(mintPk.toBytes()).toString('hex'));
|
|
126
|
+
prc20Token = push_chain_1.PushChain.utils.tokens.getPRC20Address(token).address;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else if (params.value && params.value > BigInt(0)) {
|
|
130
|
+
drainAmount = params.value;
|
|
131
|
+
}
|
|
132
|
+
return { prc20Token, drainAmount, tokenMintHex };
|
|
133
|
+
}
|
|
134
|
+
function buildR3SvmExtraPayload(ctx, params, ueaAddress, sourceChain, inboundNonce) {
|
|
135
|
+
if (!params.data) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
const executeParams = (0, helpers_1.toExecuteParams)(params);
|
|
139
|
+
const multicallCtx = Object.assign(Object.assign({}, ctx), { universalSigner: Object.assign(Object.assign({}, ctx.universalSigner), { account: Object.assign(Object.assign({}, ctx.universalSigner.account), { chain: sourceChain }) }) });
|
|
140
|
+
const multicallPayload = (0, payload_builder_1.buildMulticallPayloadData)(multicallCtx, executeParams.to, (0, payload_builders_1.buildExecuteMulticall)({ execute: executeParams, ueaAddress }));
|
|
141
|
+
const inboundPayload = (0, payload_builders_1.buildInboundUniversalPayload)(multicallPayload, {
|
|
142
|
+
nonce: inboundNonce !== null && inboundNonce !== void 0 ? inboundNonce : BigInt(0),
|
|
143
|
+
});
|
|
144
|
+
return (0, viem_1.hexToBytes)(inboundPayload);
|
|
145
|
+
}
|
|
115
146
|
/**
|
|
116
147
|
* Build the CEA-side multicall payload for a Route 2 EVM outbound. Needs the
|
|
117
148
|
* resolved `ceaAddress` because the native-value self-call branch skips the
|
|
@@ -281,7 +312,7 @@ function executeMultiChain(ctx, params, executeFn) {
|
|
|
281
312
|
*/
|
|
282
313
|
function executeUoaToCea(ctx, params, executeFn) {
|
|
283
314
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
284
|
-
var _a, _b, _c;
|
|
315
|
+
var _a, _b, _c, _d, _e;
|
|
285
316
|
const target = params.to;
|
|
286
317
|
const targetChain = target.chain;
|
|
287
318
|
const targetAddress = target.address;
|
|
@@ -337,6 +368,7 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
337
368
|
// --- 202: Gas estimation (spec-ordered before 203) ---
|
|
338
369
|
let gasFee = BigInt(0);
|
|
339
370
|
let protocolFee = BigInt(0);
|
|
371
|
+
let outboundGasPrice = BigInt(0);
|
|
340
372
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
341
373
|
let universalCoreAddress;
|
|
342
374
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
@@ -345,6 +377,7 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
345
377
|
const result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, gasLimitForQuery, targetChain);
|
|
346
378
|
gasFee = result.gasFee;
|
|
347
379
|
protocolFee = result.protocolFee;
|
|
380
|
+
outboundGasPrice = result.gasPrice;
|
|
348
381
|
gasToken = result.gasToken;
|
|
349
382
|
universalCoreAddress = result.universalCoreAddress;
|
|
350
383
|
(0, context_1.printLog)(ctx, `executeUoaToCea — queried gas fee: ${gasFee.toString()}, gasToken: ${gasToken}`);
|
|
@@ -376,19 +409,20 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
376
409
|
(0, context_1.printLog)(ctx, `executeUoaToCea — MIGRATION: using raw MIGRATION_SELECTOR payload (${ceaPayload}), native PRC-20 ${prc20Token}`);
|
|
377
410
|
}
|
|
378
411
|
// Build outbound request struct for the gateway
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, gasLimitForQuery, ceaPayload, ueaAddress // revert recipient is the UEA
|
|
386
|
-
);
|
|
412
|
+
// Empty CEA payloads intentionally use zero recipient to park funds in the
|
|
413
|
+
// CEA under the post-audit single-call guard.
|
|
414
|
+
const targetBytes = ceaPayload === '0x'
|
|
415
|
+
? selectors_1.ZERO_ADDRESS
|
|
416
|
+
: ceaAddress;
|
|
417
|
+
(0, payload_builders_1.assertCeaFundsParkingInvariant)(targetBytes, ceaPayload);
|
|
418
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, gasLimitForQuery, ceaPayload, ueaAddress, // revert recipient is the UEA
|
|
419
|
+
(_d = params.maxPCForGas) !== null && _d !== void 0 ? _d : BigInt(0), outboundGasPrice);
|
|
387
420
|
(0, context_1.printLog)(ctx, `executeUoaToCea — outbound request: ${JSON.stringify({
|
|
388
|
-
|
|
421
|
+
recipient: outboundReq.recipient,
|
|
389
422
|
token: outboundReq.token,
|
|
390
423
|
amount: outboundReq.amount.toString(),
|
|
391
424
|
gasLimit: outboundReq.gasLimit.toString(),
|
|
425
|
+
maxPCForGas: outboundReq.maxPCForGas.toString(),
|
|
392
426
|
payloadLength: outboundReq.payload.length,
|
|
393
427
|
revertRecipient: outboundReq.revertRecipient,
|
|
394
428
|
}, null, 2)}`);
|
|
@@ -446,10 +480,9 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
446
480
|
(0, context_1.printLog)(ctx, `executeUoaToCea — capping nativeValueForGas at 200 UPC ceiling (was ${nativeValueForGas.toString()})`);
|
|
447
481
|
nativeValueForGas = EVM_NATIVE_VALUE_SAFETY_CAP;
|
|
448
482
|
}
|
|
449
|
-
// Pre-flight:
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
// bubbled up as Uniswap STF reverts. PRC-20 check fires whenever
|
|
483
|
+
// Pre-flight: warns by default when UEA cannot cover (nativeValueForGas +
|
|
484
|
+
// gasReserve) or the PRC-20 burn amount; throws only when
|
|
485
|
+
// options.enforceGasCheck=true. PRC-20 check fires whenever
|
|
453
486
|
// burnAmount > 0 — user must pre-hold the burn token, even when it equals
|
|
454
487
|
// the gas token (the gateway does transferFrom BEFORE the gas swap).
|
|
455
488
|
let prc20BalanceR2Evm;
|
|
@@ -471,6 +504,7 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
471
504
|
burnToken: prc20Token,
|
|
472
505
|
burnAmount,
|
|
473
506
|
prc20Balance: prc20BalanceR2Evm,
|
|
507
|
+
enforceGasCheck: ((_e = params.options) === null || _e === void 0 ? void 0 : _e.enforceGasCheck) === true,
|
|
474
508
|
});
|
|
475
509
|
// Preflight success means nativeValueForGas already covers required + reserve; no adjust needed.
|
|
476
510
|
// Build outbound multicalls (approve burn + sendUniversalTxOutbound with native value)
|
|
@@ -534,7 +568,7 @@ function executeUoaToCea(ctx, params, executeFn) {
|
|
|
534
568
|
*/
|
|
535
569
|
function executeUoaToCeaSvm(ctx, params, target, executeFn) {
|
|
536
570
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
537
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
571
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
538
572
|
const targetChain = target.chain;
|
|
539
573
|
const targetAddress = target.address; // 0x-prefixed, 32 bytes
|
|
540
574
|
const ueaAddress = (0, uea_manager_1.computeUEAOffchain)(ctx);
|
|
@@ -561,44 +595,49 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
|
|
|
561
595
|
// --- 202: Gas estimation (spec-ordered before 203) ---
|
|
562
596
|
let gasFee = BigInt(0);
|
|
563
597
|
let protocolFeeSvm = BigInt(0);
|
|
598
|
+
let outboundGasPriceSvm = BigInt(0);
|
|
564
599
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
565
600
|
let universalCoreAddress;
|
|
566
601
|
// Effective gas limit seeded from the user param. When the user omits
|
|
567
|
-
// gasLimit, it'll be derived from the
|
|
568
|
-
//
|
|
602
|
+
// gasLimit, it'll be derived from the gas quote so the on-chain record
|
|
603
|
+
// carries a non-zero compute budget the relay can use.
|
|
569
604
|
let effectiveGasLimit = (_d = params.gasLimit) !== null && _d !== void 0 ? _d : BigInt(0);
|
|
570
|
-
//
|
|
571
|
-
//
|
|
572
|
-
//
|
|
573
|
-
//
|
|
574
|
-
//
|
|
575
|
-
const
|
|
576
|
-
? (
|
|
605
|
+
// SVM finalize budget: the Solana gateway requires gas_fee to cover the
|
|
606
|
+
// relayer signature fee, ExecutedSubTx rent, a compute buffer, and
|
|
607
|
+
// conditionally CEA ATA rent for SPL outbounds. The on-chain quote can be
|
|
608
|
+
// below that floor, so we compare the quoted fee in lamports and re-query
|
|
609
|
+
// with a bumped gasLimit when required.
|
|
610
|
+
const svmFundsToken = burnAmount > BigInt(0)
|
|
611
|
+
? (_e = params.funds) === null || _e === void 0 ? void 0 : _e.token
|
|
577
612
|
: undefined;
|
|
578
|
-
|
|
579
|
-
ctx,
|
|
580
|
-
ueaAddress,
|
|
581
|
-
targetChain,
|
|
582
|
-
splMintBase58,
|
|
583
|
-
burnAmount,
|
|
584
|
-
effectiveGasLimit,
|
|
585
|
-
});
|
|
613
|
+
const splMintBase58 = (svmFundsToken === null || svmFundsToken === void 0 ? void 0 : svmFundsToken.mechanism) === 'approve' ? svmFundsToken.address : undefined;
|
|
586
614
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
587
615
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_202_01, targetChain);
|
|
588
616
|
try {
|
|
589
|
-
|
|
617
|
+
let result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, effectiveGasLimit, targetChain);
|
|
618
|
+
result = yield (0, svm_rent_1.ensureSvmFinalizeGasBudgetQuote)({
|
|
619
|
+
ctx,
|
|
620
|
+
ueaAddress,
|
|
621
|
+
targetChain,
|
|
622
|
+
prc20Token,
|
|
623
|
+
quote: result,
|
|
624
|
+
splMintBase58,
|
|
625
|
+
burnAmount,
|
|
626
|
+
pathTag: 'executeUoaToCeaSvm',
|
|
627
|
+
});
|
|
590
628
|
gasFee = result.gasFee;
|
|
591
629
|
protocolFeeSvm = result.protocolFee;
|
|
630
|
+
outboundGasPriceSvm = result.gasPrice;
|
|
592
631
|
gasToken = result.gasToken;
|
|
593
632
|
universalCoreAddress = result.universalCoreAddress;
|
|
594
|
-
// When user omits gasLimit (sent as 0), the contract computes fees using
|
|
595
|
-
// baseGasLimitByChainNamespace. But the relay reads the
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
|
|
599
|
-
if (!params.gasLimit
|
|
600
|
-
effectiveGasLimit
|
|
601
|
-
|
|
633
|
+
// When user omits gasLimit (sent as 0), the contract computes fees using
|
|
634
|
+
// its internal baseGasLimitByChainNamespace. But the relay reads the
|
|
635
|
+
// stored gasLimit from the outbound record. Store the resolved value from
|
|
636
|
+
// UniversalCore so the relayer has a non-zero SVM budget.
|
|
637
|
+
effectiveGasLimit = result.gasLimitUsed;
|
|
638
|
+
if (!params.gasLimit) {
|
|
639
|
+
(0, context_1.printLog)(ctx, `executeUoaToCeaSvm — resolved effectiveGasLimit: ${effectiveGasLimit} ` +
|
|
640
|
+
`(gasFee=${result.gasFee}, gasPrice=${result.gasPrice})`);
|
|
602
641
|
}
|
|
603
642
|
(0, context_1.printLog)(ctx, `executeUoaToCeaSvm — queried gas fee: ${gasFee.toString()}, gasToken: ${gasToken}`);
|
|
604
643
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_202_02, targetChain, protocolFeeSvm, gasFee);
|
|
@@ -614,13 +653,14 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
|
|
|
614
653
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_203_02, ueaAddress, targetAddress, targetChain, true);
|
|
615
654
|
// --- Build outbound request ---
|
|
616
655
|
// targetBytes: for execute = program id (resolver output); for withdraw = to.address
|
|
617
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, effectiveGasLimit, svmPayload, ueaAddress // revert recipient is the UEA
|
|
618
|
-
);
|
|
656
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, effectiveGasLimit, svmPayload, ueaAddress, // revert recipient is the UEA
|
|
657
|
+
(_f = params.maxPCForGas) !== null && _f !== void 0 ? _f : BigInt(0), outboundGasPriceSvm);
|
|
619
658
|
(0, context_1.printLog)(ctx, `executeUoaToCeaSvm — outbound request: ${JSON.stringify({
|
|
620
|
-
|
|
659
|
+
recipient: outboundReq.recipient,
|
|
621
660
|
token: outboundReq.token,
|
|
622
661
|
amount: outboundReq.amount.toString(),
|
|
623
662
|
gasLimit: outboundReq.gasLimit.toString(),
|
|
663
|
+
maxPCForGas: outboundReq.maxPCForGas.toString(),
|
|
624
664
|
payloadLength: (outboundReq.payload.length - 2) / 2,
|
|
625
665
|
revertRecipient: outboundReq.revertRecipient,
|
|
626
666
|
}, null, 2)}`);
|
|
@@ -670,10 +710,9 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
|
|
|
670
710
|
(0, context_1.printLog)(ctx, `executeUoaToCeaSvm — nativeValueForGas=${nativeValueForGas.toString()} (includes 2.2x buffer)`);
|
|
671
711
|
(0, preflight_1.maybeFireSvmWarnThreshold)(ctx, nativeValueForGas, gasToken, 'R2_SVM');
|
|
672
712
|
}
|
|
673
|
-
// Pre-flight:
|
|
674
|
-
//
|
|
675
|
-
//
|
|
676
|
-
// swaps and bubbled up as Uniswap STF reverts.
|
|
713
|
+
// Pre-flight: warns by default when UEA cannot cover (nativeValueForGas +
|
|
714
|
+
// SVM_GAS_RESERVE) or the PRC-20 burn amount; throws only when
|
|
715
|
+
// options.enforceGasCheck=true.
|
|
677
716
|
// PRC-20 burn-balance pre-check fires whenever `burnAmount > 0`, regardless
|
|
678
717
|
// of whether `prc20Token` happens to equal `gasToken`. The gateway's
|
|
679
718
|
// `sendUniversalTxOutbound` does `transferFrom(user, gateway, burnAmount)`
|
|
@@ -699,6 +738,7 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
|
|
|
699
738
|
burnToken: prc20Token,
|
|
700
739
|
burnAmount,
|
|
701
740
|
prc20Balance: prc20BalanceR2Svm,
|
|
741
|
+
enforceGasCheck: ((_j = params.options) === null || _j === void 0 ? void 0 : _j.enforceGasCheck) === true,
|
|
702
742
|
});
|
|
703
743
|
// --- Build Push Chain multicalls (approve + sendUniversalTxOutbound) ---
|
|
704
744
|
// Reuse the same builder as EVM — this part is identical
|
|
@@ -764,7 +804,7 @@ function executeUoaToCeaSvm(ctx, params, target, executeFn) {
|
|
|
764
804
|
*/
|
|
765
805
|
function executeCeaToPush(ctx, params, executeFn) {
|
|
766
806
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
767
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
807
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
768
808
|
// 1. Validate and extract source chain
|
|
769
809
|
if (!((_a = params.from) === null || _a === void 0 ? void 0 : _a.chain)) {
|
|
770
810
|
throw new Error('Route 3 (CEA -> Push) requires from.chain to specify the source CEA chain');
|
|
@@ -801,11 +841,6 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
801
841
|
(0, context_1.printLog)(ctx, `executeCeaToPush — sourceChain: ${sourceChain}, CEA: ${ceaAddress}, deployed: ${ceaDeployed}`);
|
|
802
842
|
// CEA auto-deploys on-chain: Vault.finalizeUniversalTx calls CEAFactory.deployCEA()
|
|
803
843
|
// if CEA doesn't exist yet. No SDK-side blocking needed.
|
|
804
|
-
// 5. Get UniversalGateway address on source chain
|
|
805
|
-
const gatewayAddress = chain_1.UNIVERSAL_GATEWAY_ADDRESSES[sourceChain];
|
|
806
|
-
if (!gatewayAddress) {
|
|
807
|
-
throw new Error(`No UniversalGateway address configured for chain ${sourceChain}`);
|
|
808
|
-
}
|
|
809
844
|
// 6. Build multicall for CEA to execute on source chain (self-calls via sendUniversalTxToUEA)
|
|
810
845
|
const ceaMulticalls = [];
|
|
811
846
|
// Determine token and amount for sendUniversalTxToUEA
|
|
@@ -821,7 +856,7 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
821
856
|
amount = params.funds.amount;
|
|
822
857
|
}
|
|
823
858
|
else {
|
|
824
|
-
// ERC20 token
|
|
859
|
+
// ERC20 token. CEA handles gateway approval internally around sendUniversalTxToUEA.
|
|
825
860
|
tokenAddress = token.address;
|
|
826
861
|
amount = params.funds.amount;
|
|
827
862
|
}
|
|
@@ -838,33 +873,7 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
838
873
|
// query and relay execution, causing sendUniversalTxToUEA to revert with
|
|
839
874
|
// InsufficientBalance. Pre-existing CEA funds remain parked and can be swept separately.
|
|
840
875
|
const bridgeAmount = amount;
|
|
841
|
-
//
|
|
842
|
-
// Keeping bridgeAmount as-is (0) for payload-only to test precompile behavior.
|
|
843
|
-
// For ERC20 tokens, add approve call for the bridge amount
|
|
844
|
-
// (CEA approves gateway to spend the Vault-deposited amount)
|
|
845
|
-
// Reset to 0 first for USDT-style tokens that revert on non-zero to non-zero approve.
|
|
846
|
-
if (tokenAddress !== selectors_1.ZERO_ADDRESS && bridgeAmount > BigInt(0)) {
|
|
847
|
-
const approveZeroData = (0, viem_1.encodeFunctionData)({
|
|
848
|
-
abi: erc20_evm_1.ERC20_EVM,
|
|
849
|
-
functionName: 'approve',
|
|
850
|
-
args: [gatewayAddress, BigInt(0)],
|
|
851
|
-
});
|
|
852
|
-
ceaMulticalls.push({
|
|
853
|
-
to: tokenAddress,
|
|
854
|
-
value: BigInt(0),
|
|
855
|
-
data: approveZeroData,
|
|
856
|
-
});
|
|
857
|
-
const approveData = (0, viem_1.encodeFunctionData)({
|
|
858
|
-
abi: erc20_evm_1.ERC20_EVM,
|
|
859
|
-
functionName: 'approve',
|
|
860
|
-
args: [gatewayAddress, bridgeAmount],
|
|
861
|
-
});
|
|
862
|
-
ceaMulticalls.push({
|
|
863
|
-
to: tokenAddress,
|
|
864
|
-
value: BigInt(0),
|
|
865
|
-
data: approveData,
|
|
866
|
-
});
|
|
867
|
-
}
|
|
876
|
+
// The post-audit CEA allows amount=0 for payload-only sendUniversalTxToUEA.
|
|
868
877
|
// Pre-fetch UEA nonce — needed for the inbound UniversalPayload struct
|
|
869
878
|
// Skip getCode if accountStatusCache already confirmed deployment
|
|
870
879
|
let isUEADeployed;
|
|
@@ -927,18 +936,19 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
927
936
|
const outboundGasLimit = (_f = params.gasLimit) !== null && _f !== void 0 ? _f : selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
|
|
928
937
|
(0, context_1.printLog)(ctx, `executeCeaToPush — prc20Token: ${prc20Token}, burnAmount: ${burnAmount.toString()}`);
|
|
929
938
|
// 9. Build outbound request (same structure as Route 2)
|
|
930
|
-
//
|
|
931
|
-
|
|
939
|
+
// recipient = CEA address (for self-execution), value = 0 in payload
|
|
940
|
+
let outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, // recipient: CEA address (to=CEA for self-execution)
|
|
932
941
|
prc20Token, // token: native PRC-20 for source chain (for namespace lookup)
|
|
933
942
|
burnAmount, // amount: 0 (payload-only, CEA uses its own balance)
|
|
934
943
|
outboundGasLimit, ceaPayload, // payload: ABI-encoded CEA multicall
|
|
935
|
-
ueaAddress // revertRecipient: UEA
|
|
936
|
-
);
|
|
944
|
+
ueaAddress, // revertRecipient: UEA
|
|
945
|
+
(_g = params.maxPCForGas) !== null && _g !== void 0 ? _g : BigInt(0));
|
|
937
946
|
(0, context_1.printLog)(ctx, `executeCeaToPush — outbound request: ${JSON.stringify({
|
|
938
|
-
|
|
947
|
+
recipient: outboundReq.recipient,
|
|
939
948
|
token: outboundReq.token,
|
|
940
949
|
amount: outboundReq.amount.toString(),
|
|
941
950
|
gasLimit: outboundReq.gasLimit.toString(),
|
|
951
|
+
maxPCForGas: outboundReq.maxPCForGas.toString(),
|
|
942
952
|
payloadLength: outboundReq.payload.length,
|
|
943
953
|
revertRecipient: outboundReq.revertRecipient,
|
|
944
954
|
}, null, 2)}`);
|
|
@@ -949,6 +959,7 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
949
959
|
// 11. Query gas fees from UniversalCore
|
|
950
960
|
let gasFee = BigInt(0);
|
|
951
961
|
let protocolFeeR3 = BigInt(0);
|
|
962
|
+
let outboundGasPriceR3 = BigInt(0);
|
|
952
963
|
let nativeValueForGas = BigInt(0);
|
|
953
964
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
954
965
|
let sizingDecisionR3;
|
|
@@ -958,10 +969,12 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
958
969
|
const result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, outboundGasLimit, sourceChain);
|
|
959
970
|
gasToken = result.gasToken;
|
|
960
971
|
gasFee = result.gasFee;
|
|
972
|
+
outboundGasPriceR3 = result.gasPrice;
|
|
961
973
|
protocolFeeR3 = result.protocolFee;
|
|
962
974
|
nativeValueForGas = result.nativeValueForGas;
|
|
963
975
|
sizingDecisionR3 = result.sizing;
|
|
964
|
-
(0,
|
|
976
|
+
outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress, (_h = params.maxPCForGas) !== null && _h !== void 0 ? _h : BigInt(0), outboundGasPriceR3);
|
|
977
|
+
(0, context_1.printLog)(ctx, `executeCeaToPush — queried gas fee: ${gasFee.toString()}, gasToken: ${gasToken}, nativeValueForGas: ${nativeValueForGas.toString()}, sizing=${(_k = (_j = result.sizing) === null || _j === void 0 ? void 0 : _j.category) !== null && _k !== void 0 ? _k : 'legacy'}`);
|
|
965
978
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_02, sourceChain, protocolFeeR3, gasFee);
|
|
966
979
|
}
|
|
967
980
|
catch (err) {
|
|
@@ -1034,7 +1047,8 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
1034
1047
|
}
|
|
1035
1048
|
// Pre-flight (R3 EVM): no PRC-20 burn check — `burnAmount = 0` makes this
|
|
1036
1049
|
// payload-only (UEA never holds the source-chain PRC-20; see plan §9 #4).
|
|
1037
|
-
// Native UPC check still applies for the gas swap.
|
|
1050
|
+
// Native UPC check still applies for the gas swap. It warns by default and
|
|
1051
|
+
// throws only when options.enforceGasCheck=true.
|
|
1038
1052
|
(0, preflight_1.runPreflight)({
|
|
1039
1053
|
ctx,
|
|
1040
1054
|
ueaAddress,
|
|
@@ -1042,6 +1056,7 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
1042
1056
|
requiredValue: nativeValueForGas,
|
|
1043
1057
|
gasReserve: OUTBOUND_GAS_RESERVE_R3,
|
|
1044
1058
|
pathTag: 'R3_EVM',
|
|
1059
|
+
enforceGasCheck: ((_l = params.options) === null || _l === void 0 ? void 0 : _l.enforceGasCheck) === true,
|
|
1045
1060
|
});
|
|
1046
1061
|
// 12. Build Push Chain multicalls (approvals + sendUniversalTxOutbound)
|
|
1047
1062
|
const pushChainMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
@@ -1107,7 +1122,7 @@ function executeCeaToPush(ctx, params, executeFn) {
|
|
|
1107
1122
|
*/
|
|
1108
1123
|
function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
1109
1124
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1110
|
-
var _a, _b, _c, _d;
|
|
1125
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1111
1126
|
if (typeof params.to !== 'string') {
|
|
1112
1127
|
throw new Error('Route 3 SVM (CEA -> Push): to must be a Push Chain address (string), not a ChainTarget');
|
|
1113
1128
|
}
|
|
@@ -1121,41 +1136,31 @@ function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
|
1121
1136
|
const gatewayProgramHex = ('0x' + Buffer.from(programPk.toBytes()).toString('hex'));
|
|
1122
1137
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_301, sourceChain, lockerContract);
|
|
1123
1138
|
(0, context_1.printLog)(ctx, `executeCeaToPushSvm — sourceChain: ${sourceChain}, gateway: ${lockerContract}`);
|
|
1124
|
-
//
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
drainAmount = params.funds.amount;
|
|
1130
|
-
const token = params.funds.token;
|
|
1131
|
-
if (token && token.address) {
|
|
1132
|
-
// Convert SPL mint address to 32-byte hex
|
|
1133
|
-
const mintPk = new web3_js_1.PublicKey(token.address);
|
|
1134
|
-
tokenMintHex = ('0x' + Buffer.from(mintPk.toBytes()).toString('hex'));
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
else if (params.value && params.value > BigInt(0)) {
|
|
1138
|
-
// Native SOL drain
|
|
1139
|
-
drainAmount = params.value;
|
|
1140
|
-
}
|
|
1141
|
-
// Route 3 SVM: ALWAYS use native PRC-20 for chain namespace lookup + gas fees.
|
|
1142
|
-
// CEA uses its own pre-existing balance — no PRC-20 burn needed on Push Chain.
|
|
1143
|
-
const prc20Token = (0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork);
|
|
1144
|
-
// Build the SVM CPI payload (send_universal_tx_to_uea wrapped in execute)
|
|
1145
|
-
// If params.data is provided, pass it as extraPayload for Push Chain execution
|
|
1146
|
-
let extraPayload;
|
|
1147
|
-
if (params.data && typeof params.data === 'string') {
|
|
1148
|
-
extraPayload = (0, viem_1.hexToBytes)(params.data);
|
|
1149
|
-
}
|
|
1139
|
+
// Route 3 SVM: CEA uses its own pre-existing balance — no PRC-20 burn
|
|
1140
|
+
// needed on Push Chain. The outer request token must still match the source
|
|
1141
|
+
// asset so the relayer supplies the same Solana mint that the payload
|
|
1142
|
+
// encodes; otherwise the gateway rejects with InvalidMint.
|
|
1143
|
+
const { prc20Token, drainAmount, tokenMintHex } = resolveR3SvmDrain(params, sourceChain, ctx.pushNetwork);
|
|
1150
1144
|
// Derive CEA PDA as revert recipient: ["push_identity", ueaAddress_20_bytes]
|
|
1151
1145
|
const ueaBytes = Buffer.from(ueaAddress.slice(2), 'hex'); // 20 bytes
|
|
1152
1146
|
const [ceaPda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from('push_identity'), ueaBytes], programPk);
|
|
1153
1147
|
const ceaPdaHex = ('0x' + Buffer.from(ceaPda.toBytes()).toString('hex'));
|
|
1148
|
+
// Pre-fetch UEA status before payload construction. The inbound
|
|
1149
|
+
// UniversalPayload must use the nonce after this outbound execution, because
|
|
1150
|
+
// the Push-side execute() below consumes one UEA nonce before the Solana
|
|
1151
|
+
// round-trip payload returns.
|
|
1152
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
1153
|
+
const [ueaCode, ueaBalance] = yield Promise.all([
|
|
1154
|
+
ctx.pushClient.publicClient.getCode({ address: ueaAddress }),
|
|
1155
|
+
ctx.pushClient.getBalance(ueaAddress),
|
|
1156
|
+
]);
|
|
1157
|
+
const isUEADeployed = ueaCode !== undefined;
|
|
1158
|
+
const ueaNonce = isUEADeployed ? yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress) : BigInt(0);
|
|
1154
1159
|
const svmPayload = (0, payload_builders_1.encodeSvmCeaToUeaPayload)({
|
|
1155
1160
|
gatewayProgramHex,
|
|
1156
1161
|
drainAmount,
|
|
1157
1162
|
tokenMintHex,
|
|
1158
|
-
extraPayload,
|
|
1163
|
+
extraPayload: buildR3SvmExtraPayload(ctx, params, ueaAddress, sourceChain, ueaNonce + BigInt(1)),
|
|
1159
1164
|
revertRecipientHex: ceaPdaHex,
|
|
1160
1165
|
});
|
|
1161
1166
|
(0, context_1.printLog)(ctx, `executeCeaToPushSvm — drainAmount: ${drainAmount.toString()}, payload length: ${(svmPayload.length - 2) / 2} bytes`);
|
|
@@ -1166,33 +1171,42 @@ function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
|
1166
1171
|
// (e.g. pSOL). The UGPC upgrade post-2026-03-19 already accepts amount = 0
|
|
1167
1172
|
// on the cascade path, and the same precompile is used here.
|
|
1168
1173
|
const burnAmount = BigInt(0);
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
(0,
|
|
1172
|
-
|
|
1173
|
-
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
1174
|
-
const [ueaCode, ueaBalance] = yield Promise.all([
|
|
1175
|
-
ctx.pushClient.publicClient.getCode({ address: ueaAddress }),
|
|
1176
|
-
ctx.pushClient.getBalance(ueaAddress),
|
|
1177
|
-
]);
|
|
1178
|
-
const isUEADeployed = ueaCode !== undefined;
|
|
1179
|
-
const ueaNonce = isUEADeployed ? yield (0, uea_manager_1.getUEANonce)(ctx, ueaAddress) : BigInt(0);
|
|
1174
|
+
let effectiveGasLimit = (_a = params.gasLimit) !== null && _a !== void 0 ? _a : BigInt(0);
|
|
1175
|
+
// Build outbound request: recipient = gateway program (self-call)
|
|
1176
|
+
let outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, prc20Token, burnAmount, effectiveGasLimit, svmPayload, ueaAddress, (_b = params.maxPCForGas) !== null && _b !== void 0 ? _b : BigInt(0));
|
|
1177
|
+
(0, context_1.printLog)(ctx, `executeCeaToPushSvm — outbound request: recipient=${outboundReq.recipient.slice(0, 20)}..., token=${outboundReq.token}, maxPCForGas=${outboundReq.maxPCForGas}`);
|
|
1180
1178
|
// Query gas fees
|
|
1181
1179
|
let gasFee = BigInt(0);
|
|
1182
1180
|
let protocolFeeR3Svm = BigInt(0);
|
|
1181
|
+
let outboundGasPriceR3Svm = BigInt(0);
|
|
1183
1182
|
let nativeValueForGas = BigInt(0);
|
|
1184
1183
|
let gasToken = selectors_1.ZERO_ADDRESS;
|
|
1185
1184
|
let sizingDecisionR3Svm;
|
|
1186
1185
|
if (prc20Token !== selectors_1.ZERO_ADDRESS) {
|
|
1187
1186
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_01, sourceChain);
|
|
1188
1187
|
try {
|
|
1189
|
-
|
|
1188
|
+
let result = yield (0, gas_calculator_1.queryOutboundGasFee)(ctx, prc20Token, outboundReq.gasLimit, sourceChain);
|
|
1189
|
+
result = yield (0, svm_rent_1.ensureSvmFinalizeGasBudgetQuote)({
|
|
1190
|
+
ctx,
|
|
1191
|
+
ueaAddress,
|
|
1192
|
+
targetChain: sourceChain,
|
|
1193
|
+
prc20Token,
|
|
1194
|
+
quote: result,
|
|
1195
|
+
splMintBase58: undefined,
|
|
1196
|
+
burnAmount: BigInt(0),
|
|
1197
|
+
pathTag: 'executeCeaToPushSvm',
|
|
1198
|
+
});
|
|
1190
1199
|
gasToken = result.gasToken;
|
|
1191
1200
|
gasFee = result.gasFee;
|
|
1201
|
+
outboundGasPriceR3Svm = result.gasPrice;
|
|
1192
1202
|
protocolFeeR3Svm = result.protocolFee;
|
|
1193
1203
|
nativeValueForGas = result.nativeValueForGas;
|
|
1194
1204
|
sizingDecisionR3Svm = result.sizing;
|
|
1195
|
-
|
|
1205
|
+
effectiveGasLimit = result.gasLimitUsed;
|
|
1206
|
+
outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, prc20Token, burnAmount, effectiveGasLimit, svmPayload, ueaAddress, (_c = params.maxPCForGas) !== null && _c !== void 0 ? _c : BigInt(0), outboundGasPriceR3Svm);
|
|
1207
|
+
(0, context_1.printLog)(ctx, `executeCeaToPushSvm — resolved effectiveGasLimit: ${effectiveGasLimit} ` +
|
|
1208
|
+
`(gasFee=${result.gasFee}, gasPrice=${result.gasPrice})`);
|
|
1209
|
+
(0, context_1.printLog)(ctx, `executeCeaToPushSvm — gasFee: ${gasFee.toString()}, gasToken: ${gasToken}, nativeValueForGas: ${nativeValueForGas.toString()}, sizing=${(_e = (_d = result.sizing) === null || _d === void 0 ? void 0 : _d.category) !== null && _e !== void 0 ? _e : 'legacy'}`);
|
|
1196
1210
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_302_02, sourceChain, protocolFeeR3Svm, gasFee);
|
|
1197
1211
|
}
|
|
1198
1212
|
catch (err) {
|
|
@@ -1233,13 +1247,13 @@ function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
|
1233
1247
|
: UPWARD_BASE_CEILING_R3_SVM;
|
|
1234
1248
|
// Upward-only allocation: when balance has headroom over the calibrated
|
|
1235
1249
|
// value, consume more of it (up to the ceiling above). Down-clamp +
|
|
1236
|
-
// zero-balance
|
|
1250
|
+
// zero-balance handling lives in pre-flight.
|
|
1237
1251
|
// Ordering note: pre-flight runs AFTER the upward adjust below; the
|
|
1238
1252
|
// semantics are equivalent to running it before — when upward adjust
|
|
1239
1253
|
// applies it sets nativeValueForGas to balance-reserve (capped), and the
|
|
1240
1254
|
// post-adjust pre-flight check is always satisfied. When upward adjust is
|
|
1241
1255
|
// skipped (balance too low), pre-flight runs against the calibrated value
|
|
1242
|
-
// and throws
|
|
1256
|
+
// and either warns or throws based on options.enforceGasCheck.
|
|
1243
1257
|
if (currentBalance > OUTBOUND_GAS_RESERVE_R3_SVM &&
|
|
1244
1258
|
currentBalance - OUTBOUND_GAS_RESERVE_R3_SVM > nativeValueForGas) {
|
|
1245
1259
|
const balanceDriven = currentBalance - OUTBOUND_GAS_RESERVE_R3_SVM;
|
|
@@ -1252,9 +1266,8 @@ function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
|
1252
1266
|
}
|
|
1253
1267
|
// SVM warn-threshold telemetry (no truncation — pre-flight handles drain protection).
|
|
1254
1268
|
(0, preflight_1.maybeFireSvmWarnThreshold)(ctx, nativeValueForGas, gasToken, 'R3_SVM');
|
|
1255
|
-
// Pre-flight (R3 SVM): no PRC-20 burn check
|
|
1256
|
-
//
|
|
1257
|
-
// (see plan §9 #4 / §10.2 latent-bug ticket). Native UPC check still applies.
|
|
1269
|
+
// Pre-flight (R3 SVM): no PRC-20 burn check. R3 SVM uses burnAmount=0
|
|
1270
|
+
// because the drain amount lives inside the SVM instruction data.
|
|
1258
1271
|
(0, preflight_1.runPreflight)({
|
|
1259
1272
|
ctx,
|
|
1260
1273
|
ueaAddress,
|
|
@@ -1262,6 +1275,7 @@ function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
|
1262
1275
|
requiredValue: nativeValueForGas,
|
|
1263
1276
|
gasReserve: OUTBOUND_GAS_RESERVE_R3_SVM,
|
|
1264
1277
|
pathTag: 'R3_SVM',
|
|
1278
|
+
enforceGasCheck: ((_f = params.options) === null || _f === void 0 ? void 0 : _f.enforceGasCheck) === true,
|
|
1265
1279
|
});
|
|
1266
1280
|
// Build Push Chain multicalls (approvals + sendUniversalTxOutbound)
|
|
1267
1281
|
const pushChainMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
@@ -1299,17 +1313,11 @@ function executeCeaToPushSvm(ctx, params, sourceChain, executeFn) {
|
|
|
1299
1313
|
response.chain = sourceChain;
|
|
1300
1314
|
const chainInfo = chain_1.CHAIN_INFO[sourceChain];
|
|
1301
1315
|
response.chainNamespace = `${chain_1.VM_NAMESPACE[chainInfo.vm]}:${chainInfo.chainId}`;
|
|
1302
|
-
// R3 SVM
|
|
1303
|
-
//
|
|
1304
|
-
//
|
|
1305
|
-
//
|
|
1306
|
-
|
|
1307
|
-
// log — the parent utxId's `outboundStatus=OBSERVED` is the terminal state.
|
|
1308
|
-
// Polling for a deterministically-derived child id therefore never
|
|
1309
|
-
// resolves, and the cosmos `inbound_tx_hash` text-search fallback also
|
|
1310
|
-
// returns 0 hits. Receipts now resolve as soon as the Solana outbound is
|
|
1311
|
-
// observed instead of timing out at 300s.
|
|
1312
|
-
response._expectsInboundRoundTrip = false;
|
|
1316
|
+
// R3 SVM mirrors EVM R3: when funds drain back to Push, the Solana-side
|
|
1317
|
+
// send_universal_tx_to_uea emits an inbound leg whose payload can execute on
|
|
1318
|
+
// Push. Payload-only R3 has no child inbound UTX, so skip round-trip tracking
|
|
1319
|
+
// when no amount is being drained.
|
|
1320
|
+
response._expectsInboundRoundTrip = drainAmount > BigInt(0);
|
|
1313
1321
|
return response;
|
|
1314
1322
|
});
|
|
1315
1323
|
}
|
|
@@ -1335,7 +1343,7 @@ function executeCeaToCea(ctx, params, executeFn) {
|
|
|
1335
1343
|
*/
|
|
1336
1344
|
function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
1337
1345
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
1338
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
1346
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
1339
1347
|
const ueaAddress = (0, uea_manager_1.computeUEAOffchain)(ctx);
|
|
1340
1348
|
switch (route) {
|
|
1341
1349
|
case route_detector_1.TransactionRoute.UOA_TO_PUSH: {
|
|
@@ -1379,13 +1387,13 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1379
1387
|
}
|
|
1380
1388
|
else if (hasExecute) {
|
|
1381
1389
|
prc20Token = (0, helpers_1.getNativePRC20ForChain)(target.chain, ctx.pushNetwork);
|
|
1382
|
-
burnAmount = BigInt(
|
|
1390
|
+
burnAmount = BigInt(0);
|
|
1383
1391
|
}
|
|
1384
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, (_b = params.gasLimit) !== null && _b !== void 0 ? _b : BigInt(0), payload, ueaAddress);
|
|
1392
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, (_b = params.gasLimit) !== null && _b !== void 0 ? _b : BigInt(0), payload, ueaAddress, (_c = params.maxPCForGas) !== null && _c !== void 0 ? _c : BigInt(0));
|
|
1385
1393
|
return { payload, gatewayRequest: outboundReq };
|
|
1386
1394
|
}
|
|
1387
1395
|
// EVM path: Resolve CEA address first (needed for self-transfer check)
|
|
1388
|
-
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, target.chain, (
|
|
1396
|
+
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, target.chain, (_d = ctx.rpcUrls[target.chain]) === null || _d === void 0 ? void 0 : _d[0]);
|
|
1389
1397
|
// Build CEA outbound payload
|
|
1390
1398
|
const multicalls = [];
|
|
1391
1399
|
if (params.data) {
|
|
@@ -1418,21 +1426,24 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1418
1426
|
const payload = (0, payload_builders_1.buildCeaMulticallPayload)(multicalls);
|
|
1419
1427
|
let prc20Token = selectors_1.ZERO_ADDRESS;
|
|
1420
1428
|
let burnAmount = BigInt(0);
|
|
1421
|
-
if ((
|
|
1429
|
+
if ((_e = params.funds) === null || _e === void 0 ? void 0 : _e.amount) {
|
|
1422
1430
|
const token = params.funds.token;
|
|
1423
1431
|
if (token) {
|
|
1424
1432
|
prc20Token = push_chain_1.PushChain.utils.tokens.getPRC20Address(token).address;
|
|
1425
1433
|
burnAmount = params.funds.amount;
|
|
1426
1434
|
}
|
|
1427
1435
|
}
|
|
1428
|
-
const targetBytes =
|
|
1429
|
-
|
|
1436
|
+
const targetBytes = payload === '0x'
|
|
1437
|
+
? selectors_1.ZERO_ADDRESS
|
|
1438
|
+
: ceaAddress;
|
|
1439
|
+
(0, payload_builders_1.assertCeaFundsParkingInvariant)(targetBytes, payload);
|
|
1440
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetBytes, prc20Token, burnAmount, (_f = params.gasLimit) !== null && _f !== void 0 ? _f : BigInt(0), payload, ueaAddress, (_g = params.maxPCForGas) !== null && _g !== void 0 ? _g : BigInt(0));
|
|
1430
1441
|
return { payload, gatewayRequest: outboundReq };
|
|
1431
1442
|
}
|
|
1432
1443
|
case route_detector_1.TransactionRoute.CEA_TO_PUSH: {
|
|
1433
1444
|
// Route 3: CEA -> Push Chain
|
|
1434
|
-
// Build CEA multicall (
|
|
1435
|
-
if (!((
|
|
1445
|
+
// Build CEA multicall (sendUniversalTxToUEA self-call) and wrap in outbound
|
|
1446
|
+
if (!((_h = params.from) === null || _h === void 0 ? void 0 : _h.chain)) {
|
|
1436
1447
|
throw new Error('Route 3 (CEA -> Push) requires from.chain');
|
|
1437
1448
|
}
|
|
1438
1449
|
const sourceChain = params.from.chain;
|
|
@@ -1445,21 +1456,7 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1445
1456
|
}
|
|
1446
1457
|
const programPk = new web3_js_1.PublicKey(lockerContract);
|
|
1447
1458
|
const gatewayProgramHex = ('0x' + Buffer.from(programPk.toBytes()).toString('hex'));
|
|
1448
|
-
|
|
1449
|
-
let tokenMintHex;
|
|
1450
|
-
if (((_g = params.funds) === null || _g === void 0 ? void 0 : _g.amount) && params.funds.amount > BigInt(0)) {
|
|
1451
|
-
drainAmount = params.funds.amount;
|
|
1452
|
-
const token = params.funds.token;
|
|
1453
|
-
if (token && token.address) {
|
|
1454
|
-
const mintPk = new web3_js_1.PublicKey(token.address);
|
|
1455
|
-
tokenMintHex = ('0x' + Buffer.from(mintPk.toBytes()).toString('hex'));
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
else if (params.value && params.value > BigInt(0)) {
|
|
1459
|
-
drainAmount = params.value;
|
|
1460
|
-
}
|
|
1461
|
-
// Route 3 SVM: ALWAYS use native PRC-20, CEA uses its own balance.
|
|
1462
|
-
const prc20Token = (0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork);
|
|
1459
|
+
const { prc20Token, drainAmount, tokenMintHex } = resolveR3SvmDrain(params, sourceChain, ctx.pushNetwork);
|
|
1463
1460
|
// Derive CEA PDA as revert recipient
|
|
1464
1461
|
const ueaBytes2 = Buffer.from(ueaAddress.slice(2), 'hex');
|
|
1465
1462
|
const [ceaPda2] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from('push_identity'), ueaBytes2], programPk);
|
|
@@ -1468,25 +1465,22 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1468
1465
|
gatewayProgramHex,
|
|
1469
1466
|
drainAmount,
|
|
1470
1467
|
tokenMintHex,
|
|
1468
|
+
extraPayload: buildR3SvmExtraPayload(ctx, params, ueaAddress, sourceChain, nonce + BigInt(1)),
|
|
1471
1469
|
revertRecipientHex: ceaPdaHex2,
|
|
1472
1470
|
});
|
|
1473
|
-
//
|
|
1474
|
-
const burnAmount = BigInt(
|
|
1475
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, prc20Token, burnAmount, (
|
|
1471
|
+
// Payload-only outbound: drain amount lives inside ixData.
|
|
1472
|
+
const burnAmount = BigInt(0);
|
|
1473
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, prc20Token, burnAmount, (_j = params.gasLimit) !== null && _j !== void 0 ? _j : BigInt(0), svmPayload, ueaAddress, (_k = params.maxPCForGas) !== null && _k !== void 0 ? _k : BigInt(0));
|
|
1476
1474
|
return { payload: svmPayload, gatewayRequest: outboundReq };
|
|
1477
1475
|
}
|
|
1478
|
-
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (
|
|
1476
|
+
const { cea: ceaAddress } = yield (0, cea_utils_1.getCEAAddress)(ueaAddress, sourceChain, (_l = ctx.rpcUrls[sourceChain]) === null || _l === void 0 ? void 0 : _l[0]);
|
|
1479
1477
|
// CEA auto-deploys on-chain: Vault.finalizeUniversalTx calls CEAFactory.deployCEA()
|
|
1480
1478
|
// if CEA doesn't exist yet. No SDK-side blocking needed.
|
|
1481
|
-
const gatewayAddr = chain_1.UNIVERSAL_GATEWAY_ADDRESSES[sourceChain];
|
|
1482
|
-
if (!gatewayAddr) {
|
|
1483
|
-
throw new Error(`No UniversalGateway address configured for chain ${sourceChain}`);
|
|
1484
|
-
}
|
|
1485
1479
|
// Build CEA multicalls (self-calls via sendUniversalTxToUEA)
|
|
1486
1480
|
const ceaMulticalls = [];
|
|
1487
1481
|
let tokenAddress = selectors_1.ZERO_ADDRESS;
|
|
1488
1482
|
let amount = BigInt(0);
|
|
1489
|
-
if ((
|
|
1483
|
+
if ((_m = params.funds) === null || _m === void 0 ? void 0 : _m.amount) {
|
|
1490
1484
|
const token = params.funds.token;
|
|
1491
1485
|
if (token) {
|
|
1492
1486
|
if (token.mechanism === 'native') {
|
|
@@ -1496,27 +1490,6 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1496
1490
|
else {
|
|
1497
1491
|
tokenAddress = token.address;
|
|
1498
1492
|
amount = params.funds.amount;
|
|
1499
|
-
// Reset allowance to 0 first for USDT-style tokens, then approve
|
|
1500
|
-
const approveZeroData = (0, viem_1.encodeFunctionData)({
|
|
1501
|
-
abi: erc20_evm_1.ERC20_EVM,
|
|
1502
|
-
functionName: 'approve',
|
|
1503
|
-
args: [gatewayAddr, BigInt(0)],
|
|
1504
|
-
});
|
|
1505
|
-
ceaMulticalls.push({
|
|
1506
|
-
to: tokenAddress,
|
|
1507
|
-
value: BigInt(0),
|
|
1508
|
-
data: approveZeroData,
|
|
1509
|
-
});
|
|
1510
|
-
const approveData = (0, viem_1.encodeFunctionData)({
|
|
1511
|
-
abi: erc20_evm_1.ERC20_EVM,
|
|
1512
|
-
functionName: 'approve',
|
|
1513
|
-
args: [gatewayAddr, amount],
|
|
1514
|
-
});
|
|
1515
|
-
ceaMulticalls.push({
|
|
1516
|
-
to: tokenAddress,
|
|
1517
|
-
value: BigInt(0),
|
|
1518
|
-
data: approveData,
|
|
1519
|
-
});
|
|
1520
1493
|
}
|
|
1521
1494
|
}
|
|
1522
1495
|
}
|
|
@@ -1551,8 +1524,8 @@ function buildPayloadForRoute(ctx, params, route, nonce) {
|
|
|
1551
1524
|
// Route 3: CEA uses its own pre-existing balance — no PRC-20 burn needed.
|
|
1552
1525
|
// burnAmount = 0 makes this a payload-only outbound relay.
|
|
1553
1526
|
const burnAmount = BigInt(0);
|
|
1554
|
-
const outboundGasLimit = (
|
|
1555
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress);
|
|
1527
|
+
const outboundGasLimit = (_o = params.gasLimit) !== null && _o !== void 0 ? _o : selectors_1.DEFAULT_CEA_TO_PUSH_GAS_LIMIT;
|
|
1528
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, prc20Token, burnAmount, outboundGasLimit, ceaPayload, ueaAddress, (_p = params.maxPCForGas) !== null && _p !== void 0 ? _p : BigInt(0));
|
|
1556
1529
|
return { payload: ceaPayload, gatewayRequest: outboundReq };
|
|
1557
1530
|
}
|
|
1558
1531
|
default:
|