crossx-20-js-core
CROSSx JavaScript Core Skill
Documentation
Dependency
npm install @nexus-cross/crossx-sdk-coreInstructions
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,SDKConfigoptions, 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
projectIdandappNameprovided 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, usesignIn(). - After
signIn(), wallet-dependent flows may still require wallet creation. Checkresult.needsMigrationand callcreateWallet()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 nodomain.chainId; usesignTypedData(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
walletRpcfor transaction signing or sending — it is read-only (eth_call,eth_getBalance, etc.). - Do not introduce
signTypedDatawhen the typed data is off-chain (missingdomain.chainId) — usesignTypedDataOffchaininstead. - 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 forprojectId. - If
projectIdorappNameis missing, ask the user for them before writing SDK setup code.
Implementation Workflow
- Identify the feature category and the affected files.
- Inspect the existing project structure before making changes.
- Confirm the required setup before adding feature code.
- Apply the smallest code change that fits the existing architecture and style.
- Use the correct SDK APIs, CAIP-2 chain IDs, and parameter requirements.
- 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.
projectIdandappNameare present inSDKConfig.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; usecreateWallet()if needed. Or usesignInWithCreate()for one-step login + wallet setup. - Chain-aware APIs use CAIP-2
eip155:<number>format forchainIdorChainIdconstants. - Transaction sign/send calls include
tx.toandtx.valueortx.dataas appropriate. walletRpcis 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_EXPIREDfor session recovery.
Updated about 20 hours ago