@pushchain/core 5.1.4 → 5.1.5-alpha.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/index.d.ts +1 -1
- package/src/lib/orchestrator/internals/cascade.js +68 -25
- package/src/lib/orchestrator/internals/execute-funds-payload.js +4 -4
- package/src/lib/orchestrator/internals/execute-standard.js +55 -7
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +10 -0
- package/src/lib/orchestrator/internals/gas-calculator.js +95 -3
- package/src/lib/orchestrator/internals/gateway-client.js +6 -6
- package/src/lib/orchestrator/internals/response-builder.js +24 -1
- package/src/lib/orchestrator/internals/route-handlers.js +27 -43
- package/src/lib/orchestrator/orchestrator.types.d.ts +13 -23
- package/src/lib/orchestrator/route-detector.js +0 -3
- package/src/lib/orchestrator/svm-idl/build-payload.d.ts +11 -0
- package/src/lib/orchestrator/svm-idl/build-payload.js +36 -0
- package/src/lib/orchestrator/svm-idl/ix-encoder.d.ts +3 -0
- package/src/lib/orchestrator/svm-idl/ix-encoder.js +47 -0
- package/src/lib/orchestrator/svm-idl/registry.d.ts +10 -0
- package/src/lib/orchestrator/svm-idl/registry.js +36 -0
- package/src/lib/orchestrator/svm-idl/resolve.d.ts +14 -0
- package/src/lib/orchestrator/svm-idl/resolve.js +85 -0
- package/src/lib/progress-hook/progress-hook.js +40 -0
- package/src/lib/progress-hook/progress-hook.types.d.ts +5 -0
- package/src/lib/progress-hook/progress-hook.types.js +6 -0
- package/src/lib/push-chain/push-chain.js +14 -4
- package/src/lib/universal/account/account.d.ts +13 -0
- package/src/lib/universal/account/account.js +1 -0
- package/src/lib/utils.d.ts +20 -1
- package/src/lib/utils.js +28 -0
package/package.json
CHANGED
package/src/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PushChain } from './push-chain/push-chain';
|
|
2
2
|
export type { ConversionQuote } from './constants/tokens';
|
|
3
3
|
export type { UniversalSigner, UniversalAccount, UniversalSignerSkeleton, DerivedExecutorAccount, ResolvedAccount, ResolvedControllerAccounts, AccountType, AccountRole, } from './universal/universal.types';
|
|
4
|
-
export type { ChainTarget, ChainSource, UniversalTo, TransactionRouteType, UniversalExecuteParams, UniversalOutboundTxRequest, PreparedUniversalTx, CascadedTxResponse, CascadeHopInfo, CascadeTrackOptions, CascadeProgressEvent, CascadeCompletionResult, MultiChainTxResponse, OutboundTxDetails, WaitForOutboundOptions, SvmGatewayAccountMeta, SvmExecutePayloadFields,
|
|
4
|
+
export type { ChainTarget, ChainSource, UniversalTo, TransactionRouteType, UniversalExecuteParams, UniversalOutboundTxRequest, PreparedUniversalTx, CascadedTxResponse, CascadeHopInfo, CascadeTrackOptions, CascadeProgressEvent, CascadeCompletionResult, MultiChainTxResponse, OutboundTxDetails, WaitForOutboundOptions, SvmGatewayAccountMeta, SvmExecutePayloadFields, AccountStatus, UEAStatus, RescueFundsParams, } from './orchestrator/orchestrator.types';
|
|
5
5
|
export { parseUEAVersion } from './orchestrator/orchestrator.types';
|
|
6
6
|
export { TransactionRoute, detectRoute, isChainTarget } from './orchestrator/route-detector';
|
|
7
7
|
export { getCEAAddress, getPushAccountForCEA, isCEA, chainSupportsCEA, chainSupportsOutbound, getCEAFactoryAddress, getAllCEAAddresses, } from './orchestrator/cea-utils';
|
|
@@ -27,6 +27,9 @@ const payload_builder_1 = require("./payload-builder");
|
|
|
27
27
|
const uea_manager_1 = require("./uea-manager");
|
|
28
28
|
const gas_calculator_1 = require("./gas-calculator");
|
|
29
29
|
const route_handlers_1 = require("./route-handlers");
|
|
30
|
+
const build_payload_1 = require("../svm-idl/build-payload");
|
|
31
|
+
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
32
|
+
const progress_hook_1 = tslib_1.__importDefault(require("../../progress-hook/progress-hook"));
|
|
30
33
|
// ============================================================================
|
|
31
34
|
// prepareTransaction
|
|
32
35
|
// ============================================================================
|
|
@@ -110,18 +113,12 @@ function buildHopDescriptor(ctx, params, route, ueaAddress) {
|
|
|
110
113
|
const targetChain = target.chain;
|
|
111
114
|
// Branch: SVM vs EVM
|
|
112
115
|
if ((0, payload_builders_1.isSvmChain)(targetChain)) {
|
|
113
|
-
// SVM path: no CEA lookup, build SVM payload
|
|
114
|
-
const hasSvmExecute =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
targetProgram: exec.targetProgram,
|
|
120
|
-
accounts: exec.accounts,
|
|
121
|
-
ixData: exec.ixData,
|
|
122
|
-
instructionId: 2,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
116
|
+
// SVM path: no CEA lookup, build SVM payload via IDL resolver
|
|
117
|
+
const { svmPayload, hasExecute: hasSvmExecute } = (0, build_payload_1.buildSvmPayloadFromParams)({
|
|
118
|
+
data: params.data,
|
|
119
|
+
to: target,
|
|
120
|
+
senderUea: ueaAddress,
|
|
121
|
+
});
|
|
125
122
|
let prc20Token = selectors_1.ZERO_ADDRESS;
|
|
126
123
|
let burnAmount = BigInt(0);
|
|
127
124
|
if ((_b = params.funds) === null || _b === void 0 ? void 0 : _b.amount) {
|
|
@@ -432,7 +429,7 @@ function getSegmentType(route) {
|
|
|
432
429
|
// composeCascade
|
|
433
430
|
// ============================================================================
|
|
434
431
|
function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
435
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
432
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
436
433
|
let accumulatedPushMulticalls = [];
|
|
437
434
|
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
438
435
|
// Compute per-outbound nativeValueForGas from UEA balance
|
|
@@ -465,10 +462,9 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
465
462
|
if (isSvmSegment) {
|
|
466
463
|
// SVM: use the pre-built SVM payload from the hop descriptor
|
|
467
464
|
outboundPayload = (_a = firstHop.svmPayload) !== null && _a !== void 0 ? _a : '0x';
|
|
468
|
-
// For SVM,
|
|
465
|
+
// For SVM, to.address IS the target (program for execute, recipient for withdraw)
|
|
469
466
|
const svmTarget = firstHop.params.to;
|
|
470
|
-
targetForOutbound =
|
|
471
|
-
(_c = (_b = firstHop.params.svmExecute) === null || _b === void 0 ? void 0 : _b.targetProgram) !== null && _c !== void 0 ? _c : svmTarget.address;
|
|
467
|
+
targetForOutbound = svmTarget.address;
|
|
472
468
|
}
|
|
473
469
|
else if (isMigration) {
|
|
474
470
|
// Migration: use raw 4-byte MIGRATION_SELECTOR, no multicall wrapping
|
|
@@ -482,7 +478,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
482
478
|
targetForOutbound = (firstHop === null || firstHop === void 0 ? void 0 : firstHop.ceaAddress) || ueaAddress;
|
|
483
479
|
}
|
|
484
480
|
// Build outbound request
|
|
485
|
-
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetForOutbound, segment.prc20Token || selectors_1.ZERO_ADDRESS, segment.totalBurnAmount || BigInt(0), (
|
|
481
|
+
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(targetForOutbound, segment.prc20Token || selectors_1.ZERO_ADDRESS, segment.totalBurnAmount || BigInt(0), (_b = segment.gasLimit) !== null && _b !== void 0 ? _b : BigInt(0), outboundPayload, ueaAddress);
|
|
486
482
|
// Build approval + outbound multicalls
|
|
487
483
|
const segGasFee = segment.gasFee || BigInt(0);
|
|
488
484
|
const outboundMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
@@ -507,7 +503,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
507
503
|
// Build push multicalls from this hop's own data (e.g., counter.increment())
|
|
508
504
|
// This is the Route 3 hop's payload that executes on Push Chain after inbound.
|
|
509
505
|
const hop0 = segment.hops[0];
|
|
510
|
-
if ((
|
|
506
|
+
if ((_c = hop0 === null || hop0 === void 0 ? void 0 : hop0.params) === null || _c === void 0 ? void 0 : _c.data) {
|
|
511
507
|
const hopPushMulticalls = (0, payload_builders_1.buildExecuteMulticall)({
|
|
512
508
|
execute: {
|
|
513
509
|
to: hop0.params.to,
|
|
@@ -543,7 +539,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
543
539
|
let drainAmount = BigInt(0);
|
|
544
540
|
let tokenMintHex;
|
|
545
541
|
const params = hop.params;
|
|
546
|
-
if (((
|
|
542
|
+
if (((_d = params.funds) === null || _d === void 0 ? void 0 : _d.amount) && params.funds.amount > BigInt(0)) {
|
|
547
543
|
drainAmount = params.funds.amount;
|
|
548
544
|
const token = params.funds.token;
|
|
549
545
|
if (token && token.address) {
|
|
@@ -572,7 +568,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
572
568
|
});
|
|
573
569
|
const svmBurnAmount = segment.totalBurnAmount || BigInt(0);
|
|
574
570
|
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(gatewayProgramHex, segment.prc20Token ||
|
|
575
|
-
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), svmBurnAmount, (
|
|
571
|
+
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), svmBurnAmount, (_e = segment.gasLimit) !== null && _e !== void 0 ? _e : BigInt(0), svmPayload, ueaAddress);
|
|
576
572
|
const inboundGasFee = segment.gasFee || BigInt(0);
|
|
577
573
|
const outboundMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
578
574
|
prc20Token: segment.prc20Token ||
|
|
@@ -598,7 +594,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
598
594
|
let tokenAddress = selectors_1.ZERO_ADDRESS;
|
|
599
595
|
let amount = BigInt(0);
|
|
600
596
|
const params = hop.params;
|
|
601
|
-
if ((
|
|
597
|
+
if ((_f = params.funds) === null || _f === void 0 ? void 0 : _f.amount) {
|
|
602
598
|
const token = params.funds.token;
|
|
603
599
|
if (token) {
|
|
604
600
|
if (token.mechanism === 'native') {
|
|
@@ -645,7 +641,7 @@ function composeCascade(ctx, segments, ueaAddress, ueaBalance, ueaNonce) {
|
|
|
645
641
|
// Wrap CEA multicall in outbound from Push Chain
|
|
646
642
|
const ceaPayload = (0, payload_builders_1.buildCeaMulticallPayload)(ceaMulticalls);
|
|
647
643
|
const outboundReq = (0, payload_builders_1.buildOutboundRequest)(ceaAddress, segment.prc20Token ||
|
|
648
|
-
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), segment.totalBurnAmount || BigInt(0), (
|
|
644
|
+
(0, helpers_1.getNativePRC20ForChain)(sourceChain, ctx.pushNetwork), segment.totalBurnAmount || BigInt(0), (_g = segment.gasLimit) !== null && _g !== void 0 ? _g : BigInt(0), ceaPayload, ueaAddress);
|
|
649
645
|
const inboundGasFee = segment.gasFee || BigInt(0);
|
|
650
646
|
const outboundMulticalls = (0, payload_builders_1.buildOutboundApprovalAndCall)({
|
|
651
647
|
prc20Token: segment.prc20Token ||
|
|
@@ -781,8 +777,8 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
781
777
|
hops: hopInfos,
|
|
782
778
|
hopCount: hops.length,
|
|
783
779
|
waitForAll: (opts) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
784
|
-
var _a;
|
|
785
|
-
const { pollingIntervalMs = 10000, timeout = 300000, progressHook: cascadeProgressHook, } = opts || {};
|
|
780
|
+
var _a, _b;
|
|
781
|
+
const { pollingIntervalMs = 10000, timeout = 300000, progressHook: cascadeProgressHook, eventHook, } = opts || {};
|
|
786
782
|
const startTime = Date.now();
|
|
787
783
|
try {
|
|
788
784
|
// 1. Wait for initial Push Chain tx confirmation
|
|
@@ -847,12 +843,14 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
847
843
|
status: 'timeout',
|
|
848
844
|
elapsed: Date.now() - startTime,
|
|
849
845
|
});
|
|
846
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_04](Date.now() - startTime));
|
|
850
847
|
return {
|
|
851
848
|
success: false,
|
|
852
849
|
hops: hopInfos,
|
|
853
850
|
failedAt: hop.hopIndex,
|
|
854
851
|
};
|
|
855
852
|
}
|
|
853
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_08_01](hop.executionChain));
|
|
856
854
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
857
855
|
hopIndex: hop.hopIndex,
|
|
858
856
|
route: hop.route,
|
|
@@ -860,6 +858,7 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
860
858
|
status: 'polling',
|
|
861
859
|
elapsed: Date.now() - startTime,
|
|
862
860
|
});
|
|
861
|
+
let lastEmittedStatus;
|
|
863
862
|
try {
|
|
864
863
|
const outboundDetails = yield callbacks.waitForOutboundTxFn(response.hash, {
|
|
865
864
|
initialWaitMs: Math.min(60000, remainingTimeout),
|
|
@@ -873,11 +872,17 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
873
872
|
status: event.status,
|
|
874
873
|
elapsed: Date.now() - startTime,
|
|
875
874
|
});
|
|
875
|
+
if (event.status === 'polling' &&
|
|
876
|
+
lastEmittedStatus !== 'polling') {
|
|
877
|
+
lastEmittedStatus = 'polling';
|
|
878
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_08_02](event.elapsed));
|
|
879
|
+
}
|
|
876
880
|
},
|
|
877
881
|
});
|
|
878
882
|
hop.status = 'confirmed';
|
|
879
883
|
hop.txHash = outboundDetails.externalTxHash;
|
|
880
884
|
hop.outboundDetails = outboundDetails;
|
|
885
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_03](outboundDetails));
|
|
881
886
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
882
887
|
hopIndex: hop.hopIndex,
|
|
883
888
|
route: hop.route,
|
|
@@ -888,6 +893,11 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
888
893
|
});
|
|
889
894
|
}
|
|
890
895
|
catch (err) {
|
|
896
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
897
|
+
const isTimeout = errMsg.startsWith('Timeout waiting for outbound transaction');
|
|
898
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(isTimeout
|
|
899
|
+
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_04](remainingTimeout)
|
|
900
|
+
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_05](errMsg));
|
|
891
901
|
hop.status = 'failed';
|
|
892
902
|
cascadeProgressHook === null || cascadeProgressHook === void 0 ? void 0 : cascadeProgressHook({
|
|
893
903
|
hopIndex: hop.hopIndex,
|
|
@@ -905,6 +915,13 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
905
915
|
}
|
|
906
916
|
else {
|
|
907
917
|
// Multiple outbound hops: use V2 API which returns outboundTx[]
|
|
918
|
+
// Emit "Awaiting External Chain" once per outbound hop before
|
|
919
|
+
// polling begins.
|
|
920
|
+
for (const outHop of outboundHops) {
|
|
921
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_08_01](outHop.executionChain));
|
|
922
|
+
}
|
|
923
|
+
const perHopLastStatus = new Map();
|
|
924
|
+
const confirmedHops = new Set();
|
|
908
925
|
const allOutboundDetails = yield callbacks.waitForAllOutboundTxsFn(response.hash, outboundHops, {
|
|
909
926
|
initialWaitMs: Math.min(60000, timeout - (Date.now() - startTime)),
|
|
910
927
|
pollingIntervalMs,
|
|
@@ -918,13 +935,39 @@ function createCascadedBuilder(ctx, preparedTxs, callbacks) {
|
|
|
918
935
|
txHash: event.txHash,
|
|
919
936
|
elapsed: Date.now() - startTime,
|
|
920
937
|
});
|
|
938
|
+
const prev = perHopLastStatus.get(event.hopIndex);
|
|
939
|
+
if (event.status === 'polling' &&
|
|
940
|
+
prev !== 'polling') {
|
|
941
|
+
perHopLastStatus.set(event.hopIndex, 'polling');
|
|
942
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_08_02](Date.now() - startTime));
|
|
943
|
+
}
|
|
944
|
+
if (event.status === 'confirmed' &&
|
|
945
|
+
event.txHash &&
|
|
946
|
+
!confirmedHops.has(event.hopIndex)) {
|
|
947
|
+
// waitForAllOutboundTxsV2 populates hop.outboundDetails
|
|
948
|
+
// on the matched hop before emitting 'confirmed' (see
|
|
949
|
+
// outbound-sync.ts:348-355). Auto-promotion paths
|
|
950
|
+
// without a txHash are skipped by the `event.txHash`
|
|
951
|
+
// guard above, so we only reach here with full details.
|
|
952
|
+
const matchedHop = outboundHops.find((h) => h.hopIndex === event.hopIndex);
|
|
953
|
+
if (matchedHop === null || matchedHop === void 0 ? void 0 : matchedHop.outboundDetails) {
|
|
954
|
+
confirmedHops.add(event.hopIndex);
|
|
955
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_03](matchedHop.outboundDetails));
|
|
956
|
+
}
|
|
957
|
+
}
|
|
921
958
|
},
|
|
922
959
|
});
|
|
923
960
|
if (!allOutboundDetails.success) {
|
|
961
|
+
const failedIdx = (_b = allOutboundDetails.failedAt) !== null && _b !== void 0 ? _b : 0;
|
|
962
|
+
const failedHop = outboundHops.find((h) => h.hopIndex === failedIdx);
|
|
963
|
+
const failMsg = failedHop
|
|
964
|
+
? `Outbound failed for hop ${failedIdx} on ${failedHop.executionChain}`
|
|
965
|
+
: `Outbound cascade failed at hop ${failedIdx}`;
|
|
966
|
+
eventHook === null || eventHook === void 0 ? void 0 : eventHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_05](failMsg));
|
|
924
967
|
return {
|
|
925
968
|
success: false,
|
|
926
969
|
hops: hopInfos,
|
|
927
|
-
failedAt:
|
|
970
|
+
failedAt: failedIdx,
|
|
928
971
|
};
|
|
929
972
|
}
|
|
930
973
|
}
|
|
@@ -74,15 +74,15 @@ function executeFundsWithPayload(ctx, execute, eventBuffer, getResponseCallbacks
|
|
|
74
74
|
const ueaAddress = (0, uea_manager_1.computeUEAOffchain)(ctx);
|
|
75
75
|
const ueaBalance = yield ctx.pushClient.getBalance(ueaAddress);
|
|
76
76
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_03_02, ueaAddress, deployed);
|
|
77
|
-
// Determine USD to deposit via gateway (8 decimals) with caps: min=$1, max=$
|
|
77
|
+
// Determine USD to deposit via gateway (8 decimals) with caps: min=$1, max=$1000
|
|
78
78
|
const oneUsd = utils_1.Utils.helpers.parseUnits('1', 8);
|
|
79
|
-
const
|
|
79
|
+
const maxUsd = utils_1.Utils.helpers.parseUnits('1000', 8);
|
|
80
80
|
const deficit = requiredFunds > ueaBalance ? requiredFunds - ueaBalance : BigInt(0);
|
|
81
81
|
let depositUsd = deficit > BigInt(0) ? ctx.pushClient.pushToUSDC(deficit) : oneUsd;
|
|
82
82
|
if (depositUsd < oneUsd)
|
|
83
83
|
depositUsd = oneUsd;
|
|
84
|
-
if (depositUsd >
|
|
85
|
-
throw new Error('Deposit value exceeds max $
|
|
84
|
+
if (depositUsd > maxUsd)
|
|
85
|
+
throw new Error('Deposit value exceeds max $1000 worth of native token');
|
|
86
86
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_02, depositUsd);
|
|
87
87
|
// If SVM, clamp depositUsd to on-chain Config caps
|
|
88
88
|
if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM) {
|
|
@@ -200,7 +200,34 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
200
200
|
const fundDifference = requiredFunds - funds;
|
|
201
201
|
const fixedPushAmount = utils_1.Utils.helpers.parseUnits('0.001', 18);
|
|
202
202
|
const lockAmount = funds < requiredFunds ? fundDifference : fixedPushAmount;
|
|
203
|
-
|
|
203
|
+
// Size the USD deposit against the REAL Uniswap pool rate (not the fixed
|
|
204
|
+
// $0.10/PC SDK rate) for EVM origins. The pool typically prices PC much
|
|
205
|
+
// higher than $0.10, so pushToUSDC under-provisions and the resulting
|
|
206
|
+
// deposit gets clamped up to the $1 minimum, producing near-zero WPC.
|
|
207
|
+
// When the quoted USD exceeds the $1000 cap the later clamp kicks in
|
|
208
|
+
// (pool limit surfaces via the pre-flight capacity message).
|
|
209
|
+
// Falls back to pushToUSDC if the quoter is unavailable.
|
|
210
|
+
const { vm: sizingOriginVm } = chain_1.CHAIN_INFO[chain];
|
|
211
|
+
let lockAmountInUSD = ctx.pushClient.pushToUSDC(lockAmount);
|
|
212
|
+
if (sizingOriginVm === enums_1.VM.EVM && lockAmount > BigInt(0)) {
|
|
213
|
+
// Target lockAmount × 1.2 so that the 10% slippage margin applied by
|
|
214
|
+
// the pre-flight check (safeUPC = predictedUPC × 0.9) leaves enough
|
|
215
|
+
// headroom even when Uniswap V3 exactOutput↔exactInput quotes aren't
|
|
216
|
+
// perfectly symmetric (tick-math rounding).
|
|
217
|
+
const targetWPC = (lockAmount * BigInt(12)) / BigInt(10);
|
|
218
|
+
const originPrc20ForSizing = (0, helpers_2.getNativePRC20ForChain)(chain, ctx.pushNetwork);
|
|
219
|
+
const requiredNative = yield (0, gas_calculator_1.estimateNativeForDesiredDeposit)(ctx, targetWPC, originPrc20ForSizing);
|
|
220
|
+
if (requiredNative > BigInt(0)) {
|
|
221
|
+
const ethPriceForSizing = yield new price_fetch_1.PriceFetch(ctx.rpcUrls).getPrice(chain);
|
|
222
|
+
if (ethPriceForSizing > BigInt(0)) {
|
|
223
|
+
// requiredNative (18-dec wei) × ethPrice (8-dec USD/ETH) / 1e18 = USD in 8-dec
|
|
224
|
+
const poolBasedUsd = (requiredNative * ethPriceForSizing) / BigInt(1e18);
|
|
225
|
+
(0, context_1.printLog)(ctx, `Fee-lock sizing: pushToUSDC=${lockAmountInUSD.toString()} (fixed $0.10/PC), ` +
|
|
226
|
+
`poolBased=${poolBasedUsd.toString()} (pool quote for ${targetWPC.toString()} WPC) — using poolBased`);
|
|
227
|
+
lockAmountInUSD = poolBasedUsd;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
204
231
|
// Apply minimum deposit override (e.g., Route 2 needs enough UPC for outbound swap)
|
|
205
232
|
const effectiveLockAmountInUSD = execute._minimumDepositUsd && execute._minimumDepositUsd > lockAmountInUSD
|
|
206
233
|
? execute._minimumDepositUsd
|
|
@@ -212,12 +239,12 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
212
239
|
const { vm: originVm } = chain_1.CHAIN_INFO[chain];
|
|
213
240
|
if (originVm === enums_1.VM.EVM) {
|
|
214
241
|
try {
|
|
215
|
-
// Replicate lockFee's USD → native conversion (with its $1–$
|
|
242
|
+
// Replicate lockFee's USD → native conversion (with its $1–$1000 clamp)
|
|
216
243
|
const oneUsd = utils_1.Utils.helpers.parseUnits('1', 8);
|
|
217
|
-
const
|
|
244
|
+
const maxUsd = utils_1.Utils.helpers.parseUnits('1000', 8);
|
|
218
245
|
let depositUsd = effectiveLockAmountInUSD < oneUsd ? oneUsd : effectiveLockAmountInUSD;
|
|
219
|
-
if (depositUsd >
|
|
220
|
-
depositUsd =
|
|
246
|
+
if (depositUsd > maxUsd)
|
|
247
|
+
depositUsd = maxUsd;
|
|
221
248
|
const ethPrice = yield new price_fetch_1.PriceFetch(ctx.rpcUrls).getPrice(chain);
|
|
222
249
|
if (ethPrice > BigInt(0)) {
|
|
223
250
|
const nativeAmountETH = (depositUsd * BigInt(1e18) + (ethPrice - BigInt(1))) / ethPrice + BigInt(1);
|
|
@@ -233,11 +260,32 @@ function executeStandardPayload(ctx, execute, eventBuffer, getResponseCallbacks)
|
|
|
233
260
|
`total: ${totalAvailable.toString()}, required: ${requiredFunds.toString()}`);
|
|
234
261
|
if (totalAvailable < requiredFunds) {
|
|
235
262
|
const shortfall = requiredFunds - totalAvailable;
|
|
263
|
+
// On failure only: probe pool capacity at the max cap so the
|
|
264
|
+
// caller gets a readable "max transferable right now" number.
|
|
265
|
+
// One extra quoter call — not run on the success path.
|
|
266
|
+
let maxTransferableNote = '';
|
|
267
|
+
if (depositUsd < maxUsd) {
|
|
268
|
+
const maxNativeAmountETH = (maxUsd * BigInt(1e18) + (ethPrice - BigInt(1))) / ethPrice + BigInt(1);
|
|
269
|
+
const maxPredictedUPC = yield (0, gas_calculator_1.estimateDepositFromLockedNative)(ctx, maxNativeAmountETH, originPrc20);
|
|
270
|
+
if (maxPredictedUPC > BigInt(0)) {
|
|
271
|
+
const maxSafeUPC = (maxPredictedUPC * BigInt(90)) / BigInt(100);
|
|
272
|
+
const gasReserve = utils_1.Utils.helpers.parseUnits('0.01', 18);
|
|
273
|
+
const maxFromDeposit = maxSafeUPC > gasReserve ? maxSafeUPC - gasReserve : BigInt(0);
|
|
274
|
+
const maxTransferable = funds + maxFromDeposit;
|
|
275
|
+
maxTransferableNote =
|
|
276
|
+
`Max transferable right now (at $1000 cap, pool-limited): ` +
|
|
277
|
+
`~${(Number(maxTransferable) / 1e18).toFixed(4)} $PC ` +
|
|
278
|
+
`(UEA balance ${(Number(funds) / 1e18).toFixed(4)} + ` +
|
|
279
|
+
`pool-safe deposit ${(Number(maxFromDeposit) / 1e18).toFixed(4)} − gas).`;
|
|
280
|
+
(0, context_1.printLog)(ctx, `Fee-lock capacity: ${maxTransferableNote}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
236
283
|
throw new Error(`Insufficient deposit: the fee-lock will deposit ~${(Number(safeUPC) / 1e18).toFixed(4)} $PC ` +
|
|
237
284
|
`but the transaction requires ~${(Number(requiredFunds) / 1e18).toFixed(4)} $PC ` +
|
|
238
285
|
`(shortfall: ~${(Number(shortfall) / 1e18).toFixed(4)} $PC). ` +
|
|
239
|
-
`The fee-lock deposit is capped at $
|
|
240
|
-
|
|
286
|
+
`The fee-lock deposit is capped at $1000 USD. ` +
|
|
287
|
+
(maxTransferableNote ? maxTransferableNote + ' ' : '') +
|
|
288
|
+
`Reduce the transfer value or pre-fund the UEA (${UEA}) on Push Chain.`);
|
|
241
289
|
}
|
|
242
290
|
}
|
|
243
291
|
}
|
|
@@ -45,3 +45,13 @@ export declare function calculateGasAmountFromAmountOutMinETH(ctx: OrchestratorC
|
|
|
45
45
|
* Returns 0 on any failure (caller should fall back to other logic).
|
|
46
46
|
*/
|
|
47
47
|
export declare function estimateDepositFromLockedNative(ctx: OrchestratorContext, nativeAmountForLocker: bigint, prc20Token: `0x${string}`): Promise<bigint>;
|
|
48
|
+
/**
|
|
49
|
+
* Inverse of estimateDepositFromLockedNative: given a desired WPC output,
|
|
50
|
+
* asks the Push Chain Uniswap V3 pool how much native PRC-20 (pETH) input is
|
|
51
|
+
* required to produce exactly that output via QuoterV2.quoteExactOutputSingle.
|
|
52
|
+
*
|
|
53
|
+
* Used to size fee-lock deposits against the real on-chain pool rate instead
|
|
54
|
+
* of the fixed $0.10/PC SDK rate. Returns 0 on any failure (caller should
|
|
55
|
+
* fall back to the fixed-rate sizing).
|
|
56
|
+
*/
|
|
57
|
+
export declare function estimateNativeForDesiredDeposit(ctx: OrchestratorContext, desiredWpc: bigint, prc20Token: `0x${string}`): Promise<bigint>;
|
|
@@ -11,6 +11,7 @@ exports.queryRescueGasFee = queryRescueGasFee;
|
|
|
11
11
|
exports.calculateNativeAmountForDeposit = calculateNativeAmountForDeposit;
|
|
12
12
|
exports.calculateGasAmountFromAmountOutMinETH = calculateGasAmountFromAmountOutMinETH;
|
|
13
13
|
exports.estimateDepositFromLockedNative = estimateDepositFromLockedNative;
|
|
14
|
+
exports.estimateNativeForDesiredDeposit = estimateNativeForDesiredDeposit;
|
|
14
15
|
const tslib_1 = require("tslib");
|
|
15
16
|
const web3_js_1 = require("@solana/web3.js");
|
|
16
17
|
const viem_1 = require("viem");
|
|
@@ -336,13 +337,13 @@ function calculateNativeAmountForDeposit(ctx, chain, requiredFunds, ueaBalance)
|
|
|
336
337
|
var _a, _b;
|
|
337
338
|
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_02_01);
|
|
338
339
|
const oneUsd = utils_1.Utils.helpers.parseUnits('1', 8);
|
|
339
|
-
const
|
|
340
|
+
const maxUsd = utils_1.Utils.helpers.parseUnits('1000', 8);
|
|
340
341
|
const deficit = requiredFunds > ueaBalance ? requiredFunds - ueaBalance : BigInt(0);
|
|
341
342
|
let depositUsd = deficit > BigInt(0) ? ctx.pushClient.pushToUSDC(deficit) : oneUsd;
|
|
342
343
|
if (depositUsd < oneUsd)
|
|
343
344
|
depositUsd = oneUsd;
|
|
344
|
-
if (depositUsd >
|
|
345
|
-
throw new Error('Deposit value exceeds max $
|
|
345
|
+
if (depositUsd > maxUsd)
|
|
346
|
+
throw new Error('Deposit value exceeds max $1000 worth of native token');
|
|
346
347
|
if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM) {
|
|
347
348
|
const svmClient = new svm_client_1.SvmClient({
|
|
348
349
|
rpcUrls: ctx.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
|
|
@@ -515,4 +516,95 @@ function estimateDepositFromLockedNative(ctx, nativeAmountForLocker, prc20Token)
|
|
|
515
516
|
}
|
|
516
517
|
});
|
|
517
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Inverse of estimateDepositFromLockedNative: given a desired WPC output,
|
|
521
|
+
* asks the Push Chain Uniswap V3 pool how much native PRC-20 (pETH) input is
|
|
522
|
+
* required to produce exactly that output via QuoterV2.quoteExactOutputSingle.
|
|
523
|
+
*
|
|
524
|
+
* Used to size fee-lock deposits against the real on-chain pool rate instead
|
|
525
|
+
* of the fixed $0.10/PC SDK rate. Returns 0 on any failure (caller should
|
|
526
|
+
* fall back to the fixed-rate sizing).
|
|
527
|
+
*/
|
|
528
|
+
function estimateNativeForDesiredDeposit(ctx, desiredWpc, prc20Token) {
|
|
529
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
530
|
+
var _a, _b;
|
|
531
|
+
try {
|
|
532
|
+
if (desiredWpc <= BigInt(0))
|
|
533
|
+
return BigInt(0);
|
|
534
|
+
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
535
|
+
const quoterAddress = (_b = (_a = chain_1.CHAIN_INFO[pushChain]) === null || _a === void 0 ? void 0 : _a.dex) === null || _b === void 0 ? void 0 : _b.uniV3QuoterV2;
|
|
536
|
+
if (!quoterAddress || quoterAddress.startsWith('0xTBD'))
|
|
537
|
+
return BigInt(0);
|
|
538
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
539
|
+
const universalCoreAddress = yield ctx.pushClient.readContract({
|
|
540
|
+
address: gatewayPcAddress,
|
|
541
|
+
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
542
|
+
functionName: 'UNIVERSAL_CORE',
|
|
543
|
+
args: [],
|
|
544
|
+
});
|
|
545
|
+
const [wpcAddress, feeTier] = yield Promise.all([
|
|
546
|
+
ctx.pushClient.readContract({
|
|
547
|
+
address: universalCoreAddress,
|
|
548
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
549
|
+
functionName: 'WPC',
|
|
550
|
+
args: [],
|
|
551
|
+
}),
|
|
552
|
+
ctx.pushClient.readContract({
|
|
553
|
+
address: universalCoreAddress,
|
|
554
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
555
|
+
functionName: 'defaultFeeTier',
|
|
556
|
+
args: [prc20Token],
|
|
557
|
+
}),
|
|
558
|
+
]);
|
|
559
|
+
if (!feeTier || !wpcAddress)
|
|
560
|
+
return BigInt(0);
|
|
561
|
+
const QUOTER_ABI = [
|
|
562
|
+
{
|
|
563
|
+
type: 'function',
|
|
564
|
+
name: 'quoteExactOutputSingle',
|
|
565
|
+
inputs: [
|
|
566
|
+
{
|
|
567
|
+
type: 'tuple',
|
|
568
|
+
components: [
|
|
569
|
+
{ name: 'tokenIn', type: 'address' },
|
|
570
|
+
{ name: 'tokenOut', type: 'address' },
|
|
571
|
+
{ name: 'amount', type: 'uint256' },
|
|
572
|
+
{ name: 'fee', type: 'uint24' },
|
|
573
|
+
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
574
|
+
],
|
|
575
|
+
},
|
|
576
|
+
],
|
|
577
|
+
outputs: [
|
|
578
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
579
|
+
{ name: 'sqrtPriceX96After', type: 'uint160' },
|
|
580
|
+
{ name: 'initializedTicksCrossed', type: 'uint32' },
|
|
581
|
+
{ name: 'gasEstimate', type: 'uint256' },
|
|
582
|
+
],
|
|
583
|
+
stateMutability: 'view',
|
|
584
|
+
},
|
|
585
|
+
];
|
|
586
|
+
const result = yield ctx.pushClient.readContract({
|
|
587
|
+
address: quoterAddress,
|
|
588
|
+
abi: QUOTER_ABI,
|
|
589
|
+
functionName: 'quoteExactOutputSingle',
|
|
590
|
+
args: [
|
|
591
|
+
{
|
|
592
|
+
tokenIn: prc20Token,
|
|
593
|
+
tokenOut: wpcAddress,
|
|
594
|
+
amount: desiredWpc,
|
|
595
|
+
fee: feeTier,
|
|
596
|
+
sqrtPriceLimitX96: BigInt(0),
|
|
597
|
+
},
|
|
598
|
+
],
|
|
599
|
+
});
|
|
600
|
+
const amountIn = result[0];
|
|
601
|
+
(0, context_1.printLog)(ctx, `estimateNativeForDesiredDeposit — quote: ${desiredWpc.toString()} WPC ← ${amountIn.toString()} pETH (fee tier: ${feeTier})`);
|
|
602
|
+
return amountIn;
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
(0, context_1.printLog)(ctx, `estimateNativeForDesiredDeposit — failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
606
|
+
return BigInt(0);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
518
610
|
//# sourceMappingURL=gas-calculator.js.map
|
|
@@ -96,10 +96,10 @@ req) {
|
|
|
96
96
|
const nativeTokenUsdPrice = yield new price_fetch_1.PriceFetch(ctx.rpcUrls).getPrice(chain);
|
|
97
97
|
const nativeDecimals = 18;
|
|
98
98
|
const oneUsd = utils_1.Utils.helpers.parseUnits('1', 8);
|
|
99
|
-
const
|
|
99
|
+
const maxUsd = utils_1.Utils.helpers.parseUnits('1000', 8);
|
|
100
100
|
let depositUsd = amount < oneUsd ? oneUsd : amount;
|
|
101
|
-
if (depositUsd >
|
|
102
|
-
depositUsd =
|
|
101
|
+
if (depositUsd > maxUsd)
|
|
102
|
+
depositUsd = maxUsd;
|
|
103
103
|
let nativeAmount = (depositUsd * BigInt(Math.pow(10, nativeDecimals)) +
|
|
104
104
|
(nativeTokenUsdPrice - BigInt(1))) /
|
|
105
105
|
nativeTokenUsdPrice;
|
|
@@ -114,10 +114,10 @@ req) {
|
|
|
114
114
|
]);
|
|
115
115
|
const nativeDecimals = 9;
|
|
116
116
|
const oneUsd = utils_1.Utils.helpers.parseUnits('1', 8);
|
|
117
|
-
const
|
|
117
|
+
const maxUsd = utils_1.Utils.helpers.parseUnits('1000', 8);
|
|
118
118
|
let depositUsd = amount < oneUsd ? oneUsd : amount;
|
|
119
|
-
if (depositUsd >
|
|
120
|
-
depositUsd =
|
|
119
|
+
if (depositUsd > maxUsd)
|
|
120
|
+
depositUsd = maxUsd;
|
|
121
121
|
let nativeAmount = (depositUsd * BigInt(Math.pow(10, nativeDecimals)) +
|
|
122
122
|
(nativeTokenUsdPrice - BigInt(1))) /
|
|
123
123
|
nativeTokenUsdPrice;
|
|
@@ -16,6 +16,8 @@ const viem_1 = require("viem");
|
|
|
16
16
|
const uea_evm_1 = require("../../constants/abi/uea.evm");
|
|
17
17
|
const chain_1 = require("../../constants/chain");
|
|
18
18
|
const enums_1 = require("../../constants/enums");
|
|
19
|
+
const progress_hook_types_1 = require("../../progress-hook/progress-hook.types");
|
|
20
|
+
const progress_hook_1 = tslib_1.__importDefault(require("../../progress-hook/progress-hook"));
|
|
19
21
|
const account_1 = require("../../universal/account/account");
|
|
20
22
|
const push_client_1 = require("../../push-client/push-client");
|
|
21
23
|
const route_detector_1 = require("../route-detector");
|
|
@@ -472,19 +474,40 @@ function transformToUniversalTxResponse(ctx_1, tx_1) {
|
|
|
472
474
|
? (0, route_detector_1.getRouteInfo)(universalTxResponse.route)
|
|
473
475
|
: undefined;
|
|
474
476
|
if (routeInfo === null || routeInfo === void 0 ? void 0 : routeInfo.isOutbound) {
|
|
477
|
+
// Response-level only — NOT routed through ctx.progressHook because
|
|
478
|
+
// the default ui-kit toast lacks icon/hide-timer handling for these
|
|
479
|
+
// events. A follow-up ui-kit PR will add handling and can route
|
|
480
|
+
// through both hooks.
|
|
481
|
+
registeredProgressHook === null || registeredProgressHook === void 0 ? void 0 : registeredProgressHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_08_01]());
|
|
482
|
+
let lastEmittedStatus;
|
|
483
|
+
const outboundTranslator = (event) => {
|
|
484
|
+
if (!registeredProgressHook)
|
|
485
|
+
return;
|
|
486
|
+
if (event.status === 'polling' && lastEmittedStatus !== 'polling') {
|
|
487
|
+
lastEmittedStatus = 'polling';
|
|
488
|
+
registeredProgressHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_08_02](event.elapsed));
|
|
489
|
+
}
|
|
490
|
+
};
|
|
475
491
|
try {
|
|
476
492
|
const outboundDetails = yield callbacks.waitForOutboundTx(tx.hash, {
|
|
477
493
|
initialWaitMs: callbacks.outboundConstants.initialWaitMs,
|
|
478
494
|
pollingIntervalMs: callbacks.outboundConstants.pollingIntervalMs,
|
|
479
495
|
timeout: callbacks.outboundConstants.maxTimeoutMs,
|
|
496
|
+
progressHook: outboundTranslator,
|
|
480
497
|
});
|
|
498
|
+
registeredProgressHook === null || registeredProgressHook === void 0 ? void 0 : registeredProgressHook(progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_03](outboundDetails));
|
|
481
499
|
// Merge external chain details into receipt
|
|
482
500
|
baseReceipt = Object.assign(Object.assign({}, baseReceipt), { externalTxHash: outboundDetails.externalTxHash, externalChain: outboundDetails.destinationChain, externalExplorerUrl: outboundDetails.explorerUrl, externalRecipient: outboundDetails.recipient, externalAmount: outboundDetails.amount, externalAssetAddr: outboundDetails.assetAddr });
|
|
483
501
|
}
|
|
484
502
|
catch (error) {
|
|
503
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
504
|
+
const isTimeout = errMsg.startsWith('Timeout waiting for outbound transaction');
|
|
505
|
+
registeredProgressHook === null || registeredProgressHook === void 0 ? void 0 : registeredProgressHook(isTimeout
|
|
506
|
+
? progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_04](callbacks.outboundConstants.maxTimeoutMs)
|
|
507
|
+
: progress_hook_1.default[progress_hook_types_1.PROGRESS_HOOK.SEND_TX_99_05](errMsg));
|
|
485
508
|
// Outbound polling timed out - return partial receipt (don't throw)
|
|
486
509
|
// Push Chain tx succeeded, external tracking can be retried later
|
|
487
|
-
callbacks.printLog(`[wait] External chain tracking failed: ${
|
|
510
|
+
callbacks.printLog(`[wait] External chain tracking failed: ${errMsg}`);
|
|
488
511
|
}
|
|
489
512
|
}
|
|
490
513
|
return baseReceipt;
|