@pushchain/core 5.1.4-alpha.9 → 5.1.5-alpha.0

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.
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeAnchorIxData = encodeAnchorIxData;
4
+ exports.isAnchorIdl = isAnchorIdl;
5
+ const anchor_1 = require("@coral-xyz/anchor");
6
+ const web3_js_1 = require("@solana/web3.js");
7
+ const buffer_1 = require("buffer");
8
+ function encodeAnchorIxData(idl, functionName, positionalArgs = []) {
9
+ var _a, _b;
10
+ const ix = findInstruction(idl, functionName);
11
+ 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'}'`);
13
+ }
14
+ if (positionalArgs.length !== ix.args.length) {
15
+ throw new Error(`Arg count mismatch for '${ix.name}': IDL expects ${ix.args.length}, got ${positionalArgs.length}`);
16
+ }
17
+ const named = {};
18
+ for (let i = 0; i < ix.args.length; i++) {
19
+ named[ix.args[i].name] = normalizeArg(positionalArgs[i], ix.args[i]);
20
+ }
21
+ const coder = new anchor_1.BorshInstructionCoder(idl);
22
+ return new Uint8Array(coder.encode(ix.name, named));
23
+ }
24
+ function findInstruction(idl, name) {
25
+ const snake = name.replace(/([A-Z])/g, (_, c) => '_' + c.toLowerCase());
26
+ const camel = name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
27
+ return idl.instructions.find((i) => i.name === name || i.name === snake || i.name === camel);
28
+ }
29
+ function normalizeArg(value, field) {
30
+ if (typeof value === 'bigint') {
31
+ return new anchor_1.BN(value.toString());
32
+ }
33
+ if (field.type === 'pubkey' &&
34
+ typeof value === 'string' &&
35
+ value.startsWith('0x') &&
36
+ value.length === 66) {
37
+ return new web3_js_1.PublicKey(buffer_1.Buffer.from(value.slice(2), 'hex'));
38
+ }
39
+ return value;
40
+ }
41
+ function isAnchorIdl(value) {
42
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
43
+ return false;
44
+ const maybe = value;
45
+ return Array.isArray(maybe['instructions']) && typeof maybe['address'] === 'string';
46
+ }
47
+ //# sourceMappingURL=ix-encoder.js.map
@@ -0,0 +1,10 @@
1
+ import type { Idl } from '@coral-xyz/anchor';
2
+ type AddressKey = `0x${string}`;
3
+ export declare function registerIdl(programAddress: string, idl: unknown): void;
4
+ export declare function getIdl(programAddress: string): Idl | undefined;
5
+ export declare function getRegisteredIdls(): Array<{
6
+ address: AddressKey;
7
+ idl: Idl;
8
+ }>;
9
+ export declare function clearRegistry(): void;
10
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerIdl = registerIdl;
4
+ exports.getIdl = getIdl;
5
+ exports.getRegisteredIdls = getRegisteredIdls;
6
+ exports.clearRegistry = clearRegistry;
7
+ const ix_encoder_1 = require("./ix-encoder");
8
+ const store = new Map();
9
+ function normalizeKey(address) {
10
+ if (typeof address !== 'string' || !address.startsWith('0x')) {
11
+ throw new Error(`registerIdl: programAddress must be 0x-prefixed 32-byte hex, got '${address}'`);
12
+ }
13
+ const body = address.slice(2);
14
+ if (body.length !== 64 || !/^[0-9a-fA-F]+$/.test(body)) {
15
+ throw new Error(`registerIdl: programAddress must be 32 bytes (66 chars incl. 0x), got length ${address.length}`);
16
+ }
17
+ return ('0x' + body.toLowerCase());
18
+ }
19
+ function registerIdl(programAddress, idl) {
20
+ const key = normalizeKey(programAddress);
21
+ if (!(0, ix_encoder_1.isAnchorIdl)(idl)) {
22
+ throw new Error(`registerIdl: idl for ${programAddress} is not a recognized Anchor IDL (missing 'instructions' or 'address')`);
23
+ }
24
+ store.set(key, idl);
25
+ }
26
+ function getIdl(programAddress) {
27
+ const key = normalizeKey(programAddress);
28
+ return store.get(key);
29
+ }
30
+ function getRegisteredIdls() {
31
+ return Array.from(store.entries()).map(([address, idl]) => ({ address, idl }));
32
+ }
33
+ function clearRegistry() {
34
+ store.clear();
35
+ }
36
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,14 @@
1
+ import { CHAIN } from '../../constants/enums';
2
+ import type { SvmGatewayAccountMeta } from '../orchestrator.types';
3
+ export interface ResolveInput {
4
+ programAddress: `0x${string}`;
5
+ data: Uint8Array;
6
+ senderUea: `0x${string}`;
7
+ targetChain: CHAIN;
8
+ }
9
+ export interface ResolvedSvmCall {
10
+ targetProgram: `0x${string}`;
11
+ accounts: SvmGatewayAccountMeta[];
12
+ ixData: Uint8Array;
13
+ }
14
+ export declare function resolveSvmCall(input: ResolveInput): ResolvedSvmCall;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveSvmCall = resolveSvmCall;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const buffer_1 = require("buffer");
6
+ const account_1 = require("../../universal/account/account");
7
+ const registry_1 = require("./registry");
8
+ const CEA_AUTHORITY_NAMES = new Set([
9
+ 'cea_authority',
10
+ 'ceaAuthority',
11
+ 'cea',
12
+ 'cea_signer',
13
+ 'ceaSigner',
14
+ ]);
15
+ function resolveSvmCall(input) {
16
+ var _a, _b;
17
+ const idl = (0, registry_1.getIdl)(input.programAddress);
18
+ if (!idl) {
19
+ throw new Error(`resolveSvmCall: no IDL registered for ${input.programAddress}. ` +
20
+ `Call PushChain.utils.svm.registerIdl(${input.programAddress}, idl) first.`);
21
+ }
22
+ if (input.data.length < 8) {
23
+ throw new Error('resolveSvmCall: data must be at least 8 bytes (Anchor discriminator)');
24
+ }
25
+ const disc = input.data.slice(0, 8);
26
+ const ix = idl.instructions.find((i) => buffer_1.Buffer.from(i.discriminator).equals(buffer_1.Buffer.from(disc)));
27
+ if (!ix) {
28
+ 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(',')}]`);
29
+ }
30
+ const programPk = new web3_js_1.PublicKey(buffer_1.Buffer.from(input.programAddress.slice(2), 'hex'));
31
+ const { address: ceaPdaHex } = (0, account_1.deriveSvmCeaPda)(input.senderUea, input.targetChain, true);
32
+ const accounts = [];
33
+ for (const item of ix.accounts) {
34
+ if ('accounts' in item) {
35
+ throw new Error(`resolveSvmCall: nested account group '${item.name}' in '${ix.name}' not supported`);
36
+ }
37
+ const flat = item;
38
+ const pubkey = resolveAccountPubkey(flat, programPk, ceaPdaHex, ix.name);
39
+ accounts.push({ pubkey, isWritable: Boolean(flat.writable) });
40
+ }
41
+ return {
42
+ targetProgram: input.programAddress,
43
+ accounts,
44
+ ixData: input.data,
45
+ };
46
+ }
47
+ function resolveAccountPubkey(spec, programPk, ceaPdaHex, ixName) {
48
+ if (spec.address) {
49
+ return pkToHex(new web3_js_1.PublicKey(spec.address));
50
+ }
51
+ if (spec.pda) {
52
+ const seeds = resolveConstSeeds(spec.pda.seeds, spec.name, ixName);
53
+ const programForPda = spec.pda.program
54
+ ? new web3_js_1.PublicKey(resolveConstSeedValue(spec.pda.program, spec.name, ixName))
55
+ : programPk;
56
+ const [pda] = web3_js_1.PublicKey.findProgramAddressSync(seeds, programForPda);
57
+ return pkToHex(pda);
58
+ }
59
+ if (CEA_AUTHORITY_NAMES.has(spec.name)) {
60
+ return ceaPdaHex;
61
+ }
62
+ throw new Error(`resolveSvmCall: cannot resolve account '${spec.name}' in '${ixName}'. ` +
63
+ `Add 'address' or 'pda.seeds' to the IDL, or rename to a CEA convention (cea_authority).`);
64
+ }
65
+ function resolveConstSeeds(seeds, accountName, ixName) {
66
+ return seeds.map((seed, idx) => {
67
+ if (seed.kind !== 'const') {
68
+ throw new Error(`resolveSvmCall: non-const PDA seed (kind='${seed.kind}') on account '${accountName}' in '${ixName}' not supported yet`);
69
+ }
70
+ if (!Array.isArray(seed.value)) {
71
+ throw new Error(`resolveSvmCall: const seed at index ${idx} on '${accountName}' is malformed`);
72
+ }
73
+ return buffer_1.Buffer.from(seed.value);
74
+ });
75
+ }
76
+ function resolveConstSeedValue(seed, accountName, ixName) {
77
+ if (seed.kind !== 'const' || !Array.isArray(seed.value)) {
78
+ throw new Error(`resolveSvmCall: only const program-seed supported on '${accountName}' in '${ixName}'`);
79
+ }
80
+ return buffer_1.Buffer.from(seed.value);
81
+ }
82
+ function pkToHex(pk) {
83
+ return ('0x' + buffer_1.Buffer.from(pk.toBytes()).toString('hex'));
84
+ }
85
+ //# sourceMappingURL=resolve.js.map
@@ -396,15 +396,25 @@ class PushChain {
396
396
  */
397
397
  validatedUniversalSigner, (_c = options === null || options === void 0 ? void 0 : options.network) !== null && _c !== void 0 ? _c : enums_1.PUSH_NETWORK.TESTNET_DONUT, (_d = options === null || options === void 0 ? void 0 : options.rpcUrls) !== null && _d !== void 0 ? _d : {}, (_e = options === null || options === void 0 ? void 0 : options.printTraces) !== null && _e !== void 0 ? _e : false, options === null || options === void 0 ? void 0 : options.progressHook);
398
398
  const instance = new _a(orchestrator, validatedUniversalSigner, blockExplorers, isReadOnly);
399
- // Background fetch account status (non-blocking, 30s timeout)
400
- // Stored on instance so consumers can await it if needed: await client.accountStatusReady
399
+ // Background fetch account status (non-blocking, 30s timeout).
400
+ // The timer must be cleared once the race settles — otherwise the
401
+ // unref'd setTimeout keeps the Node event loop alive for the full
402
+ // 30s after the caller's work is done, making scripts appear "stuck".
401
403
  const ACCOUNT_STATUS_TIMEOUT = 30000;
404
+ let accountStatusTimer;
402
405
  instance.accountStatusReady = Promise.race([
403
406
  // eslint-disable-next-line @typescript-eslint/no-empty-function
404
407
  instance.getAccountStatus().then(() => { }),
405
- new Promise((_, reject) => setTimeout(() => reject(new Error('Account status fetch timed out')), ACCOUNT_STATUS_TIMEOUT)),
406
- ]).catch(() => {
408
+ new Promise((_, reject) => {
409
+ accountStatusTimer = setTimeout(() => reject(new Error('Account status fetch timed out')), ACCOUNT_STATUS_TIMEOUT);
410
+ }),
411
+ ])
412
+ .catch(() => {
407
413
  // Silently ignore — lazy check in execute() will retry if needed
414
+ })
415
+ .finally(() => {
416
+ if (accountStatusTimer)
417
+ clearTimeout(accountStatusTimer);
408
418
  });
409
419
  // Let execute() await the background fetch instead of re-fetching
410
420
  orchestrator.accountStatusReadyPromise = instance.accountStatusReady;
@@ -68,6 +68,19 @@ export declare function convertExecutorToOrigin(executorAddress: string, options
68
68
  /** @internal Skip deprecation warning for SDK-internal calls */
69
69
  _internal?: boolean;
70
70
  }): Promise<OriginAccountInfo>;
71
+ /**
72
+ * Derive the SVM CEA (PDA) for a UEA address on a Solana-based chain.
73
+ *
74
+ * Solana doesn't use a CEAFactory contract — instead, the CEA is a
75
+ * Program Derived Address (PDA) with seeds: ["push_identity", ueaBytes]
76
+ * and the SVM gateway program as the program ID.
77
+ *
78
+ * @param ueaAddress - The UEA (or Push EOA) hex address (20 bytes).
79
+ * @param targetChain - The SVM target chain.
80
+ * @param skipNetworkCheck - Whether to skip deployment status check.
81
+ * @returns The derived 32-byte Solana PDA address (as 0x-prefixed hex) and deployment status.
82
+ */
83
+ export declare function deriveSvmCeaPda(ueaAddress: `0x${string}`, targetChain: CHAIN, skipNetworkCheck: boolean): DerivedExecutorAccount;
71
84
  /**
72
85
  * Derive the executor account (UEA or CEA) for a given account.
73
86
  *
@@ -6,6 +6,7 @@ exports.fromChainAgnostic = fromChainAgnostic;
6
6
  exports.convertOriginToExecutor = convertOriginToExecutor;
7
7
  exports.convertExecutorToOriginAccount = convertExecutorToOriginAccount;
8
8
  exports.convertExecutorToOrigin = convertExecutorToOrigin;
9
+ exports.deriveSvmCeaPda = deriveSvmCeaPda;
9
10
  exports.deriveExecutorAccount = deriveExecutorAccount;
10
11
  exports.resolveControllerAccount = resolveControllerAccount;
11
12
  const tslib_1 = require("tslib");
@@ -3,6 +3,7 @@ import { construct, toUniversal as toUniversalSigner, toUniversalFromKeypair } f
3
3
  import { CHAIN, PUSH_NETWORK } from './constants/enums';
4
4
  import { type MoveableToken } from './constants/tokens';
5
5
  import type { PushChain } from './push-chain/push-chain';
6
+ import { registerIdl as registerSvmIdl, getRegisteredIdls as getRegisteredSvmIdls, getIdl as getSvmIdl } from './orchestrator/svm-idl/registry';
6
7
  /**
7
8
  * @dev - THESE UTILS ARE EXPORTED TO SDK CONSUMER
8
9
  * @dev - Make sure each exported fn has good comments to help out sdk consumer
@@ -32,6 +33,24 @@ export declare class Utils {
32
33
  deriveExecutorAccount: typeof deriveExecutorAccount;
33
34
  resolveControllerAccount: typeof resolveControllerAccount;
34
35
  };
36
+ /**
37
+ * SVM (Solana) utilities for registering program Anchor IDLs.
38
+ *
39
+ * Register your program's Anchor IDL once per process; `prepareTransaction`
40
+ * then resolves accounts, PDAs, and signers from the IDL so you only need
41
+ * to pass `data` (discriminator + Borsh args), the same shape used for EVM.
42
+ *
43
+ * @example
44
+ * PushChain.utils.svm.registerIdl(
45
+ * PROGRAM_ADDRESS_HEX,
46
+ * testCounterIdl
47
+ * );
48
+ */
49
+ static svm: {
50
+ registerIdl: typeof registerSvmIdl;
51
+ getRegisteredIdls: typeof getRegisteredSvmIdls;
52
+ getIdl: typeof getSvmIdl;
53
+ };
35
54
  static signer: {
36
55
  /**
37
56
  * Converts various signer types (viem, ethers v6, Solana) into a UniversalSigner.
@@ -98,7 +117,7 @@ export declare class Utils {
98
117
  */
99
118
  getChainName: (chainName: string) => string | undefined;
100
119
  encodeTxData({ abi, functionName, args, }: {
101
- abi: any[];
120
+ abi: any;
102
121
  functionName: string;
103
122
  args?: any[];
104
123
  }): `0x${string}`;
package/src/lib/utils.js CHANGED
@@ -7,6 +7,9 @@ const enums_1 = require("./constants/enums");
7
7
  const tokens_1 = require("./constants/tokens");
8
8
  const chain_1 = require("./constants/chain");
9
9
  const viem_1 = require("viem");
10
+ const buffer_1 = require("buffer");
11
+ const ix_encoder_1 = require("./orchestrator/svm-idl/ix-encoder");
12
+ const registry_1 = require("./orchestrator/svm-idl/registry");
10
13
  /**
11
14
  * @dev - THESE UTILS ARE EXPORTED TO SDK CONSUMER
12
15
  * @dev - Make sure each exported fn has good comments to help out sdk consumer
@@ -74,6 +77,24 @@ Utils.account = {
74
77
  deriveExecutorAccount: account_1.deriveExecutorAccount,
75
78
  resolveControllerAccount: account_1.resolveControllerAccount,
76
79
  };
80
+ /**
81
+ * SVM (Solana) utilities for registering program Anchor IDLs.
82
+ *
83
+ * Register your program's Anchor IDL once per process; `prepareTransaction`
84
+ * then resolves accounts, PDAs, and signers from the IDL so you only need
85
+ * to pass `data` (discriminator + Borsh args), the same shape used for EVM.
86
+ *
87
+ * @example
88
+ * PushChain.utils.svm.registerIdl(
89
+ * PROGRAM_ADDRESS_HEX,
90
+ * testCounterIdl
91
+ * );
92
+ */
93
+ Utils.svm = {
94
+ registerIdl: registry_1.registerIdl,
95
+ getRegisteredIdls: registry_1.getRegisteredIdls,
96
+ getIdl: registry_1.getIdl,
97
+ };
77
98
  Utils.signer = {
78
99
  /**
79
100
  * Converts various signer types (viem, ethers v6, Solana) into a UniversalSigner.
@@ -207,6 +228,13 @@ Utils.helpers = {
207
228
  };
208
229
  })(),
209
230
  encodeTxData({ abi, functionName, args = [], }) {
231
+ if ((0, ix_encoder_1.isAnchorIdl)(abi)) {
232
+ if (!Array.isArray(args)) {
233
+ throw new Error('Arguments must be an array');
234
+ }
235
+ const bytes = (0, ix_encoder_1.encodeAnchorIxData)(abi, functionName, args);
236
+ return `0x${buffer_1.Buffer.from(bytes).toString('hex')}`;
237
+ }
210
238
  // Validate inputs
211
239
  if (!Array.isArray(abi)) {
212
240
  throw new Error('ABI must be an array');