Wallet

Android Wallet

Wallet creation, address lookup, signing, sending, and receipt waiting.

Prerequisites

  • Signed in with sdk.signIn(...) or sdk.signInWithCreate(...)
  • EVM chain routing requires a chainId (recommended: eip155:<number>)

Address and wallet APIs

val created = sdk.createWallet()
val primary = sdk.getAddress()
val byIndex = sdk.getAddress(index = 0)
val all = sdk.getAddresses()
val state = sdk.checkWallet()
val selected = sdk.selectWallet(activity = activity)
val selectedWithHint = sdk.selectWallet(activity = activity, currentAddress = "0x...")

Users who only ran signIn() may have no address yet. Call createWallet() or use signInWithCreate() from the start.

createWallet() returns the wallet address only. Recovery-share handling is a separate flow outside the public SDK surface.

Balance after login (example)

lifecycleScope.launch {
    val ok = sdk.ensureLoggedIn()
    if (!ok) return@launch

    val chainId = "eip155:612044"
    val addressResp = sdk.getAddress()
    val address = addressResp.address.orEmpty()
    if (address.isBlank()) {
        sdk.createWallet()
    }

    val resolvedAddress = sdk.getAddress().address.orEmpty()
    if (resolvedAddress.isBlank()) return@launch

    val balanceHex = sdk.getBalance(
        address = resolvedAddress,
        chainId = chainId
    )

    // Update UI with resolvedAddress, balanceHex
}

Message and typed data signing

Confirmation UI requires an Activity.

val chainId = "eip155:612044"

val signMessageResp = sdk.signMessage(
    activity = activity,
    message = "Hello CROSSx",
    chainId = chainId
)

val signTypedResp = sdk.signTypedData(
    activity = activity,
    typedDataJson = """{"types":{},"primaryType":"Permit","domain":{"chainId":612044},"message":{}}""",
    chainId = chainId
)

val signTypedOffchainResp = sdk.signTypedDataOffchain(
    activity = activity,
    typedDataJson = """{"types":{},"primaryType":"Mail","domain":{"name":"Test"},"message":{}}"""
)

On-chain typed data: use chainId = "eip155:<n>" and match the numeric domain.chainId in the JSON.

Off-chain: use signTypedDataOffchain(...). Off-chain payloads often omit domain.chainId.

signTypedData may perform extra RPC (e.g. eth_call) for metadata parsing; chainId is still required.

Transaction signing

Prefer WalletUnsignedTransaction.EvmEip155.

val tx = WalletUnsignedTransaction.EvmEip155(
    chainId = "eip155:612044",
    from = "0xYourAddress",
    to = "0xRecipient",
    value = "0xde0b6b3a7640000",
    data = "0x"
)

val signTxResp = sdk.signTransaction(
    activity = activity,
    unsignedTx = tx,
    chainId = tx.chainId
)

Use the UnsignedTx overload if you need direct control of the gateway payload. from must not be empty for signing and sending.

Sending transactions

val sendResp = sdk.sendTransaction(
    activity = activity,
    unsignedTx = tx,
    chainId = tx.chainId
)
val txHash = sendResp.txHash

Send and wait for receipt in one step

val receipt = sdk.sendTransactionWithWaitForReceipt(
    activity = activity,
    unsignedTx = tx,
    chainId = tx.chainId,
    timeoutMs = 30_000,
    pollIntervalMs = 1_000
)

val txHash = receipt.transactionHash
val status = receipt.status

Use sendTransaction() alone if you only need the hash immediately after broadcast; poll later with waitForTxAndGetReceipt().

Manual receipt polling

val receipt = sdk.waitForTxAndGetReceipt(
    txHash = "0x...",
    chainId = "eip155:612044",
    timeoutMs = 30_000,
    pollIntervalMs = 1_000
)

End-to-end send example

lifecycleScope.launch {
    val ok = sdk.ensureLoggedIn()
    if (!ok) return@launch

    val from = sdk.getAddress().address.orEmpty()
    if (from.isBlank()) return@launch

    val tx = WalletUnsignedTransaction.EvmEip155(
        chainId = "eip155:612044",
        from = from,
        to = "0xRecipient",
        value = "0xde0b6b3a7640000",
        data = "0x"
    )

    val receipt = sdk.sendTransactionWithWaitForReceipt(
        activity = this@MainActivity,
        unsignedTx = tx,
        chainId = tx.chainId,
        timeoutMs = 30_000,
        pollIntervalMs = 1_000
    )

    // Update UI with receipt.transactionHash, receipt.status
}

RPC helpers

val rpcRespJson = sdk.walletRpc(
    request = JsonRpcRequest(
        method = "eth_call",
        params = "[]"
    ),
    chainId = "eip155:612044"
)

val balanceHex = sdk.getBalance(
    address = "0xYourAddress",
    chainId = "eip155:612044"
)

val nonceHex = sdk.getNonce(
    address = "0xYourAddress",
    chainId = "eip155:612044",
    blockTag = "pending"
)

Use walletRpc mainly for reads and calls (eth_call, etc.). Use dedicated APIs for signing and sending transactions.

JsonRpcRequest.params must be a JSON array string (e.g. [], ["0xabc","latest"]).

Wallet password and biometrics

The SDK may show password entry and confirmation UI before signing and sending. After verification once, the password is reused for later operations.

Biometric availability and settings:

val can = sdk.canUseBiometric()
val enabled = sdk.isBiometricEnabled()
lifecycleScope.launch {
    sdk.setBiometricEnabled(true)
}

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