@pushchain/core 6.0.20 → 6.0.21

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.
Files changed (111) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/package.json +1 -1
  3. package/src/lib/cache/cache.js +2 -0
  4. package/src/lib/constants/abi/index.d.ts +1 -0
  5. package/src/lib/constants/abi/index.js +8 -1
  6. package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
  7. package/src/lib/constants/abi/pc20.evm.js +150 -0
  8. package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
  9. package/src/lib/constants/abi/prc20.evm.js +97 -0
  10. package/src/lib/constants/abi/universalGatewayV0.json +1 -1
  11. package/src/lib/constants/chain.js +38 -8
  12. package/src/lib/constants/selectors.js +2 -2
  13. package/src/lib/constants/tokens.js +4 -3
  14. package/src/lib/formatters.js +16 -6
  15. package/src/lib/generated/uexecutor/v1/query.js +2 -4
  16. package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
  17. package/src/lib/generated/uexecutor/v1/types.js +90 -47
  18. package/src/lib/generated/uexecutor/v2/query.js +2 -4
  19. package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
  20. package/src/lib/generated/uexecutor/v2/types.js +49 -33
  21. package/src/lib/generated/v1/tx.js +30 -37
  22. package/src/lib/index.d.ts +3 -0
  23. package/src/lib/index.js +21 -3
  24. package/src/lib/internal/buffer.js +1 -2
  25. package/src/lib/orchestrator/cea-utils.js +73 -83
  26. package/src/lib/orchestrator/internals/account-manager.js +130 -139
  27. package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
  28. package/src/lib/orchestrator/internals/cascade.js +1184 -1059
  29. package/src/lib/orchestrator/internals/confirmation.js +138 -148
  30. package/src/lib/orchestrator/internals/error-decoder.js +1 -1
  31. package/src/lib/orchestrator/internals/errors.js +12 -3
  32. package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
  33. package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
  34. package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
  35. package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
  36. package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
  37. package/src/lib/orchestrator/internals/execute-standard.js +339 -342
  38. package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
  39. package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
  40. package/src/lib/orchestrator/internals/gateway-client.js +102 -103
  41. package/src/lib/orchestrator/internals/helpers.js +30 -27
  42. package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
  43. package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
  44. package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
  45. package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
  46. package/src/lib/orchestrator/internals/payload-builder.js +119 -100
  47. package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
  48. package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
  49. package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
  50. package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
  51. package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
  52. package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
  53. package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
  54. package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
  55. package/src/lib/orchestrator/internals/pc20/export.js +412 -0
  56. package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
  57. package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
  58. package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
  59. package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
  60. package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
  61. package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
  62. package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
  63. package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
  64. package/src/lib/orchestrator/internals/preflight.js +1 -1
  65. package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
  66. package/src/lib/orchestrator/internals/push-chain-tx.js +319 -329
  67. package/src/lib/orchestrator/internals/quote.js +90 -94
  68. package/src/lib/orchestrator/internals/rescue.js +76 -79
  69. package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
  70. package/src/lib/orchestrator/internals/response-builder.js +817 -701
  71. package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
  72. package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
  73. package/src/lib/orchestrator/internals/signing.js +78 -83
  74. package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
  75. package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
  76. package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
  77. package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
  78. package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
  79. package/src/lib/orchestrator/internals/svm-rent.js +163 -141
  80. package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
  81. package/src/lib/orchestrator/internals/uea-manager.js +89 -86
  82. package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
  83. package/src/lib/orchestrator/orchestrator.js +217 -200
  84. package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
  85. package/src/lib/orchestrator/orchestrator.types.js +19 -0
  86. package/src/lib/orchestrator/payload-builders.d.ts +2 -2
  87. package/src/lib/orchestrator/payload-builders.js +26 -24
  88. package/src/lib/orchestrator/route-detector.js +26 -9
  89. package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
  90. package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
  91. package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
  92. package/src/lib/price-fetch/price-fetch.js +67 -68
  93. package/src/lib/progress-hook/progress-hook.js +124 -72
  94. package/src/lib/push-chain/push-chain.js +171 -153
  95. package/src/lib/push-client/push-client.js +223 -237
  96. package/src/lib/universal/account/account.js +349 -365
  97. package/src/lib/universal/signer/signer.js +306 -294
  98. package/src/lib/universal-tx-detector/auto-detect.js +55 -60
  99. package/src/lib/universal-tx-detector/cascade.js +160 -172
  100. package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
  101. package/src/lib/universal-tx-detector/classify.js +2 -3
  102. package/src/lib/universal-tx-detector/detector-svm.js +139 -147
  103. package/src/lib/universal-tx-detector/detector.js +145 -157
  104. package/src/lib/universal-tx-detector/normalize.js +7 -7
  105. package/src/lib/utils/external-tx-hash.js +1 -2
  106. package/src/lib/utils.d.ts +44 -0
  107. package/src/lib/utils.js +762 -683
  108. package/src/lib/vm-client/evm-client.js +186 -202
  109. package/src/lib/vm-client/svm-client.d.ts +1 -1
  110. package/src/lib/vm-client/svm-client.js +220 -224
  111. package/src/lib/vm-client/vm-client.types.d.ts +14 -2
@@ -13,6 +13,126 @@ export type ChainTarget = {
13
13
  address: string;
14
14
  chain: CHAIN;
15
15
  };
16
+ /**
17
+ * A dynamic PC20 token, identified by chain and address alone.
18
+ *
19
+ * PC20 mappings live in UniversalCore's on-chain registry, not in the SDK's
20
+ * static token tables, so there is nothing to look a symbol up in — identity is
21
+ * address-and-chain, always.
22
+ *
23
+ * `chain` is where the token *is*, never where it is going:
24
+ * - external wrapper → Push: the external chain the wrapper is deployed on
25
+ * - Push → external: the Push chain the canonical token lives on
26
+ * `to.chain` is the destination and is a separate field.
27
+ *
28
+ * The canonical form is `{ chain, address }` — nothing else. Discrimination
29
+ * from `MoveableToken` relies on what a PC20 reference does NOT have:
30
+ * `MoveableToken` requires `symbol` and `mechanism`, so their absence is the
31
+ * discriminator (see {@link isPC20Reference}, the single predicate). This
32
+ * stays sound even if `MoveableToken` grows optional fields, because the
33
+ * check keys on its required ones.
34
+ *
35
+ * Do NOT add `symbol` to a PC20 reference — a present `symbol` makes the
36
+ * object a `MoveableToken` and routes it down the static-table path (the
37
+ * route validator names this mistake explicitly when it happens).
38
+ */
39
+ export type PC20TokenReference = {
40
+ chain: CHAIN;
41
+ /** Chain-native: checksummed hex on EVM, base58 on Solana. */
42
+ address: string;
43
+ };
44
+ /**
45
+ * Token accepted by `funds.token`.
46
+ *
47
+ * `MoveableToken` continues through the PRC20/native path unchanged;
48
+ * `PC20TokenReference` routes through the registry resolver.
49
+ */
50
+ export type FundsToken = import('../constants').MoveableToken | PC20TokenReference;
51
+ /**
52
+ * The single runtime discriminator for {@link FundsToken}.
53
+ *
54
+ * Every module must use this rather than re-deriving the check by inspecting
55
+ * fields — a second copy is how the two branches drift apart.
56
+ */
57
+ export declare function isPC20Reference(token: FundsToken | undefined): token is PC20TokenReference;
58
+ /**
59
+ * `ExecuteParams` after the PC20 gate has run.
60
+ *
61
+ * The public `funds.token` accepts either a `MoveableToken` or a
62
+ * `PC20TokenReference`. The legacy PRC20/native execution path only ever
63
+ * handles the former, so it types against this narrowed shape and a single
64
+ * gate (`resolveFundsToken` in the orchestrator) decides which branch a
65
+ * transaction takes.
66
+ *
67
+ * Narrowing here rather than at each of the ~24 `execute.funds!.token.symbol`
68
+ * call sites keeps the existing path provably untouched: if a PC20 reference
69
+ * ever reached it, that would be a type error, not a runtime `undefined`.
70
+ *
71
+ * Phase 2 adds the PC20 branch alongside this; it does not widen this type.
72
+ */
73
+ export type LegacyExecuteParams = Omit<ExecuteParams, 'funds'> & {
74
+ funds?: {
75
+ amount: bigint;
76
+ token?: InternalFundsToken;
77
+ };
78
+ /**
79
+ * Set by the PC20 gate when `funds.token` was a `PC20TokenReference`.
80
+ * Authoritative for every PC20 behavioral decision — the `funds.token` view
81
+ * above only carries the display/encoding fields the shared path reads.
82
+ */
83
+ _pc20?: import('./internals/pc20/resolver').ResolvedPC20;
84
+ };
85
+ /**
86
+ * Internal view of a funds token inside the execution path.
87
+ *
88
+ * A PC20 gets a `'pc20-burn'` mechanism rather than being flattened into a fake
89
+ * `MoveableToken`. The distinction matters at three points, and a fake would be
90
+ * wrong at all of them:
91
+ * - `'approve'` would make the SDK approve a wrapper that the gateway's
92
+ * factory burns directly via `burnFrom` — an approval that is never used.
93
+ * - `'native'` would attach the bridge amount as msg.value.
94
+ * - the Push-side transfer must target the resolved PC20, not
95
+ * `getPRC20Address`.
96
+ */
97
+ export type InternalFundsToken = import('../constants').MoveableToken | {
98
+ symbol: string;
99
+ decimals: number;
100
+ address: string;
101
+ mechanism: 'pc20-burn';
102
+ };
103
+ /**
104
+ * One known address of a PC20 token — an external wrapper deployment, or the
105
+ * canonical Push-native token itself.
106
+ *
107
+ * Shape matches `getMoveableTokens`' entries (`chain` + `chainName`) so both
108
+ * token APIs read the same way.
109
+ */
110
+ export type PC20RegistryEntry = {
111
+ /** Chain-native: checksummed hex on EVM, base58 on Solana. */
112
+ address: string;
113
+ /** CAIP-2 chain id, e.g. `'eip155:11155111'`. */
114
+ chain: CHAIN;
115
+ /** Human-readable chain key, e.g. `'ETHEREUM_SEPOLIA'`. */
116
+ chainName: string;
117
+ };
118
+ /** Result of `PushChain.utils.tokens.getPC20Address`. */
119
+ export type PC20AddressResult = {
120
+ /** Canonical Push-native PC20 address. */
121
+ address: `0x${string}`;
122
+ name: string;
123
+ symbol: string;
124
+ decimals: number;
125
+ network: import('../constants/enums').PUSH_NETWORK;
126
+ /**
127
+ * Every confirmed address for this token: external wrapper deployments in
128
+ * SDK chain order, then the Push-native entry last.
129
+ *
130
+ * Confirmed only. A predicted first-export wrapper address never appears
131
+ * here — that stays internal to the outbound builder, because publishing an
132
+ * address that does not exist yet invites callers to send to it.
133
+ */
134
+ registry: PC20RegistryEntry[];
135
+ };
16
136
  /**
17
137
  * Source chain for CEA-originated transactions (Routes 3, 4)
18
138
  * Specifies which CEA domain submits the transaction
@@ -126,7 +246,7 @@ export type ExecuteParams = {
126
246
  */
127
247
  funds?: {
128
248
  amount: bigint;
129
- token?: import('../constants').MoveableToken;
249
+ token?: FundsToken;
130
250
  };
131
251
  /**
132
252
  * Internal: Pre-fetched UEA status to avoid redundant RPC calls.
@@ -1,6 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPC20Reference = isPC20Reference;
3
4
  exports.parseUEAVersion = parseUEAVersion;
5
+ /**
6
+ * The single runtime discriminator for {@link FundsToken}.
7
+ *
8
+ * Every module must use this rather than re-deriving the check by inspecting
9
+ * fields — a second copy is how the two branches drift apart.
10
+ */
11
+ function isPC20Reference(token) {
12
+ if (!token)
13
+ return false;
14
+ const candidate = token;
15
+ // chain + address, and none of MoveableToken's required fields. Keying on
16
+ // the ABSENCE of required MoveableToken fields keeps this sound even if
17
+ // MoveableToken grows optional fields later.
18
+ return (typeof candidate.chain === 'string' &&
19
+ typeof candidate.address === 'string' &&
20
+ candidate.symbol === undefined &&
21
+ candidate.mechanism === undefined);
22
+ }
4
23
  // ============================================================================
5
24
  // UEA Version Utilities
6
25
  // ============================================================================
@@ -1,7 +1,7 @@
1
1
  import { CHAIN } from '../constants/enums';
2
- import type { ExecuteParams, MultiCall, UniversalOutboundTxRequest, SvmExecutePayloadFields } from './orchestrator.types';
2
+ import type { LegacyExecuteParams, MultiCall, UniversalOutboundTxRequest, SvmExecutePayloadFields } from './orchestrator.types';
3
3
  export declare function buildExecuteMulticall({ execute, ueaAddress, logger, allowSelfValueCall, }: {
4
- execute: ExecuteParams;
4
+ execute: LegacyExecuteParams;
5
5
  ueaAddress: `0x${string}`;
6
6
  logger?: (msg: string) => void;
7
7
  allowSelfValueCall?: boolean;
@@ -30,23 +30,22 @@ const data_utils_1 = require("./data-utils");
30
30
  const tx_1 = require("../generated/v1/tx");
31
31
  const signing_1 = require("./internals/signing");
32
32
  function buildExecuteMulticall({ execute, ueaAddress, logger, allowSelfValueCall = false, }) {
33
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
34
- const log = (msg) => logger === null || logger === void 0 ? void 0 : logger(msg);
33
+ const log = (msg) => logger?.(msg);
35
34
  const hasData = (0, data_utils_1.hasExecutablePayloadData)(execute.data);
36
35
  log('buildExecuteMulticall — input: ' + JSON.stringify({
37
36
  to: execute.to,
38
- value: (_b = (_a = execute.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : 'undefined',
37
+ value: execute.value?.toString() ?? 'undefined',
39
38
  data: execute.data ? (Array.isArray(execute.data) ? `Array(${execute.data.length})` : execute.data.slice(0, 20) + '...') : 'undefined',
40
39
  hasData,
41
- fundsAmount: (_e = (_d = (_c = execute.funds) === null || _c === void 0 ? void 0 : _c.amount) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : 'undefined',
42
- fundsTokenSymbol: (_h = (_g = (_f = execute.funds) === null || _f === void 0 ? void 0 : _f.token) === null || _g === void 0 ? void 0 : _g.symbol) !== null && _h !== void 0 ? _h : 'undefined',
43
- fundsTokenMechanism: (_l = (_k = (_j = execute.funds) === null || _j === void 0 ? void 0 : _j.token) === null || _k === void 0 ? void 0 : _k.mechanism) !== null && _l !== void 0 ? _l : 'undefined',
40
+ fundsAmount: execute.funds?.amount?.toString() ?? 'undefined',
41
+ fundsTokenSymbol: execute.funds?.token?.symbol ?? 'undefined',
42
+ fundsTokenMechanism: execute.funds?.token?.mechanism ?? 'undefined',
44
43
  ueaAddress,
45
44
  }, null, 2));
46
45
  const multicallData = [];
47
46
  // *** We will pass the value alongside with the data in a single message now ***
48
47
  const branch1 = !hasData && execute.value;
49
- log(`buildExecuteMulticall — Branch 1 (!data && value): ${branch1} | !hasData: ${!hasData} | execute.value: ${(_o = (_m = execute.value) === null || _m === void 0 ? void 0 : _m.toString()) !== null && _o !== void 0 ? _o : 'undefined'}`);
48
+ log(`buildExecuteMulticall — Branch 1 (!data && value): ${branch1} | !hasData: ${!hasData} | execute.value: ${execute.value?.toString() ?? 'undefined'}`);
50
49
  if (!hasData && execute.value) {
51
50
  const isValueToSelf = execute.to.toLowerCase() === ueaAddress.toLowerCase();
52
51
  if (isValueToSelf && !allowSelfValueCall) {
@@ -61,7 +60,7 @@ function buildExecuteMulticall({ execute, ueaAddress, logger, allowSelfValueCall
61
60
  log(`buildExecuteMulticall — Branch 1 ENTERED: pushed native value transfer to ${execute.to}`);
62
61
  }
63
62
  }
64
- if ((_p = execute.funds) === null || _p === void 0 ? void 0 : _p.amount) {
63
+ if (execute.funds?.amount) {
65
64
  const token = execute.funds.token;
66
65
  const isArrayMulticall = Array.isArray(execute.data) && execute.data.length > 0;
67
66
  const isNative = token.mechanism === 'native';
@@ -80,9 +79,16 @@ function buildExecuteMulticall({ execute, ueaAddress, logger, allowSelfValueCall
80
79
  const erc20Transfer = (0, viem_1.encodeFunctionData)({
81
80
  abi: erc20_evm_1.ERC20_EVM,
82
81
  functionName: 'transfer',
83
- args: [execute.to, (_q = execute.funds) === null || _q === void 0 ? void 0 : _q.amount],
82
+ args: [execute.to, execute.funds?.amount],
84
83
  });
85
- const { address: pushChainTo } = push_chain_1.PushChain.utils.tokens.getPRC20Address(token);
84
+ // A PC20 unlocks as its canonical Push-native token, which the resolver
85
+ // already established. `getPRC20Address` must not run for it — there is
86
+ // no static synthetic mapping to look up, and the symbol carries no
87
+ // authority.
88
+ const pc20 = execute._pc20;
89
+ const pushChainTo = pc20
90
+ ? pc20.pushAddress
91
+ : push_chain_1.PushChain.utils.tokens.getPRC20Address(token).address;
86
92
  multicallData.push({
87
93
  to: pushChainTo,
88
94
  value: BigInt(0),
@@ -181,7 +187,6 @@ function buildCeaMulticallPayload(multicalls) {
181
187
  * @returns ABI-encoded UniversalPayload struct
182
188
  */
183
189
  function buildInboundUniversalPayload(multicallData, opts) {
184
- var _a, _b, _c;
185
190
  return (0, viem_1.encodeAbiParameters)([
186
191
  {
187
192
  type: 'tuple',
@@ -202,11 +207,11 @@ function buildInboundUniversalPayload(multicallData, opts) {
202
207
  to: selectors_1.ZERO_ADDRESS,
203
208
  value: BigInt(0),
204
209
  data: multicallData,
205
- gasLimit: (_a = opts === null || opts === void 0 ? void 0 : opts.gasLimit) !== null && _a !== void 0 ? _a : BigInt(10e7),
210
+ gasLimit: opts?.gasLimit ?? BigInt(10e7),
206
211
  maxFeePerGas: BigInt(1e10),
207
212
  maxPriorityFeePerGas: BigInt(0),
208
- nonce: (_b = opts === null || opts === void 0 ? void 0 : opts.nonce) !== null && _b !== void 0 ? _b : BigInt(0),
209
- deadline: (_c = opts === null || opts === void 0 ? void 0 : opts.deadline) !== null && _c !== void 0 ? _c : BigInt(9999999999),
213
+ nonce: opts?.nonce ?? BigInt(0),
214
+ deadline: opts?.deadline ?? BigInt(9999999999),
210
215
  vType: 1, // universalTxVerification
211
216
  },
212
217
  ]);
@@ -218,16 +223,15 @@ function buildInboundUniversalPayload(multicallData, opts) {
218
223
  * DecodeUniversalPayloadSolana, not the EVM ABI decoder used for EVM origins.
219
224
  */
220
225
  function buildInboundUniversalPayloadSvm(multicallData, opts) {
221
- var _a, _b, _c;
222
226
  const payload = {
223
227
  to: selectors_1.ZERO_ADDRESS,
224
228
  value: BigInt(0).toString(),
225
229
  data: multicallData,
226
- gasLimit: ((_a = opts === null || opts === void 0 ? void 0 : opts.gasLimit) !== null && _a !== void 0 ? _a : BigInt(100000000)).toString(),
227
- maxFeePerGas: BigInt(10000000000).toString(),
230
+ gasLimit: (opts?.gasLimit ?? BigInt(100_000_000)).toString(),
231
+ maxFeePerGas: BigInt(10_000_000_000).toString(),
228
232
  maxPriorityFeePerGas: BigInt(0).toString(),
229
- nonce: ((_b = opts === null || opts === void 0 ? void 0 : opts.nonce) !== null && _b !== void 0 ? _b : BigInt(0)).toString(),
230
- deadline: ((_c = opts === null || opts === void 0 ? void 0 : opts.deadline) !== null && _c !== void 0 ? _c : BigInt(9999999999)).toString(),
233
+ nonce: (opts?.nonce ?? BigInt(0)).toString(),
234
+ deadline: (opts?.deadline ?? BigInt(9_999_999_999)).toString(),
231
235
  vType: tx_1.VerificationType.universalTxVerification,
232
236
  };
233
237
  return `0x${(0, signing_1.encodeUniversalPayloadSvm)(payload).toString('hex')}`;
@@ -355,7 +359,6 @@ function buildMigrationPayload() {
355
359
  * @returns Array of MultiCall operations (approvals + outbound call)
356
360
  */
357
361
  function buildOutboundApprovalAndCall(opts) {
358
- var _a;
359
362
  const { prc20Token, gasFee, gatewayPcAddress, outboundRequest } = opts;
360
363
  const multicalls = [];
361
364
  // ERC20 approve for burn amount (contract calls transferFrom for PRC20 burn)
@@ -390,7 +393,7 @@ function buildOutboundApprovalAndCall(opts) {
390
393
  args: [outboundRequest],
391
394
  });
392
395
  // Use pre-computed nativeValueForGas (from Uniswap quoter) or fallback to 5x gasFee
393
- const nativeValue = (_a = opts.nativeValueForGas) !== null && _a !== void 0 ? _a : (gasFee * BigInt(5));
396
+ const nativeValue = opts.nativeValueForGas ?? (gasFee * BigInt(5));
394
397
  multicalls.push({
395
398
  to: gatewayPcAddress,
396
399
  value: nativeValue,
@@ -405,8 +408,7 @@ function buildOutboundApprovalAndCall(opts) {
405
408
  * Check if a chain targets the SVM (Solana) virtual machine
406
409
  */
407
410
  function isSvmChain(chain) {
408
- var _a;
409
- return ((_a = chain_1.CHAIN_INFO[chain]) === null || _a === void 0 ? void 0 : _a.vm) === enums_1.VM.SVM;
411
+ return chain_1.CHAIN_INFO[chain]?.vm === enums_1.VM.SVM;
410
412
  }
411
413
  /**
412
414
  * Validate a Solana address in 0x-prefixed hex format.
@@ -528,7 +530,7 @@ function encodeSvmCeaToUeaPayload({ gatewayProgramHex, drainAmount, tokenMintHex
528
530
  const amountView = new DataView(amountBuf.buffer);
529
531
  amountView.setBigUint64(0, drainAmount, true); // LE
530
532
  // Extra payload (Vec<u8>: u32 LE length + bytes)
531
- const payloadData = extraPayload !== null && extraPayload !== void 0 ? extraPayload : new Uint8Array(0);
533
+ const payloadData = extraPayload ?? new Uint8Array(0);
532
534
  const payloadLenBuf = new Uint8Array(4);
533
535
  const payloadLenView = new DataView(payloadLenBuf.buffer);
534
536
  payloadLenView.setUint32(0, payloadData.length, true); // LE
@@ -20,6 +20,7 @@ exports.validateRouteParams = validateRouteParams;
20
20
  exports.getRouteInfo = getRouteInfo;
21
21
  const enums_1 = require("../constants/enums");
22
22
  const tokens_1 = require("../constants/tokens");
23
+ const orchestrator_types_1 = require("./orchestrator.types");
23
24
  const payload_builders_1 = require("./payload-builders");
24
25
  const data_utils_1 = require("./data-utils");
25
26
  const normalize_address_1 = require("./svm-idl/normalize-address");
@@ -57,6 +58,7 @@ exports.RouteValidationError = RouteValidationError;
57
58
  * Error thrown when a chain is not supported for CEA operations
58
59
  */
59
60
  class ChainNotSupportedError extends Error {
61
+ chain;
60
62
  constructor(chain) {
61
63
  super(`Chain ${chain} is not supported for CEA operations`);
62
64
  this.chain = chain;
@@ -128,7 +130,7 @@ function chainEnumToName(chain) {
128
130
  */
129
131
  function findTokenChain(token) {
130
132
  for (const [chain, tokens] of Object.entries(tokens_1.MOVEABLE_TOKENS)) {
131
- if (tokens === null || tokens === void 0 ? void 0 : tokens.some(t => t.address.toLowerCase() === token.address.toLowerCase() && t.symbol === token.symbol)) {
133
+ if (tokens?.some(t => t.address.toLowerCase() === token.address.toLowerCase() && t.symbol === token.symbol)) {
132
134
  return chain;
133
135
  }
134
136
  }
@@ -166,8 +168,7 @@ function isChainTarget(to) {
166
168
  * @throws RouteValidationError if parameters are invalid
167
169
  */
168
170
  function detectRoute(params) {
169
- var _a;
170
- const hasFromChain = ((_a = params.from) === null || _a === void 0 ? void 0 : _a.chain) !== undefined;
171
+ const hasFromChain = params.from?.chain !== undefined;
171
172
  const toIsChainTarget = isChainTarget(params.to);
172
173
  // Case 1: No from.chain, to is simple string → Route 1 (UOA → Push)
173
174
  if (!hasFromChain && !toIsChainTarget) {
@@ -213,10 +214,9 @@ function detectRoute(params) {
213
214
  * @throws ChainNotSupportedError if chain is not supported
214
215
  */
215
216
  function validateRouteParams(params, context) {
216
- var _a, _b, _c;
217
217
  const route = detectRoute(params);
218
218
  // Validate from.chain is supported external chain (Routes 3, 4)
219
- if ((_a = params.from) === null || _a === void 0 ? void 0 : _a.chain) {
219
+ if (params.from?.chain) {
220
220
  if (!isSupportedExternalChain(params.from.chain)) {
221
221
  throw new ChainNotSupportedError(params.from.chain);
222
222
  }
@@ -261,9 +261,18 @@ function validateRouteParams(params, context) {
261
261
  // - Route 3/4 (CEA_TO_PUSH, CEA_TO_CEA): validate against from.chain.
262
262
  // For a Push-registered PRC-20 the token's own `sourceChain` must match; for a
263
263
  // non-Push token, the token's symbol must be registered on the chain.
264
- if ((_b = params.funds) === null || _b === void 0 ? void 0 : _b.token) {
264
+ // PC20 funds skip the moveable-token validation (and only that — the address
265
+ // checks below still run). The static table is symbol-keyed and PC20 identity
266
+ // is never symbol-based; the PC20 gate validates chain ownership against the
267
+ // live registry, which is strictly stronger than anything this block can
268
+ // check. Two shapes qualify: an unresolved `PC20TokenReference`
269
+ // (validateRouteParams can run before the gate, e.g. in prepareTransaction)
270
+ // and the gate's resolved output (`_pc20` descriptor present).
271
+ const isPc20Funds = params._pc20 !== undefined ||
272
+ (0, orchestrator_types_1.isPC20Reference)(params.funds?.token);
273
+ if (params.funds?.token && !isPc20Funds) {
265
274
  const token = params.funds.token;
266
- const clientLabel = (context === null || context === void 0 ? void 0 : context.clientChain)
275
+ const clientLabel = context?.clientChain
267
276
  ? chainEnumToName(context.clientChain)
268
277
  : 'unknown';
269
278
  const registeredOn = findTokenChain(token);
@@ -278,7 +287,8 @@ function validateRouteParams(params, context) {
278
287
  ? (tokens_1.MOVEABLE_TOKENS[registeredOn] || []).find(t => t.address.toLowerCase() === token.address.toLowerCase() &&
279
288
  t.symbol === token.symbol)
280
289
  : undefined;
281
- const effectiveSourceChain = (_c = token.sourceChain) !== null && _c !== void 0 ? _c : registrySourceChain === null || registrySourceChain === void 0 ? void 0 : registrySourceChain.sourceChain;
290
+ const effectiveSourceChain = token.sourceChain ??
291
+ registrySourceChain?.sourceChain;
282
292
  const validateAgainst = (chain, direction) => {
283
293
  if (isPushChain(chain))
284
294
  return;
@@ -286,10 +296,17 @@ function validateRouteParams(params, context) {
286
296
  ? effectiveSourceChain === chain
287
297
  : (tokens_1.MOVEABLE_TOKENS[chain] || []).some(t => t.symbol === token.symbol);
288
298
  if (!ok) {
299
+ // A PC20 reference is { chain, address } ONLY. If a caller added a
300
+ // symbol to one, it classified as a MoveableToken and landed here —
301
+ // say so instead of leaving them to puzzle over the static table.
302
+ const pc20Hint = 'chain' in token
303
+ ? '\nIf this is a PC20 token, pass { chain, address } only — no symbol or mechanism.'
304
+ : '';
289
305
  throw new RouteValidationError(`Unsupported moveable token for current client and route:\n` +
290
306
  `token=${tokenLabel}\n` +
291
307
  `clientChain=${clientLabel}\n` +
292
- `${direction}=${chainEnumToName(chain)}`);
308
+ `${direction}=${chainEnumToName(chain)}` +
309
+ pc20Hint);
293
310
  }
294
311
  };
295
312
  switch (route) {
@@ -6,10 +6,9 @@ const anchor_1 = require("@coral-xyz/anchor");
6
6
  const web3_js_1 = require("@solana/web3.js");
7
7
  const buffer_1 = require("buffer");
8
8
  function encodeAnchorIxData(idl, functionName, positionalArgs = []) {
9
- var _a, _b;
10
9
  const ix = findInstruction(idl, functionName);
11
10
  if (!ix) {
12
- throw new Error(`Instruction '${functionName}' not found in IDL '${(_b = (_a = idl.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'unknown'}'`);
11
+ throw new Error(`Instruction '${functionName}' not found in IDL '${idl.metadata?.name ?? 'unknown'}'`);
13
12
  }
14
13
  if (positionalArgs.length !== ix.args.length) {
15
14
  throw new Error(`Arg count mismatch for '${ix.name}': IDL expects ${ix.args.length}, got ${positionalArgs.length}`);
@@ -26,7 +26,7 @@ function toSvmHexAddress(input) {
26
26
  try {
27
27
  decoded = bs58_1.bs58.decode(input);
28
28
  }
29
- catch (_a) {
29
+ catch {
30
30
  throw new Error(`SVM address '${input}' is not valid base58 and does not start with 0x. ` +
31
31
  `Expected base58 (e.g. 'So11111111111111111111111111111111111111112') ` +
32
32
  `or 0x-prefixed 32-byte hex.`);
@@ -49,7 +49,7 @@ function isValidSvmAddress(input) {
49
49
  toSvmHexAddress(input);
50
50
  return true;
51
51
  }
52
- catch (_a) {
52
+ catch {
53
53
  return false;
54
54
  }
55
55
  }
@@ -13,7 +13,6 @@ const CEA_AUTHORITY_NAMES = new Set([
13
13
  'ceaSigner',
14
14
  ]);
15
15
  function resolveSvmCall(input) {
16
- var _a, _b;
17
16
  const idl = (0, registry_1.getIdl)(input.programAddress);
18
17
  if (!idl) {
19
18
  throw new Error(`resolveSvmCall: no IDL found for ${input.programAddress}. ` +
@@ -28,7 +27,7 @@ function resolveSvmCall(input) {
28
27
  const disc = input.data.slice(0, 8);
29
28
  const ix = idl.instructions.find((i) => buffer_1.Buffer.from(i.discriminator).equals(buffer_1.Buffer.from(disc)));
30
29
  if (!ix) {
31
- throw new Error(`resolveSvmCall: no instruction in IDL '${(_b = (_a = idl.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : idl.address}' matches discriminator [${Array.from(disc).join(',')}]`);
30
+ throw new Error(`resolveSvmCall: no instruction in IDL '${idl.metadata?.name ?? idl.address}' matches discriminator [${Array.from(disc).join(',')}]`);
32
31
  }
33
32
  const programPk = new web3_js_1.PublicKey(buffer_1.Buffer.from(input.programAddress.slice(2), 'hex'));
34
33
  const { address: ceaPdaHex } = (0, account_1.deriveSvmCeaPda)(input.senderUea, input.targetChain, true);
@@ -13,84 +13,83 @@ const web3_js_2 = require("@solana/web3.js");
13
13
  const anchor_2 = require("@coral-xyz/anchor");
14
14
  // Module-level price cache — survives across PriceFetch instances.
15
15
  // Chainlink feeds update every 1-2h or on 0.5% price move; 30s TTL is safe.
16
- const PRICE_CACHE_TTL_MS = 30000;
16
+ const PRICE_CACHE_TTL_MS = 30_000;
17
17
  const priceCache = new Map();
18
18
  class PriceFetch {
19
+ rpcUrls;
19
20
  constructor(rpcUrls = {}) {
20
21
  this.rpcUrls = rpcUrls;
21
22
  }
22
- getPrice(chain) {
23
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
24
- const cached = priceCache.get(chain);
25
- if (cached && Date.now() < cached.expiry) {
26
- return cached.price;
23
+ async getPrice(chain) {
24
+ const cached = priceCache.get(chain);
25
+ if (cached && Date.now() < cached.expiry) {
26
+ return cached.price;
27
+ }
28
+ const rpcUrls = this.rpcUrls[chain] || chain_1.CHAIN_INFO[chain].defaultRPC;
29
+ const vm = chain_1.CHAIN_INFO[chain].vm;
30
+ const { lockerContract } = chain_1.CHAIN_INFO[chain];
31
+ if (!lockerContract) {
32
+ throw new Error(`Locker contract not configured for chain: ${chain}`);
33
+ }
34
+ let price;
35
+ switch (vm) {
36
+ case enums_1.VM.EVM: {
37
+ const evmClient = new evm_client_1.EvmClient({ rpcUrls });
38
+ const result = await evmClient.readContract({
39
+ abi: feeLocker_evm_1.FEE_LOCKER_EVM,
40
+ address: lockerContract,
41
+ functionName: 'getEthUsdPrice',
42
+ });
43
+ // getEthUsdPrice returns price scaled to 1e18 and the chainlink feed decimals.
44
+ // Downstream lockFee math expects the price in 8 decimals, so scale down from 1e18 to 1e8.
45
+ const [price1e18] = result;
46
+ price = price1e18 / BigInt(10 ** 10); // 1e18 -> 1e8
47
+ break;
27
48
  }
28
- const rpcUrls = this.rpcUrls[chain] || chain_1.CHAIN_INFO[chain].defaultRPC;
29
- const vm = chain_1.CHAIN_INFO[chain].vm;
30
- const { lockerContract } = chain_1.CHAIN_INFO[chain];
31
- if (!lockerContract) {
32
- throw new Error(`Locker contract not configured for chain: ${chain}`);
33
- }
34
- let price;
35
- switch (vm) {
36
- case enums_1.VM.EVM: {
37
- const evmClient = new evm_client_1.EvmClient({ rpcUrls });
38
- const result = yield evmClient.readContract({
39
- abi: feeLocker_evm_1.FEE_LOCKER_EVM,
40
- address: lockerContract,
41
- functionName: 'getEthUsdPrice',
42
- });
43
- // getEthUsdPrice returns price scaled to 1e18 and the chainlink feed decimals.
44
- // Downstream lockFee math expects the price in 8 decimals, so scale down from 1e18 to 1e8.
45
- const [price1e18] = result;
46
- price = price1e18 / BigInt(Math.pow(10, 10)); // 1e18 -> 1e8
47
- break;
49
+ case enums_1.VM.SVM: {
50
+ const PRICE_ACCOUNT = new web3_js_2.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
51
+ const connection = new web3_js_1.Connection(rpcUrls[0], 'confirmed');
52
+ const provider = new anchor_2.AnchorProvider(connection, {
53
+ publicKey: new web3_js_2.PublicKey('EfQYRThwBu4MsU7Lf3D2e68tCtdwfYj6f66ot1e2HNrq'),
54
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ }, { commitment: 'confirmed' });
56
+ const program = new anchor_1.Program(feeLocker_json_1.default, provider);
57
+ let result;
58
+ try {
59
+ result = await program.methods['getSolPrice']()
60
+ .accounts({
61
+ priceUpdate: PRICE_ACCOUNT,
62
+ })
63
+ .view();
48
64
  }
49
- case enums_1.VM.SVM: {
50
- const PRICE_ACCOUNT = new web3_js_2.PublicKey('7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE');
51
- const connection = new web3_js_1.Connection(rpcUrls[0], 'confirmed');
52
- const provider = new anchor_2.AnchorProvider(connection, {
53
- publicKey: new web3_js_2.PublicKey('EfQYRThwBu4MsU7Lf3D2e68tCtdwfYj6f66ot1e2HNrq'),
54
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
- }, { commitment: 'confirmed' });
56
- const program = new anchor_1.Program(feeLocker_json_1.default, provider);
57
- let result;
58
- try {
59
- result = yield program.methods['getSolPrice']()
60
- .accounts({
61
- priceUpdate: PRICE_ACCOUNT,
62
- })
63
- .view();
64
- }
65
- catch (err) {
66
- const e = err;
67
- console.error('[price-fetch][SVM getSolPrice] FAILED');
68
- console.error(' rpc:', rpcUrls[0]);
69
- console.error(' locker:', lockerContract);
70
- console.error(' priceAccount:', PRICE_ACCOUNT.toBase58());
71
- console.error(' message:', e === null || e === void 0 ? void 0 : e.message);
72
- if (e === null || e === void 0 ? void 0 : e.logs)
73
- console.error(' logs:', e.logs);
74
- if (e === null || e === void 0 ? void 0 : e.simulationResponse)
75
- console.error(' simulationResponse:', JSON.stringify(e.simulationResponse, null, 2));
76
- if (e === null || e === void 0 ? void 0 : e.programErrorStack)
77
- console.error(' programErrorStack:', e.programErrorStack);
78
- throw err;
79
- }
80
- if (!result || !result.price) {
81
- throw new Error('Invalid price data returned');
82
- }
83
- // Exponent on this function is always NEGATIVE
84
- price = BigInt(result.price.toNumber());
85
- break;
65
+ catch (err) {
66
+ const e = err;
67
+ console.error('[price-fetch][SVM getSolPrice] FAILED');
68
+ console.error(' rpc:', rpcUrls[0]);
69
+ console.error(' locker:', lockerContract);
70
+ console.error(' priceAccount:', PRICE_ACCOUNT.toBase58());
71
+ console.error(' message:', e?.message);
72
+ if (e?.logs)
73
+ console.error(' logs:', e.logs);
74
+ if (e?.simulationResponse)
75
+ console.error(' simulationResponse:', JSON.stringify(e.simulationResponse, null, 2));
76
+ if (e?.programErrorStack)
77
+ console.error(' programErrorStack:', e.programErrorStack);
78
+ throw err;
86
79
  }
87
- default: {
88
- throw new Error(`Unsupported VM ${vm}`);
80
+ if (!result || !result.price) {
81
+ throw new Error('Invalid price data returned');
89
82
  }
83
+ // Exponent on this function is always NEGATIVE
84
+ price = BigInt(result.price.toNumber());
85
+ break;
86
+ }
87
+ default: {
88
+ throw new Error(`Unsupported VM ${vm}`);
90
89
  }
91
- priceCache.set(chain, { price, expiry: Date.now() + PRICE_CACHE_TTL_MS });
92
- return price;
93
- });
90
+ }
91
+ priceCache.set(chain, { price, expiry: Date.now() + PRICE_CACHE_TTL_MS });
92
+ return price;
94
93
  }
95
94
  }
96
95
  exports.PriceFetch = PriceFetch;