@pushchain/core 5.1.5-alpha.0 → 5.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/src/lib/constants/abi/index.d.ts +2 -0
- package/src/lib/constants/abi/index.js +6 -1
- package/src/lib/constants/abi/uniswap-v3-router.evm.d.ts +58 -0
- package/src/lib/constants/abi/uniswap-v3-router.evm.js +41 -0
- package/src/lib/constants/abi/wpc.evm.d.ts +24 -0
- package/src/lib/constants/abi/wpc.evm.js +27 -0
- package/src/lib/constants/chain.d.ts +1 -0
- package/src/lib/constants/chain.js +8 -6
- package/src/lib/constants/tokens.js +3 -3
- package/src/lib/generated/uexecutor/v2/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v2/types.js +96 -3
- package/src/lib/orchestrator/internals/cascade.d.ts +1 -1
- package/src/lib/orchestrator/internals/cascade.js +556 -225
- package/src/lib/orchestrator/internals/confirmation.js +60 -15
- package/src/lib/orchestrator/internals/context.d.ts +23 -0
- package/src/lib/orchestrator/internals/context.js +54 -0
- package/src/lib/orchestrator/internals/execute-funds-only.js +47 -21
- package/src/lib/orchestrator/internals/execute-funds-payload.js +53 -31
- package/src/lib/orchestrator/internals/execute-standard.js +137 -26
- package/src/lib/orchestrator/internals/gas-calculator.d.ts +5 -2
- package/src/lib/orchestrator/internals/gas-calculator.js +59 -11
- package/src/lib/orchestrator/internals/gas-usd-sizer.d.ts +53 -0
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +165 -0
- package/src/lib/orchestrator/internals/helpers.js +2 -0
- package/src/lib/orchestrator/internals/inbound-tracker.d.ts +83 -0
- package/src/lib/orchestrator/internals/inbound-tracker.js +322 -0
- package/src/lib/orchestrator/internals/index.d.ts +3 -1
- package/src/lib/orchestrator/internals/index.js +8 -2
- package/src/lib/orchestrator/internals/outbound-sync.d.ts +32 -1
- package/src/lib/orchestrator/internals/outbound-sync.js +154 -17
- package/src/lib/orchestrator/internals/pc-usd-oracle.d.ts +28 -0
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +285 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.d.ts +23 -0
- package/src/lib/orchestrator/internals/progress-route-hooks.js +72 -0
- package/src/lib/orchestrator/internals/push-chain-tx.d.ts +27 -1
- package/src/lib/orchestrator/internals/push-chain-tx.js +111 -15
- package/src/lib/orchestrator/internals/rescue.js +1 -1
- package/src/lib/orchestrator/internals/response-builder.d.ts +5 -0
- package/src/lib/orchestrator/internals/response-builder.js +252 -53
- package/src/lib/orchestrator/internals/route-handlers.js +480 -206
- package/src/lib/orchestrator/internals/tx-transformer.js +293 -35
- package/src/lib/orchestrator/orchestrator.d.ts +7 -1
- package/src/lib/orchestrator/orchestrator.js +108 -56
- package/src/lib/orchestrator/orchestrator.types.d.ts +120 -5
- package/src/lib/orchestrator/payload-builders.d.ts +16 -0
- package/src/lib/orchestrator/payload-builders.js +6 -5
- package/src/lib/orchestrator/route-detector.js +20 -8
- package/src/lib/orchestrator/svm-idl/normalize-address.d.ts +19 -0
- package/src/lib/orchestrator/svm-idl/normalize-address.js +56 -0
- package/src/lib/orchestrator/svm-idl/registry.d.ts +13 -4
- package/src/lib/orchestrator/svm-idl/registry.js +15 -14
- package/src/lib/orchestrator/svm-idl/resolve.js +5 -2
- package/src/lib/progress-hook/progress-hook.d.ts +28 -0
- package/src/lib/progress-hook/progress-hook.js +555 -101
- package/src/lib/progress-hook/progress-hook.types.d.ts +76 -24
- package/src/lib/progress-hook/progress-hook.types.js +74 -29
- package/src/lib/push-client/push-client.d.ts +7 -0
- package/src/lib/push-client/push-client.js +18 -1
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.d.ts +32 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/builders.js +65 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.d.ts +72 -0
- package/src/lib/universal-tx-detector/__tests__/fixtures/scenarios.js +669 -0
- package/src/lib/universal-tx-detector/auto-detect.d.ts +37 -0
- package/src/lib/universal-tx-detector/auto-detect.js +112 -0
- package/src/lib/universal-tx-detector/cascade.d.ts +64 -0
- package/src/lib/universal-tx-detector/cascade.js +254 -0
- package/src/lib/universal-tx-detector/child-inbounds.d.ts +58 -0
- package/src/lib/universal-tx-detector/child-inbounds.js +145 -0
- package/src/lib/universal-tx-detector/classify.d.ts +33 -0
- package/src/lib/universal-tx-detector/classify.js +228 -0
- package/src/lib/universal-tx-detector/detector-svm.d.ts +46 -0
- package/src/lib/universal-tx-detector/detector-svm.js +324 -0
- package/src/lib/universal-tx-detector/detector.d.ts +13 -0
- package/src/lib/universal-tx-detector/detector.js +233 -0
- package/src/lib/universal-tx-detector/events.d.ts +765 -0
- package/src/lib/universal-tx-detector/events.js +241 -0
- package/src/lib/universal-tx-detector/index.d.ts +18 -0
- package/src/lib/universal-tx-detector/index.js +36 -0
- package/src/lib/universal-tx-detector/svm-events.d.ts +41 -0
- package/src/lib/universal-tx-detector/svm-events.js +68 -0
- package/src/lib/universal-tx-detector/types.d.ts +100 -0
- package/src/lib/universal-tx-detector/types.js +3 -0
- package/src/lib/utils.d.ts +30 -13
- package/src/lib/utils.js +47 -21
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { CHAIN } from '../constants/enums';
|
|
2
2
|
/**
|
|
3
3
|
* Chain target for cross-chain routing (Routes 2, 3, 4)
|
|
4
|
-
* When `to` is a ChainTarget, the transaction executes on the specified external chain
|
|
4
|
+
* When `to` is a ChainTarget, the transaction executes on the specified external chain.
|
|
5
|
+
*
|
|
6
|
+
* `address` is typed as `string` because the accepted shape varies by VM:
|
|
7
|
+
* - EVM chains expect a 0x-prefixed 20-byte hex address.
|
|
8
|
+
* - SVM chains (Solana) accept either a base58 32-byte pubkey OR a 0x-prefixed
|
|
9
|
+
* 32-byte hex address; the SDK normalizes base58 to hex internally.
|
|
10
|
+
* Runtime validation happens in the route detector.
|
|
5
11
|
*/
|
|
6
12
|
export type ChainTarget = {
|
|
7
|
-
address:
|
|
13
|
+
address: string;
|
|
8
14
|
chain: CHAIN;
|
|
9
15
|
};
|
|
10
16
|
/**
|
|
@@ -135,13 +141,37 @@ export interface UniversalTxResponse {
|
|
|
135
141
|
maxFeePerGas?: bigint;
|
|
136
142
|
maxPriorityFeePerGas?: bigint;
|
|
137
143
|
accessList: any[];
|
|
138
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Wait for this transaction to reach its final state.
|
|
146
|
+
*
|
|
147
|
+
* For outbound routes (R2 / R3) the resolved receipt also includes external
|
|
148
|
+
* chain details. Pass `options.outboundTimeoutMs` / `options.inboundTimeoutMs`
|
|
149
|
+
* to override the default polling timeouts on a per-call basis — useful for
|
|
150
|
+
* latency-sensitive UIs that want to surface a provisional timeout and retry
|
|
151
|
+
* with a longer budget.
|
|
152
|
+
*
|
|
153
|
+
* When the outbound or inbound leg times out / fails, `.wait()` still
|
|
154
|
+
* resolves with a receipt (no throw); inspect `externalStatus` to classify
|
|
155
|
+
* the outcome.
|
|
156
|
+
*/
|
|
157
|
+
wait: (options?: WaitOptions) => Promise<UniversalTxReceipt>;
|
|
139
158
|
/**
|
|
140
159
|
* Register a progress callback for events during wait().
|
|
141
|
-
* Call this BEFORE calling wait() to receive tracking events
|
|
160
|
+
* Call this BEFORE calling wait() to receive tracking events, including
|
|
161
|
+
* the route-specific external/inbound polling events: R2 emits the 209/299
|
|
162
|
+
* series, R3 emits 309/310/399. Registering after wait() resolves will
|
|
163
|
+
* replay the pre-execution event buffer but miss outbound polling events.
|
|
142
164
|
* @param callback - Function called with each progress event
|
|
143
165
|
*/
|
|
144
166
|
progressHook: (callback: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void) => void;
|
|
167
|
+
/**
|
|
168
|
+
* @internal Register a wait-phase progressHook without replaying buffered
|
|
169
|
+
* events. Used by `trackTransaction()` to auto-attach the caller's per-call
|
|
170
|
+
* progressHook so `tracked.wait()` can deliver wait-phase events (209-xx /
|
|
171
|
+
* 299-xx / 399-xx) to the same callback — without re-emitting the
|
|
172
|
+
* reconstructed execute-phase stream that trackTransaction already fired.
|
|
173
|
+
*/
|
|
174
|
+
_setProgressHookNoReplay?: (callback: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void) => void;
|
|
145
175
|
type: string;
|
|
146
176
|
typeVerbose: string;
|
|
147
177
|
signature: Signature;
|
|
@@ -164,10 +194,66 @@ export interface UniversalTxResponse {
|
|
|
164
194
|
childTxHash?: string;
|
|
165
195
|
/** Transaction route (UOA_TO_PUSH, UOA_TO_CEA, CEA_TO_PUSH, CEA_TO_CEA) */
|
|
166
196
|
route?: TransactionRouteType;
|
|
197
|
+
/**
|
|
198
|
+
* @internal True when this response was produced by `trackTransaction` and
|
|
199
|
+
* its progress events have already been replayed via the registered hook.
|
|
200
|
+
* `wait()` checks this to skip a redundant inner trackTransaction call that
|
|
201
|
+
* would otherwise emit the same reconstructed events a second time when
|
|
202
|
+
* the user does `tracked = trackTransaction(...); tracked.wait()`.
|
|
203
|
+
*/
|
|
204
|
+
_eventsReconstructed?: boolean;
|
|
205
|
+
/**
|
|
206
|
+
* @internal True when the R3 (CEA_TO_PUSH) execution produces a child UTX
|
|
207
|
+
* on Push Chain — i.e., the source-chain CEA payload actually calls
|
|
208
|
+
* `sendUniversalTxToUEA` (funds flowing back to UEA). When false, `.wait()`
|
|
209
|
+
* skips `waitForInboundPushTx` to avoid a 300s timeout on payload-only R3
|
|
210
|
+
* flows that have no inbound leg.
|
|
211
|
+
*/
|
|
212
|
+
_expectsInboundRoundTrip?: boolean;
|
|
167
213
|
}
|
|
168
214
|
/**
|
|
169
215
|
* New Universal Transaction Receipt interface for transaction receipts
|
|
170
216
|
*/
|
|
217
|
+
/**
|
|
218
|
+
* Per-call options accepted by `UniversalTxResponse.wait()`.
|
|
219
|
+
*
|
|
220
|
+
* All fields are optional; omitted values fall back to the orchestrator's
|
|
221
|
+
* defaults (`OUTBOUND_MAX_TIMEOUT_MS`, `INBOUND_MAX_TIMEOUT_MS`).
|
|
222
|
+
*/
|
|
223
|
+
export interface WaitOptions {
|
|
224
|
+
/**
|
|
225
|
+
* Override the outbound polling budget (ms) — applies to R2 / R3 while
|
|
226
|
+
* waiting for the external-chain tx to land via UGPC relay. When exceeded,
|
|
227
|
+
* `wait()` resolves with `externalStatus: 'timeout'` and the progress-hook
|
|
228
|
+
* stream emits `SEND-TX-299-03` (R2) or `SEND-TX-399-03` (R3 inbound).
|
|
229
|
+
*
|
|
230
|
+
* The outbound-sync initial settle-wait is automatically clamped to this
|
|
231
|
+
* timeout, so a 200ms budget will throw in ~200ms rather than blocking for
|
|
232
|
+
* the default 20s.
|
|
233
|
+
*/
|
|
234
|
+
outboundTimeoutMs?: number;
|
|
235
|
+
/**
|
|
236
|
+
* Override the inbound polling budget (ms) — applies to R3 only, for the
|
|
237
|
+
* round-trip Push tx produced by the external CEA. When exceeded,
|
|
238
|
+
* `wait()` resolves with `externalStatus: 'timeout'` and emits
|
|
239
|
+
* `SEND-TX-399-03`.
|
|
240
|
+
*/
|
|
241
|
+
inboundTimeoutMs?: number;
|
|
242
|
+
/**
|
|
243
|
+
* Override the poll interval (ms) between outbound status checks. Default
|
|
244
|
+
* is 5000ms. Lower values give faster feedback on fast relays; higher
|
|
245
|
+
* values reduce RPC pressure. Only applies to R2 / R3 outbound polling.
|
|
246
|
+
*/
|
|
247
|
+
outboundPollingIntervalMs?: number;
|
|
248
|
+
/**
|
|
249
|
+
* Override the initial settle-wait (ms) before the outbound polling loop
|
|
250
|
+
* starts. Default is 20000ms — a buffer for UGPC relay submission latency.
|
|
251
|
+
* Reducing this doesn't affect the timeout budget but may cause earlier
|
|
252
|
+
* polls that miss the relay submission and burn RPC. Rarely needed; prefer
|
|
253
|
+
* `outboundTimeoutMs` which auto-clamps the initial wait.
|
|
254
|
+
*/
|
|
255
|
+
outboundInitialWaitMs?: number;
|
|
256
|
+
}
|
|
171
257
|
export interface UniversalTxReceipt {
|
|
172
258
|
hash: string;
|
|
173
259
|
blockNumber: bigint;
|
|
@@ -202,6 +288,20 @@ export interface UniversalTxReceipt {
|
|
|
202
288
|
externalAmount?: string;
|
|
203
289
|
/** Asset address on external chain */
|
|
204
290
|
externalAssetAddr?: string;
|
|
291
|
+
/**
|
|
292
|
+
* Outcome of the external-chain leg for outbound routes (R2 / R3).
|
|
293
|
+
* - `success`: external tx landed and was confirmed (299-01 fired).
|
|
294
|
+
* - `failed`: external tx reverted or UGPC reported terminal failure (299-02 fired).
|
|
295
|
+
* - `timeout`: UGPC relay timed out before an external tx was observed (299-03 fired).
|
|
296
|
+
* Undefined on non-outbound receipts.
|
|
297
|
+
*/
|
|
298
|
+
externalStatus?: 'success' | 'failed' | 'timeout';
|
|
299
|
+
/** Error message from the external-chain leg when `externalStatus !== 'success'`. */
|
|
300
|
+
externalError?: string;
|
|
301
|
+
/** Push Chain tx hash that closed the R3 round-trip (inbound from CEA). */
|
|
302
|
+
pushInboundTxHash?: string;
|
|
303
|
+
/** Child UTX id that owns the inbound execution. */
|
|
304
|
+
pushInboundUtxId?: string;
|
|
205
305
|
}
|
|
206
306
|
/**
|
|
207
307
|
* Signature interface modeled after ethers.js v6 Signature interface
|
|
@@ -400,6 +500,8 @@ export interface HopDescriptor {
|
|
|
400
500
|
svmPayload?: `0x${string}`;
|
|
401
501
|
/** Whether this hop is a CEA migration (raw MIGRATION_SELECTOR payload) */
|
|
402
502
|
isMigration?: boolean;
|
|
503
|
+
/** SDK 5.2 gas-abstraction sizing decision for this hop. @internal */
|
|
504
|
+
sizing?: import('./internals/gas-usd-sizer').GasSizingDecision;
|
|
403
505
|
}
|
|
404
506
|
/**
|
|
405
507
|
* Segment types for cascade composition
|
|
@@ -434,6 +536,13 @@ export interface CascadeSegment {
|
|
|
434
536
|
gasFee?: bigint;
|
|
435
537
|
/** Gas limit for this segment */
|
|
436
538
|
gasLimit?: bigint;
|
|
539
|
+
/**
|
|
540
|
+
* SDK 5.2 gas-abstraction sizing decision for this segment. When the
|
|
541
|
+
* segment merges multiple hops, the strictest (highest category) sizing
|
|
542
|
+
* among them is taken (C > B > A).
|
|
543
|
+
* @internal
|
|
544
|
+
*/
|
|
545
|
+
sizing?: import('./internals/gas-usd-sizer').GasSizingDecision;
|
|
437
546
|
}
|
|
438
547
|
/**
|
|
439
548
|
* Prepared transaction for inspection before sending
|
|
@@ -515,8 +624,14 @@ export interface CascadeTrackOptions {
|
|
|
515
624
|
pollingIntervalMs?: number;
|
|
516
625
|
/** Total timeout (default: 600000ms = 10 min) */
|
|
517
626
|
timeout?: number;
|
|
518
|
-
/**
|
|
627
|
+
/** Per-hop progress callback */
|
|
519
628
|
progressHook?: (event: CascadeProgressEvent) => void;
|
|
629
|
+
/**
|
|
630
|
+
* Unified ProgressEvent stream for SEND-TX-08/99_03-05 telemetry.
|
|
631
|
+
* Fires per outbound hop during external chain polling. Use alongside
|
|
632
|
+
* `progressHook` — they emit complementary views of the same events.
|
|
633
|
+
*/
|
|
634
|
+
eventHook?: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void;
|
|
520
635
|
}
|
|
521
636
|
/**
|
|
522
637
|
* Progress event emitted during cascade tracking
|
|
@@ -5,6 +5,22 @@ export declare function buildExecuteMulticall({ execute, ueaAddress, logger, }:
|
|
|
5
5
|
ueaAddress: `0x${string}`;
|
|
6
6
|
logger?: (msg: string) => void;
|
|
7
7
|
}): MultiCall[];
|
|
8
|
+
/**
|
|
9
|
+
* Multicall tuple type definition for ABI encoding
|
|
10
|
+
*/
|
|
11
|
+
export declare const MULTICALL_TUPLE_TYPE: {
|
|
12
|
+
readonly type: "tuple[]";
|
|
13
|
+
readonly components: readonly [{
|
|
14
|
+
readonly name: "to";
|
|
15
|
+
readonly type: "address";
|
|
16
|
+
}, {
|
|
17
|
+
readonly name: "value";
|
|
18
|
+
readonly type: "uint256";
|
|
19
|
+
}, {
|
|
20
|
+
readonly name: "data";
|
|
21
|
+
readonly type: "bytes";
|
|
22
|
+
}];
|
|
23
|
+
};
|
|
8
24
|
/**
|
|
9
25
|
* Build CEA multicall payload for outbound transactions
|
|
10
26
|
* Format: UEA_MULTICALL_SELECTOR + abi.encode(Multicall[])
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MULTICALL_TUPLE_TYPE = void 0;
|
|
3
4
|
exports.buildExecuteMulticall = buildExecuteMulticall;
|
|
4
5
|
exports.buildCeaMulticallPayload = buildCeaMulticallPayload;
|
|
5
6
|
exports.buildInboundUniversalPayload = buildInboundUniversalPayload;
|
|
@@ -124,7 +125,7 @@ function buildExecuteMulticall({ execute, ueaAddress, logger, }) {
|
|
|
124
125
|
/**
|
|
125
126
|
* Multicall tuple type definition for ABI encoding
|
|
126
127
|
*/
|
|
127
|
-
|
|
128
|
+
exports.MULTICALL_TUPLE_TYPE = {
|
|
128
129
|
type: 'tuple[]',
|
|
129
130
|
components: [
|
|
130
131
|
{ name: 'to', type: 'address' },
|
|
@@ -148,7 +149,7 @@ function buildCeaMulticallPayload(multicalls) {
|
|
|
148
149
|
return '0x';
|
|
149
150
|
}
|
|
150
151
|
// Encode the multicall array
|
|
151
|
-
const encoded = (0, viem_1.encodeAbiParameters)([MULTICALL_TUPLE_TYPE], [multicalls.map((m) => ({
|
|
152
|
+
const encoded = (0, viem_1.encodeAbiParameters)([exports.MULTICALL_TUPLE_TYPE], [multicalls.map((m) => ({
|
|
152
153
|
to: m.to,
|
|
153
154
|
value: m.value,
|
|
154
155
|
data: m.data,
|
|
@@ -418,11 +419,11 @@ function isZeroAddress(address) {
|
|
|
418
419
|
*/
|
|
419
420
|
function buildOutboundApprovalAndCall(opts) {
|
|
420
421
|
var _a;
|
|
421
|
-
const { prc20Token,
|
|
422
|
+
const { prc20Token, gasFee, gatewayPcAddress, outboundRequest } = opts;
|
|
422
423
|
const multicalls = [];
|
|
423
424
|
// ERC20 approve for burn amount (contract calls transferFrom for PRC20 burn)
|
|
424
425
|
// Reset to 0 first for USDT-style tokens that revert on non-zero to non-zero approve.
|
|
425
|
-
if (burnAmount > BigInt(0) &&
|
|
426
|
+
if (opts.burnAmount > BigInt(0) &&
|
|
426
427
|
prc20Token.toLowerCase() !== selectors_1.ZERO_ADDRESS.toLowerCase()) {
|
|
427
428
|
const approveZeroData = (0, viem_1.encodeFunctionData)({
|
|
428
429
|
abi: erc20_evm_1.ERC20_EVM,
|
|
@@ -432,7 +433,7 @@ function buildOutboundApprovalAndCall(opts) {
|
|
|
432
433
|
const approveData = (0, viem_1.encodeFunctionData)({
|
|
433
434
|
abi: erc20_evm_1.ERC20_EVM,
|
|
434
435
|
functionName: 'approve',
|
|
435
|
-
args: [gatewayPcAddress, burnAmount],
|
|
436
|
+
args: [gatewayPcAddress, opts.burnAmount],
|
|
436
437
|
});
|
|
437
438
|
multicalls.push({
|
|
438
439
|
to: prc20Token,
|
|
@@ -21,6 +21,7 @@ exports.getRouteInfo = getRouteInfo;
|
|
|
21
21
|
const enums_1 = require("../constants/enums");
|
|
22
22
|
const tokens_1 = require("../constants/tokens");
|
|
23
23
|
const payload_builders_1 = require("./payload-builders");
|
|
24
|
+
const normalize_address_1 = require("./svm-idl/normalize-address");
|
|
24
25
|
// ============================================================================
|
|
25
26
|
// Transaction Route Enum
|
|
26
27
|
// ============================================================================
|
|
@@ -253,13 +254,18 @@ function validateRouteParams(params, context) {
|
|
|
253
254
|
throw new RouteValidationError('migration is not supported on SVM chains');
|
|
254
255
|
}
|
|
255
256
|
}
|
|
256
|
-
// Validate funds token symbol is available on target chain (Route 2 outbound)
|
|
257
|
+
// Validate funds token symbol is available on target chain (Route 2 outbound).
|
|
258
|
+
// A PushChainMoveableToken (e.g. pSOL, pETH_BNB) carries a `sourceChain` pointing at
|
|
259
|
+
// the external chain it mirrors — bridging it to that chain is always valid since
|
|
260
|
+
// the target receives the underlying asset (SOL, ETH, etc.).
|
|
257
261
|
if (((_b = params.funds) === null || _b === void 0 ? void 0 : _b.token) && isChainTarget(params.to)) {
|
|
258
262
|
const targetChain = params.to.chain;
|
|
259
263
|
if (!isPushChain(targetChain)) {
|
|
264
|
+
const tokenSourceChain = params.funds.token.sourceChain;
|
|
265
|
+
const isBridgeBack = tokenSourceChain === targetChain;
|
|
260
266
|
const targetTokens = tokens_1.MOVEABLE_TOKENS[targetChain] || [];
|
|
261
267
|
const hasSymbolOnTarget = targetTokens.some(t => t.symbol === params.funds.token.symbol);
|
|
262
|
-
if (!hasSymbolOnTarget) {
|
|
268
|
+
if (!hasSymbolOnTarget && !isBridgeBack) {
|
|
263
269
|
const tokenChain = findTokenChain(params.funds.token);
|
|
264
270
|
const tokenLabel = tokenChain
|
|
265
271
|
? `${chainEnumToName(tokenChain)}.${params.funds.token.symbol}`
|
|
@@ -297,16 +303,22 @@ function validateRouteParams(params, context) {
|
|
|
297
303
|
}
|
|
298
304
|
// Validate address format
|
|
299
305
|
if (isChainTarget(params.to)) {
|
|
300
|
-
if (!params.to.address.startsWith('0x')) {
|
|
301
|
-
throw new RouteValidationError(`Invalid address format: ${params.to.address}`);
|
|
302
|
-
}
|
|
303
|
-
// SVM targets require 32-byte addresses (0x + 64 hex chars)
|
|
304
306
|
if ((0, payload_builders_1.isSvmChain)(params.to.chain)) {
|
|
305
|
-
|
|
307
|
+
// SVM targets accept either base58 (native Solana form) or 0x-prefixed
|
|
308
|
+
// 32-byte hex. Normalize to hex up front so downstream handlers only see
|
|
309
|
+
// the canonical form.
|
|
310
|
+
try {
|
|
311
|
+
params.to.address = (0, normalize_address_1.toSvmHexAddress)(params.to.address);
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
306
314
|
throw new RouteValidationError(`Invalid Solana address format: ${params.to.address}. ` +
|
|
307
|
-
`Expected 32
|
|
315
|
+
`Expected base58 (32-byte pubkey) or 0x-prefixed 32-byte hex. ` +
|
|
316
|
+
`(${err.message})`);
|
|
308
317
|
}
|
|
309
318
|
}
|
|
319
|
+
else if (!params.to.address.startsWith('0x')) {
|
|
320
|
+
throw new RouteValidationError(`Invalid address format: ${params.to.address}`);
|
|
321
|
+
}
|
|
310
322
|
}
|
|
311
323
|
else if (typeof params.to === 'string') {
|
|
312
324
|
if (!params.to.startsWith('0x')) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical internal form of a Solana program / account address.
|
|
3
|
+
* All validation and payload paths key off this `0x`-prefixed 32-byte hex string.
|
|
4
|
+
*/
|
|
5
|
+
export type SvmHexAddress = `0x${string}`;
|
|
6
|
+
/**
|
|
7
|
+
* Normalize an SVM address supplied by an end user to the internal `0x`-prefixed
|
|
8
|
+
* 32-byte hex form. Accepts either:
|
|
9
|
+
* - `0x`-prefixed 64-hex-char string (the internal form), or
|
|
10
|
+
* - base58 string that decodes to exactly 32 bytes (the native Solana form).
|
|
11
|
+
*
|
|
12
|
+
* Throws with a message naming both accepted forms if the input matches neither.
|
|
13
|
+
*/
|
|
14
|
+
export declare function toSvmHexAddress(input: unknown): SvmHexAddress;
|
|
15
|
+
/**
|
|
16
|
+
* Predicate form of {@link toSvmHexAddress} — returns true if the input is a
|
|
17
|
+
* valid SVM address in either accepted form.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isValidSvmAddress(input: unknown): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toSvmHexAddress = toSvmHexAddress;
|
|
4
|
+
exports.isValidSvmAddress = isValidSvmAddress;
|
|
5
|
+
const bs58_1 = require("../../internal/bs58");
|
|
6
|
+
const HEX_FORM = /^0x[0-9a-fA-F]{64}$/;
|
|
7
|
+
/**
|
|
8
|
+
* Normalize an SVM address supplied by an end user to the internal `0x`-prefixed
|
|
9
|
+
* 32-byte hex form. Accepts either:
|
|
10
|
+
* - `0x`-prefixed 64-hex-char string (the internal form), or
|
|
11
|
+
* - base58 string that decodes to exactly 32 bytes (the native Solana form).
|
|
12
|
+
*
|
|
13
|
+
* Throws with a message naming both accepted forms if the input matches neither.
|
|
14
|
+
*/
|
|
15
|
+
function toSvmHexAddress(input) {
|
|
16
|
+
if (typeof input !== 'string' || input.length === 0) {
|
|
17
|
+
throw new Error(`SVM address must be a non-empty string (base58 or 0x-prefixed 32-byte hex), got ${typeof input}`);
|
|
18
|
+
}
|
|
19
|
+
if (input.startsWith('0x')) {
|
|
20
|
+
if (!HEX_FORM.test(input)) {
|
|
21
|
+
throw new Error(`SVM address in hex form must be 0x + 64 hex chars (32 bytes), got '${input}' (length ${input.length})`);
|
|
22
|
+
}
|
|
23
|
+
return input.toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
let decoded;
|
|
26
|
+
try {
|
|
27
|
+
decoded = bs58_1.bs58.decode(input);
|
|
28
|
+
}
|
|
29
|
+
catch (_a) {
|
|
30
|
+
throw new Error(`SVM address '${input}' is not valid base58 and does not start with 0x. ` +
|
|
31
|
+
`Expected base58 (e.g. 'So11111111111111111111111111111111111111112') ` +
|
|
32
|
+
`or 0x-prefixed 32-byte hex.`);
|
|
33
|
+
}
|
|
34
|
+
if (decoded.length !== 32) {
|
|
35
|
+
throw new Error(`SVM address '${input}' decodes to ${decoded.length} bytes; expected 32.`);
|
|
36
|
+
}
|
|
37
|
+
let hex = '0x';
|
|
38
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
39
|
+
hex += decoded[i].toString(16).padStart(2, '0');
|
|
40
|
+
}
|
|
41
|
+
return hex;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Predicate form of {@link toSvmHexAddress} — returns true if the input is a
|
|
45
|
+
* valid SVM address in either accepted form.
|
|
46
|
+
*/
|
|
47
|
+
function isValidSvmAddress(input) {
|
|
48
|
+
try {
|
|
49
|
+
toSvmHexAddress(input);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch (_a) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=normalize-address.js.map
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import type { Idl } from '@coral-xyz/anchor';
|
|
2
|
-
type
|
|
3
|
-
|
|
2
|
+
import { type SvmHexAddress } from './normalize-address';
|
|
3
|
+
/**
|
|
4
|
+
* Register an Anchor IDL so the SDK can resolve accounts, PDAs, and CEA
|
|
5
|
+
* authorities when building SVM gateway payloads.
|
|
6
|
+
*
|
|
7
|
+
* Normal usage never needs this — `PushChain.utils.helpers.encodeTxData`
|
|
8
|
+
* auto-registers the IDL whenever you pass it as `abi`. Use this only when
|
|
9
|
+
* building `data` manually (raw discriminator + Borsh bytes).
|
|
10
|
+
*
|
|
11
|
+
* The program address is pulled from `idl.address` (Anchor ≥ 0.30 spec).
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerIdl(idl: unknown): void;
|
|
4
14
|
export declare function getIdl(programAddress: string): Idl | undefined;
|
|
5
15
|
export declare function getRegisteredIdls(): Array<{
|
|
6
|
-
address:
|
|
16
|
+
address: SvmHexAddress;
|
|
7
17
|
idl: Idl;
|
|
8
18
|
}>;
|
|
9
19
|
export declare function clearRegistry(): void;
|
|
10
|
-
export {};
|
|
@@ -5,26 +5,27 @@ exports.getIdl = getIdl;
|
|
|
5
5
|
exports.getRegisteredIdls = getRegisteredIdls;
|
|
6
6
|
exports.clearRegistry = clearRegistry;
|
|
7
7
|
const ix_encoder_1 = require("./ix-encoder");
|
|
8
|
+
const normalize_address_1 = require("./normalize-address");
|
|
8
9
|
const store = new Map();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function registerIdl(
|
|
20
|
-
const key = normalizeKey(programAddress);
|
|
10
|
+
/**
|
|
11
|
+
* Register an Anchor IDL so the SDK can resolve accounts, PDAs, and CEA
|
|
12
|
+
* authorities when building SVM gateway payloads.
|
|
13
|
+
*
|
|
14
|
+
* Normal usage never needs this — `PushChain.utils.helpers.encodeTxData`
|
|
15
|
+
* auto-registers the IDL whenever you pass it as `abi`. Use this only when
|
|
16
|
+
* building `data` manually (raw discriminator + Borsh bytes).
|
|
17
|
+
*
|
|
18
|
+
* The program address is pulled from `idl.address` (Anchor ≥ 0.30 spec).
|
|
19
|
+
*/
|
|
20
|
+
function registerIdl(idl) {
|
|
21
21
|
if (!(0, ix_encoder_1.isAnchorIdl)(idl)) {
|
|
22
|
-
throw new Error(`registerIdl:
|
|
22
|
+
throw new Error(`registerIdl: input is not a recognized Anchor IDL (missing 'instructions' or 'address')`);
|
|
23
23
|
}
|
|
24
|
+
const key = (0, normalize_address_1.toSvmHexAddress)(idl.address);
|
|
24
25
|
store.set(key, idl);
|
|
25
26
|
}
|
|
26
27
|
function getIdl(programAddress) {
|
|
27
|
-
const key =
|
|
28
|
+
const key = (0, normalize_address_1.toSvmHexAddress)(programAddress);
|
|
28
29
|
return store.get(key);
|
|
29
30
|
}
|
|
30
31
|
function getRegisteredIdls() {
|
|
@@ -16,8 +16,11 @@ function resolveSvmCall(input) {
|
|
|
16
16
|
var _a, _b;
|
|
17
17
|
const idl = (0, registry_1.getIdl)(input.programAddress);
|
|
18
18
|
if (!idl) {
|
|
19
|
-
throw new Error(`resolveSvmCall: no IDL
|
|
20
|
-
`
|
|
19
|
+
throw new Error(`resolveSvmCall: no IDL found for ${input.programAddress}. ` +
|
|
20
|
+
`The SDK auto-registers Anchor IDLs when you call ` +
|
|
21
|
+
`PushChain.utils.helpers.encodeTxData({abi: idl, ...}). ` +
|
|
22
|
+
`If you built 'data' manually, call PushChain.utils.svm.registerIdl(idl) ` +
|
|
23
|
+
`once before prepareTransaction.`);
|
|
21
24
|
}
|
|
22
25
|
if (input.data.length < 8) {
|
|
23
26
|
throw new Error('resolveSvmCall: data must be at least 8 bytes (Anchor discriminator)');
|
|
@@ -1,3 +1,31 @@
|
|
|
1
1
|
import { ProgressEventFunction } from './progress-hook.types';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of the `response` field emitted by `SEND_TX_104_04` (R1),
|
|
4
|
+
* `SEND_TX_204_04` (R2), and `SEND_TX_304_04` (R3). Exported so consumers
|
|
5
|
+
* can read `isUserDecline` without casting through `object`.
|
|
6
|
+
*/
|
|
7
|
+
export interface DeclineHookResponse {
|
|
8
|
+
/** The underlying sign-time error message (decline copy when absent). */
|
|
9
|
+
error: string;
|
|
10
|
+
/** True if the error looks like a real wallet rejection. */
|
|
11
|
+
isUserDecline: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Classify a sign-time error as either a true wallet user-decline
|
|
15
|
+
* (viem `UserRejectedRequestError`, ethers `ACTION_REJECTED`, EIP-1193 4001,
|
|
16
|
+
* or textual "user rejected"/"user denied"/"declined by user") or a generic
|
|
17
|
+
* signature failure (insufficient funds, RPC failure, contract revert
|
|
18
|
+
* during sign, etc.). Shared by SEND_TX_104_04 (R1), SEND_TX_204_04 (R2),
|
|
19
|
+
* and SEND_TX_304_04 (R3) so the heuristic lives in one place.
|
|
20
|
+
*
|
|
21
|
+
* When `errorMessage` is omitted, treat it as a decline — the spec copy is
|
|
22
|
+
* already the decline copy ("Verification declined by user"), so flipping
|
|
23
|
+
* to "Signature Failed" would make the event self-contradict.
|
|
24
|
+
*/
|
|
25
|
+
export declare function classifyDeclineError(errorMessage?: string): {
|
|
26
|
+
isUserDecline: boolean;
|
|
27
|
+
title: string;
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
2
30
|
declare const PROGRESS_HOOKS: Record<string, ProgressEventFunction>;
|
|
3
31
|
export default PROGRESS_HOOKS;
|