Guides
NEXUS
Guides

Wallet

Core SDK — Wallet

This guide covers wallet creation, address/balance APIs, signing, sending, and receipt polling.

Prerequisites

  • User should be authenticated (sdk.signIn() completed).
  • EVM chain routing requires chainId in CAIP-2 format (e.g. eip155:612044).

Address & wallet APIs

const address = await sdk.getAddress()         // { address, index } | null
const byIndex = await sdk.getAddress(0)        // specific derivation index
const all = await sdk.getAddresses()           // [{ address, index, name? }, ...]
const wallet = await sdk.createWallet()        // { address }

// Synchronous access (no API call)
const addr = sdk.currentAddress                // string | null
const userId = sdk.currentUserId               // string | null

Wallet selector

Display a wallet selection modal when the user has multiple wallets:

// Show wallet selector (no "selected" indicator)
const wallet = await sdk.selectWallet()

// Show wallet selector with current address highlighted as "selected"
const wallet = await sdk.selectWallet(currentAddress)

if (wallet) {
  console.log(wallet.address, wallet.index, wallet.name) // name is the optional user-defined wallet label
  await sdk.signMessage(chainId, message, { index: wallet.index })
}
ParameterTypeDescription
currentAddressstring?If provided, the matching wallet is highlighted with a "selected" tag in the popup

selectWallet() emits an addressChanged event when a wallet is selected, which automatically updates sdk.currentAddress, the wagmi provider state, and CROSSxProvider (React).

Automatic selection during sign-in

signInWithCreate() calls selectWallet() automatically when 2+ wallets exist. You don't need to call selectWallet() manually after signInWithCreate():

// Wallet selector modal appears automatically if user has 2+ wallets
const result = await sdk.signInWithCreate()
console.log(result.address) // the wallet user selected

Balance & nonce

const chainId = 'eip155:612044'

const { wei, formatted } = await sdk.getBalance(chainId)
console.log(`Balance: ${formatted}`)  // "1.234567 tONE"

const nonce = await sdk.getNonce(chainId)

Sign message

All signing methods display a user confirmation modal.

const chainId = 'eip155:612044'

const { signature } = await sdk.signMessage(chainId, 'Hello, World!')

// With options: customize confirmation modal
const { signature } = await sdk.signMessage(chainId, 'Hello, World!', {
  dappName: 'My DApp',
  accountName: 'Account 1',
  index: 0,
})

Sign EIP-712 typed data

// On-chain (domain.chainId required — e.g. Permit)
const { signature } = await sdk.signTypedData(chainId, {
  domain: { name: 'MyApp', version: '1', chainId: 612044 },
  types: { /* ... */ },
  primaryType: 'MyType',
  message: { /* ... */ },
}, { dappName: 'My DApp' })

// Off-chain (no domain.chainId — e.g. EIP-712 order signatures)
const { signature } = await sdk.signTypedDataOffchain({
  domain: { name: 'MyApp' },
  types: { /* ... */ },
  primaryType: 'MyType',
  message: { /* ... */ },
})

Sign transaction (without broadcasting)

const { signedTx, txHash } = await sdk.signTransaction(chainId, {
  from: '0xYourAddress...',
  to: '0xRecipient...',
  value: '0x0',
  data: '0x',
}, { dappName: 'My DApp' })

Send transaction

const { txHash } = await sdk.sendTransaction(chainId, {
  from: '0xYourAddress...',
  to: '0xRecipient...',
  value: '0xDE0B6B3A7640000', // 1 ETH in wei (hex)
  data: '0x',
}, { dappName: 'My DApp' })

Send + wait for receipt

const { txHash, receipt } = await sdk.sendTransactionWithWaitForReceipt(
  chainId,
  { from: '0xYourAddress...', to: '0x...', value: '0x...', data: '0x' },
  { intervalMs: 2000, timeoutMs: 30000 }
)
console.log(receipt.status) // '0x1' (success) | '0x0' (reverted)

For transaction sign/send flows, from must be provided (non-empty).

Manual receipt polling

const receipt = await sdk.waitForTxAndGetReceipt(
  '0xTxHash...',
  chainId,
  { intervalMs: 1000, timeoutMs: 30000 }
)

Polling starts at the base interval (intervalMs, default 1000 ms) and backs off exponentially — doubling after each attempt, capped at 10000 ms — until the receipt is found or timeoutMs (default 60000 ms) expires.

EIP-1193 Provider

Standard provider for ethers.js, viem, and wagmi integration:

const provider = sdk.getProvider('eip155:612044')

// ethers.js v6
import { BrowserProvider } from 'ethers'
const ethersProvider = new BrowserProvider(provider)

// viem
import { createWalletClient, custom } from 'viem'
const client = createWalletClient({ transport: custom(provider) })

Chain info

// Get all supported chains
const chains = await sdk.getChains()
chains.forEach(c => console.log(c.chainId, c.rpcUrl))

// Get specific chain info
const chain = await sdk.getChain('eip155:612044')
console.log(chain.rpcUrl) // 'https://testnet.onechain.nexus:22001'

Gas helpers

const chainId = 'eip155:612044'

// Legacy gas price
const gasPrice = await sdk.getGasPrice(chainId) // hex string

// Estimate gas for a transaction
const gasLimit = await sdk.estimateGas(
  { from: '0x...', to: '0x...', value: '0x0' },
  chainId,
) // hex string

// EIP-1559 base fee (null on legacy chains)
const baseFee = await sdk.getBaseFeePerGas(chainId)

// EIP-1559 priority fee (tip)
const tip = await sdk.getMaxPriorityFeePerGas(chainId)

PIN management

The SDK supports PIN-based security for wallet operations. PIN is a 4-digit code used for transaction signing and wallet migration.

// Set PIN (cached in memory for the session)
sdk.setPin('1234')

// Check if PIN is set
const hasPinSet = sdk.hasPin() // boolean

// Clear cached PIN
sdk.clearPin()

// Check whether the next sign/send will prompt for PIN
if (sdk.isPinRequired()) {
  // show your own PIN UI, then cache it
}

// Change PIN (requires current PIN)
await sdk.changePin('1234', '5678')

// Switch the PIN modal keyboard mode at runtime
sdk.setPinKeyboard('native')  // OS keyboard
sdk.setPinKeyboard('virtual') // SDK-rendered numpad (default)
sdk.setPinKeyboard(() => window.innerWidth < 768 ? 'native' : 'virtual')
MethodSignatureDescription
setPin(pin: string): voidCache PIN in memory for signing flows
clearPin(): voidClear cached PIN from memory
hasPin(): booleanCheck if a PIN is cached
isPinRequired(): booleantrue if the next sign/send will require PIN entry (no PIN cached)
changePin(oldPin: string, newPin: string): Promise<void>Change PIN on the server
setPinKeyboard(mode: 'virtual' | 'native' | (() => 'virtual' | 'native')): voidChange the PIN modal keyboard mode (applies from the next modal; also settable via SDKConfig.pinKeyboard)

When a PIN is required but not cached, the SDK automatically displays a PIN input modal to the user.

Token history

Register wallet-sent coin/ERC-20 transfers and query them later (cursor-based pagination):

// Register a transfer after it is mined and indexed
// (must be a successful ERC-20 transfer 0xa9059cbb or coin transfer 0x00000000)
await sdk.registerTokenHistory('eip155:612044', txHash, 'my-dapp/1.2.3')

// Query registered transfers
const history = await sdk.getTokenHistory() // TokenHistoryItem[]

// Next page
if (history.length > 0) {
  const last = history[history.length - 1]
  const nextPage = await sdk.getTokenHistory({
    lastTimestamp: last.timestamp,
    lastTxIndex: last.tx_index,
  })
}
MethodSignature
registerTokenHistory(chainId: string, txHash: string, clientVersion: string): Promise<void>
getTokenHistory(options?: { lastTimestamp?: number; lastTxIndex?: number }): Promise<TokenHistoryItem[]>

RPC helpers

// Arbitrary RPC method call
const blockNumber = await sdk.walletRpc('eth_blockNumber', [], chainId)

walletRpc is for read-only calls only (e.g. eth_call).
Transaction signing/sending is not supported via this API.