crossx-20-js-core

CROSSx JavaScript Core Skill

Documentation

Dependency

npm install @nexus-cross/crossx-sdk-core

Instructions

Identify the request category first, then make the smallest TypeScript/JavaScript changes that fit the existing project structure.

Treat the CROSSx JavaScript Core documentation linked above as the primary source for SDK usage, integration flow, and sample patterns.

If the bundled docs do not fully answer the question or the latest SDK behavior is unclear, prefer the official cross MCP server before unrelated documentation sources.

File Discovery

Before editing, find the existing integration points for package setup, SDK creation, authentication flow, and wallet-related actions.

Check these first when they exist:

  • package.json (dependency setup)
  • SDK initialization location (entry point, app root, or service file)
  • existing auth, wallet, settings, or blockchain-related integration points

Prefer extending existing integration points over introducing new wrappers or architectural layers.

Request Classification

Classify each request into one or more of these categories before writing code:

  • SDK setup: package install, SDK creation via createCROSSxSDK, SDKConfig options, initialization
  • Authentication: login provider, signIn / signInWithCreate / signInWithJWT / signInAgain, session restore, ensureLoggedIn, sign-out, login checks
  • Wallet: wallet state check, wallet creation (createWallet), address lookup, wallet selection (selectWallet)
  • Signing and transactions: sign message, sign typed data (on-chain vs off-chain), sign transaction, send transaction, wait for receipt
  • RPC and chain access: walletRpc, getBalance, getNonce, getGasPrice, estimateGas, chain info
  • EIP-1193 provider: getProvider, CROSSxEthereumProvider
  • Theme and locale: applyTheme, applyLocale, SDKThemeTokens, SDKColorOverrides

If a request spans multiple categories, handle setup and authentication prerequisites before wallet, signing, transaction, or RPC work.

Key Types Reference

SDKConfig

interface SDKConfig {
  projectId: string;            // required
  appName: string;              // required, shown in signing modals
  locale?: SDKLocale;           // 'en' | 'ko' etc.
  theme?: 'light' | 'dark';    // default: 'light'
  autoDetectTheme?: boolean;    // use prefers-color-scheme
  themeTokens?: SDKThemeTokens;
  receiptPolling?: { intervalMs?: number; timeoutMs?: number };
  migration?: { allowSkip?: boolean };
  showConnectOtherWallets?: boolean;
  useMockWallet?: boolean;      // dev/test only
  logger?: LoggerPort;
  debug?: boolean;
}

AuthResult

interface AuthResult {
  success: boolean;
  address?: string;
  user?: UserInfo;
  error?: string;
  needsMigration?: boolean;
}

interface SignInWithCreateResult extends AuthResult {
  addresses: Array<{ address: string; index: number }>;
}

CROSSxError / ErrorCode

class CROSSxError extends Error {
  code: ErrorCode;
  details?: unknown;
}

enum ErrorCode {
  // Session / Auth
  SESSION_EXPIRED = 'SESSION_EXPIRED',         // requires sign-out and re-login
  AUTH_NOT_INITIALIZED = 'AUTH_NOT_INITIALIZED',
  AUTH_NOT_AUTHENTICATED = 'AUTH_NOT_AUTHENTICATED',
  AUTH_FAILED = 'AUTH_FAILED',
  OAUTH_POPUP_BLOCKED = 'OAUTH_POPUP_BLOCKED',
  USER_REJECTED = 'USER_REJECTED',

  // Wallet
  WALLET_NOT_FOUND = 'WALLET_NOT_FOUND',
  WALLET_ALREADY_EXISTS = 'WALLET_ALREADY_EXISTS',
  WALLET_INCONSISTENT_STATE = 'WALLET_INCONSISTENT_STATE',

  // Signing / Transaction
  SIGN_FAILED = 'SIGN_FAILED',
  TX_FAILED = 'TX_FAILED',
  BROADCAST_FAILED = 'BROADCAST_FAILED',
  TX_INVALID_PARAMS = 'TX_INVALID_PARAMS',

  // Chain
  INVALID_CHAIN = 'INVALID_CHAIN',
  CHAIN_NOT_SUPPORTED = 'CHAIN_NOT_SUPPORTED',
  TYPED_DATA_CHAIN_ID_MISMATCH = 'TYPED_DATA_CHAIN_ID_MISMATCH',

  // PIN
  PIN_NOT_SET = 'PIN_NOT_SET',
  PIN_WRONG = 'PIN_WRONG',
  PIN_LOCKED = 'PIN_LOCKED',
  PIN_CANCELLED = 'PIN_CANCELLED',

  // Network / General
  NETWORK_ERROR = 'NETWORK_ERROR',
  UNKNOWN_ERROR = 'UNKNOWN_ERROR',
  // ... and more
}

SDK Events

interface SDKEventMap {
  authChanged: { isAuthenticated: boolean; address: string | null };
  addressChanged: { address: string | null };
  initialized: void;
  connectExternalWallet: void;
}

sdk.on('authChanged', (event) => { ... });
sdk.on('addressChanged', (event) => { ... });

Chain ID Format

All chain ID parameters use CAIP-2 eip155:<number> format. The SDK exports ChainId constants:

import { ChainId } from '@nexus-cross/crossx-sdk-core';

ChainId.CROSS_MAINNET  // 'eip155:612055'
ChainId.CROSS_TESTNET  // 'eip155:612044'

Core API Signatures

Creation & Initialization

import { createCROSSxSDK } from '@nexus-cross/crossx-sdk-core';

const sdk = createCROSSxSDK(config: SDKConfig): CROSSxSDK;
await sdk.initialize(opts?: { preferredWalletIndex?: number }): Promise<AuthResult | null>;

Authentication

await sdk.signIn(options?: SignInOptions): Promise<AuthResult>;
await sdk.signInWithCreate(options?: SignInOptions): Promise<SignInWithCreateResult>;
await sdk.signInWithJWT(accessToken: string, refreshToken?: string): Promise<AuthResult>;
await sdk.signInWithOAuthToken(firebaseToken: string): Promise<AuthResult>;
await sdk.signInAgain(): Promise<AuthResult>;
await sdk.signOut(): Promise<void>;
sdk.isAuthenticated(): boolean;
await sdk.ensureLoggedIn(): Promise<boolean>;
await sdk.getUserInfo(): Promise<SDKUserInfo>;
sdk.currentAddress: string | null;
sdk.currentUserId: string | null;

Wallet

await sdk.createWallet(): Promise<{ address: string }>;
await sdk.getAddress(index?: number): Promise<{ address: string; index: number } | null>;
await sdk.getAddresses(): Promise<Array<{ address: string; index: number }>>;
await sdk.selectWallet(currentAddress?: string): Promise<{ address: string; index: number } | null>;
await sdk.migrateWallet(pin: string): Promise<MigrateResult>;

Signing

await sdk.signMessage(chainId: string, message: string, opts?: SignOptions): Promise<SignMessageResp>;
await sdk.signTypedData(chainId: string, typedData: unknown, opts?: SignOptions): Promise<SignTypedDataResp>;
await sdk.signTypedDataOffchain(typedData: unknown, opts?: SignOptions): Promise<SignTypedDataResp>;

Transactions

await sdk.signTransaction(chainId: string, tx: EvmTransactionRequest, opts?: SignOptions): Promise<SignTxResp>;
await sdk.sendTransaction(chainId: string, tx: EvmTransactionRequest, opts?: SignOptions): Promise<SendTxResp>;
await sdk.sendTransactionWithWaitForReceipt(chainId: string, tx: EvmTransactionRequest, opts?: SignOptions): Promise<TransactionReceipt>;
await sdk.getTransactionReceipt(txHash: string, chainId: string): Promise<TransactionReceipt | null>;
await sdk.waitForTxAndGetReceipt(txHash: string, chainId: string): Promise<TransactionReceipt>;

RPC (read-only)

await sdk.walletRpc(method: string, params: any[], chainId: string): Promise<any>;
await sdk.getBalance(chainId: string): Promise<{ wei: string; formatted: string; chainId: string }>;
await sdk.getNonce(chainId: string): Promise<number>;
await sdk.getGasPrice(chainId: string): Promise<string>;
await sdk.estimateGas(tx: EvmTransactionRequest, chainId: string): Promise<string>;
await sdk.getBaseFeePerGas(chainId: string): Promise<string | null>;
await sdk.getMaxPriorityFeePerGas(chainId: string): Promise<string>;

Chain Info

await sdk.getChains(): Promise<ChainInfo[]>;
await sdk.getChain(chainId: string): Promise<ChainInfo>;

EIP-1193 Provider

const provider = sdk.getProvider(chainId: string): CROSSxEthereumProvider;
// Standard EIP-1193 interface
const balance = await provider.request({ method: 'eth_getBalance', params: [address, 'latest'] });

Theme / Locale

sdk.applyTheme(themeMode?: 'light' | 'dark', themeTokens?: SDKThemeTokens): void;
sdk.applyLocale(locale?: SDKLocale): void;

PIN

sdk.setPin(pin: string): void;
await sdk.changePin(oldPin: string, newPin: string): Promise<void>;

Code Examples

SDK Setup and Initialization

import { createCROSSxSDK, ChainId } from '@nexus-cross/crossx-sdk-core';

const sdk = createCROSSxSDK({
  projectId: 'YOUR_PROJECT_ID',
  appName: 'My DApp',
  theme: 'light',
  autoDetectTheme: true,
});

// Restore session on page load
const restored = await sdk.initialize();
if (restored) {
  console.log('Session restored, address:', restored.address);
}

Sign In and Wallet Setup

try {
  // One-step: sign in + wallet creation
  const result = await sdk.signInWithCreate();
  console.log('Address:', result.address);

  // Or two-step
  const authResult = await sdk.signIn();
  if (authResult.needsMigration) {
    await sdk.createWallet();
  }
  const addr = await sdk.getAddress();
} catch (err) {
  if (err instanceof CROSSxError && err.code === ErrorCode.SESSION_EXPIRED) {
    await sdk.signOut();
    // redirect to login
  }
}

JWT Authentication (Server-Side Auth)

const result = await sdk.signInWithJWT(serverAccessToken, serverRefreshToken);

Send Transaction

import { ChainId } from '@nexus-cross/crossx-sdk-core';

const receipt = await sdk.sendTransactionWithWaitForReceipt(
  ChainId.CROSS_MAINNET,
  {
    to: '0xReceiverAddress',
    value: '0xDE0B6B3A7640000', // 1 CROSS in wei
    gasLimit: '0x5208',
  }
);
console.log('TX Hash:', receipt.transactionHash);

RPC Read

const balance = await sdk.getBalance(ChainId.CROSS_MAINNET);
console.log('Balance:', balance.formatted, 'CROSS');

const gasPrice = await sdk.getGasPrice(ChainId.CROSS_MAINNET);
const nonce = await sdk.getNonce(ChainId.CROSS_MAINNET);

EIP-1193 Provider

const provider = sdk.getProvider(ChainId.CROSS_MAINNET);
const blockNumber = await provider.request({ method: 'eth_blockNumber', params: [] });

Preconditions

Confirm the required setup before implementing a feature.

  • SDK setup requires a real projectId and appName provided by the user or already present in project configuration.
  • initialize() must be called on page/app load before any other SDK operations; it attempts to restore a stored session.
  • Authentication work requires a valid session flow; use ensureLoggedIn() to verify before protected actions.
  • Use signInWithCreate() to combine sign-in and wallet setup in a single call. For sign-in only, use signIn().
  • After signIn(), wallet-dependent flows may still require wallet creation. Check result.needsMigration and call createWallet() if needed.
  • For apps with server-side auth, use signInWithJWT(accessToken, refreshToken?) instead of OAuth.
  • Wallet and RPC work require a valid login state and the correct CAIP-2 chain ID (eip155:<number>).
  • Use signTypedDataOffchain() when the typed data has no domain.chainId; use signTypedData(chainId, ...) when it does.

Guardrails

  • Do not assume authentication is complete unless initialize() and session flow are wired correctly.
  • Do not use wallet or RPC features as the default path before confirming login state.
  • Do not use walletRpc for transaction signing or sending — it is read-only (eth_call, eth_getBalance, etc.).
  • Do not introduce signTypedData when the typed data is off-chain (missing domain.chainId) — use signTypedDataOffchain instead.
  • Do not add new wrappers or architectural layers when the feature can fit existing integration points.
  • Do not guess unclear SDK behavior when the latest documentation or MCP resources should be checked first.
  • Do not generate fallback values such as empty strings, crossx, my-app, or sample IDs for projectId.
  • If projectId or appName is missing, ask the user for them before writing SDK setup code.

Implementation Workflow

  1. Identify the feature category and the affected files.
  2. Inspect the existing project structure before making changes.
  3. Confirm the required setup before adding feature code.
  4. Apply the smallest code change that fits the existing architecture and style.
  5. Use the correct SDK APIs, CAIP-2 chain IDs, and parameter requirements.
  6. Review the affected files for integration gaps before finalizing.

Validation Checklist

Before finalizing CROSSx JavaScript SDK changes, verify the following:

  • The change matches the requested feature scope without unnecessary refactoring.
  • projectId and appName are present in SDKConfig.
  • initialize() is called on page/app load before other SDK operations.
  • Authentication, wallet, and RPC flows satisfy login and session requirements.
  • After signIn(), confirm a wallet exists for wallet-dependent flows; use createWallet() if needed. Or use signInWithCreate() for one-step login + wallet setup.
  • Chain-aware APIs use CAIP-2 eip155:<number> format for chainId or ChainId constants.
  • Transaction sign/send calls include tx.to and tx.value or tx.data as appropriate.
  • walletRpc is only used for read-only call scenarios.
  • On-chain vs off-chain typed data uses the correct signing method.
  • Errors are handled: check err.code === ErrorCode.SESSION_EXPIRED for session recovery.

© 2025 NEXUS Co., Ltd. All Rights Reserved.