@nexus-cross/crossx-sdk-core
v1.0.9
Published
CROSSx Core SDK - Vanilla JavaScript Embedded Wallet SDK
Maintainers
Readme
@nexus-cross/crossx-sdk-core
CROSSx Embedded Wallet SDK — Built on Clean Architecture + Hexagonal Architecture
Features
- EIP-1193 Provider: Direct integration with ethers.js / viem / wagmi
- Clean Architecture: Separation of pure business logic and implementation
- Environment Independent: Supports Web / Node / React Native
- Port & Adapters: Swap implementations without modifying core code
- CAIP-2: Standard chain ID format (
eip155:612044) - Transaction Confirmation Modal: User approval required before signing/sending (cannot be bypassed)
Installation
npm install @nexus-cross/crossx-sdk-coreQuick Start
import { createCROSSxSDK, ChainId } from '@nexus-cross/crossx-sdk-core';
const sdk = createCROSSxSDK({
receiptPolling: { intervalMs: 2000, timeoutMs: 60000 }, // optional
});
await sdk.init();
const result = await sdk.signIn();
console.log('Wallet address:', sdk.getAddress());Backend URLs are configured via
VITE_*environment variables in.env. Do not add URL fields toSDKConfigor pass them directly.
API Reference
Initialization & Authentication
// Initialize SDK (includes automatic session restoration)
await sdk.init();
// Sign in (OAuth popup)
const result = await sdk.signIn();
const result = await sdk.signIn({ provider: 'google' });
// Check authentication status
sdk.isAuthenticated(); // boolean
sdk.getAddress(); // string | null
// Sign out
await sdk.signOut();Wallet
// Create wallet (when no wallet exists after sign-in)
const { address } = await sdk.createWallet();
// Get native balance
const { wei, formatted } = await sdk.getBalance('eip155:612044');
console.log(formatted); // "1.234567 CROSS"
// Get current nonce
const nonce = await sdk.getNonce('eip155:612044');Transaction Confirmation Modal
When calling signTransaction() / sendTransaction() / sendTransactionAndWait(), the SDK automatically displays a user approval modal. There is no public API for DApp developers to bypass this.
import { CROSSxError, ErrorCode } from '@nexus-cross/crossx-sdk-core';
try {
const result = await sdk.signTransaction(ChainId.CROSS_TESTNET, tx);
} catch (error) {
if (error instanceof CROSSxError && error.code === ErrorCode.USER_REJECTED) {
console.log('User cancelled the transaction');
}
}For more details → Transaction Confirmation Modal Guide
Sign & Send Transactions
const tx = {
from: sdk.getAddress()!,
to: '0x...',
value: '0x2386f26fc10000',
data: '0x',
chainId: 612044,
gasLimit: '0x5208',
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x3b9aca00',
nonce: await sdk.getNonce('eip155:612044'),
};
// Sign only
const { signedTx, txHash } = await sdk.signTransaction('eip155:612044', tx);
// Send (returns immediately with status: 'pending')
const { txHash } = await sdk.sendTransaction('eip155:612044', tx);
// Send + Poll receipt (waits until included in block)
const { txHash, receipt } = await sdk.sendTransactionAndWait('eip155:612044', tx);
console.log(receipt.status); // '0x1' = success, '0x0' = revertedReceipt Query & Polling
// Single query (returns null if not yet mined)
const receipt = await sdk.getTransactionReceipt(txHash, 'eip155:612044');
// Poll until mined
const receipt = await sdk.waitForTransaction(txHash, 'eip155:612044');
// Override polling options
const receipt = await sdk.waitForTransaction(txHash, 'eip155:612044', {
intervalMs: 3000,
timeoutMs: 120000,
});EIP-1193 Provider
Standard Provider for integration with ethers.js, viem, wagmi, and more.
const provider = sdk.getProvider('eip155:612044');
// ethers.js
import { ethers } from 'ethers';
const ethersProvider = new ethers.BrowserProvider(provider);
const signer = await ethersProvider.getSigner();
await signer.sendTransaction({ to: '0x...', value: ethers.parseEther('0.01') });
// viem
import { createWalletClient, custom } from 'viem';
const client = createWalletClient({ transport: custom(provider) });Generic RPC Calls
Sends JSON-RPC requests directly to the node via the /wallet/rpc endpoint.
// Native balance
const balance = await sdk.walletRpc('eth_getBalance', [address, 'latest'], 'eip155:612044');
// eth_call — ERC-20 balanceOf
const selector = '70a08231';
const padded = address.slice(2).padStart(64, '0');
const raw = await sdk.walletRpc(
'eth_call',
[{ to: contractAddress, data: '0x' + selector + padded }, 'latest'],
'eip155:612044',
);
console.log(BigInt(raw).toString());
// Same call via Provider
const result = await provider.request({
method: 'eth_call',
params: [{ to: contractAddress, data: '0x' + selector + padded }, 'latest'],
});Gateway API Access Control (Project Whitelist)
The Gateway API enforces whitelist verification so that only authorized projects can access it. Only combinations of project + origin (web) or app ID (native) registered in the management console are allowed. Unregistered requests are blocked.
Required Headers
In addition to the existing Authorization header, the following headers must be included:
| Header | Description | Required |
|--------|------------|----------|
| X-Project-Id | Project ID issued from the management console | Always required |
| Origin | Request origin domain (automatically set by browser) | Required for web |
| X-App-Id | bundle ID or package name | Required for native apps |
| X-App-Type | ios / android / windows | Required when using X-App-Id |
Request Examples
Web request (browser automatically includes Origin):
X-Project-Id: {project-id}
Authorization: Bearer {token}Native app request:
X-Project-Id: {project-id}
X-App-Id: com.example.app
X-App-Type: android
Authorization: Bearer {token}Error Responses
| Code | Description |
|------|------------|
| -10022 | Unregistered project or origin/app |
| -10023 | Missing X-Project-Id header |
| -10024 | Missing Origin or X-App-Id header |
| -10025 | X-App-Type is not android / ios / windows |
The SDK automatically includes
SDKConfig.projectIdin theX-Project-Idheader. For web, the browser automatically sets theOriginheader — no additional configuration needed. For native apps, setSDKConfig.appIdandSDKConfig.appTypeand the SDK will include the appropriate headers automatically.
SDKConfig
const sdk = createCROSSxSDK({
/** OAuth popup mode: 'popup' (default) | 'modal' */
oauthDisplayMode: 'popup',
/** Enable mock wallet (for development/testing) */
useMockWallet: false,
/** Confirmation modal theme: 'light' (default) | 'dark' */
theme: 'light',
/**
* Confirmation modal color customization (independent overrides per light/dark mode)
*/
themeTokens: {
light: {
primary: '#FF6B35', // Button & accent color (default: #019D92)
bg: '#F5F0EB', // Card background color (default: #FFFFFF)
},
dark: {
primary: '#FF6B35',
bg: '#1A0A00', // Card background color (default: #121212)
},
},
/** Receipt polling defaults */
receiptPolling: {
intervalMs: 2000, // Polling interval (ms)
timeoutMs: 60000, // Maximum wait time (ms)
},
/**
* Enable debug log output (default: true)
* ⚠️ Always disabled in production builds regardless of this value.
*/
debug: true,
});Confirmation Modal Theme
| Method | Description |
|---|---|
| config.theme | Initial theme setting ('light' by default) |
| sdk.setTheme('dark') | Runtime theme switching (preserves themeTokens overrides) |
| config.themeTokens.light.* | Light mode semantic token overrides |
| config.themeTokens.dark.* | Dark mode semantic token overrides |
Available override tokens: primary · secondary · onPrimary · borderDefault · borderSubtle · textPrimary · textSecondary · textTertiary · surfaceDefault · bg
For details, see Confirmation Modal & Prepare Flow.
Chain ID Constants
Use ChainId constants to prevent typos.
import { ChainId } from '@nexus-cross/crossx-sdk-core';
await sdk.getBalance(ChainId.CROSS_TESTNET); // 'eip155:612044'
await sdk.getBalance(ChainId.CROSS_MAINNET); // 'eip155:612055'Environment Variables
| Variable | Purpose | Required |
|---|---|---|
| VITE_WALLET_GATEWAY_URL | Wallet Gateway API URL | ✅ |
| VITE_OAUTH_SERVICE_URL | OAuth Service URL | ✅ |
| VITE_AUTH_API_URL | Auth API URL | ✅ |
Public Types
import type {
SDKConfig,
ConfirmationTokenOverride, // themeTokens type (per light/dark mode overrides)
ConfirmationThemeTokens, // Single mode semantic token type
AuthResult,
EvmTransactionRequest,
TransactionResult,
TransactionWithReceipt, // sendTransactionAndWait() return type
TransactionReceipt, // waitForTransaction() return type
SignTransactionResult,
ChainIdValue,
} from '@nexus-cross/crossx-sdk-core';Related Documentation
- Transaction Confirmation Modal
- Ethereum Provider Guide
- Environment Variables
- CAIP-2 Chain ID Guide
- wagmi Integration Guide
- Architecture
License
MIT
