Integrating a Wallet with OXN
If you build a wallet and want to add OXN support, this guide covers the specific things wallets need to do that go beyond standard Ethereum integration.
Basics: OXN as an EVM chain
OXN is a standard EVM-compatible chain from the wallet's perspective. Add it to your supported networks with:
- Chain ID:
186 - RPC:
https://rpc.bout.network - Currency symbol:
TBLUAI, 18 decimals - Explorer:
https://explorer.bout.network
The Testnet Parameters page has the full details in JSON form for programmatic configuration.
What makes OXN different for wallets
Standard EVM wallets sign transactions and display the calldata for user review. On OXN:
- Calldata is encrypted at the client side before signing.
- Balances for confidential tokens are only visible via signed queries.
- Event logs are encrypted per-caller.
If the wallet only signs whatever data the dApp passes, no changes are strictly needed. But to give users a good experience, the wallet needs to know about OXN's encryption.
Signing encrypted transactions
The dApp constructs the encrypted envelope. The wallet's job is to sign the outer transaction with the encrypted data as-is:
{
to: "0xContractAddress",
data: "0xa3...", // CBOR envelope from the dApp
value: 0,
gas: 500_000,
gasPrice: 100_000_000,
nonce: ...
}
The wallet signs this exactly as it would sign any Ethereum transaction. It does not need to decode the encrypted data.
Displaying encrypted transactions
The user sees the outer transaction — to, value, gas — but the data field is a long hex blob that isn't human-readable. To improve UX:
- Detect the CBOR envelope prefix (
0xa0–0xbf) and label the transaction "Encrypted". - Encourage the dApp to display a plain-language summary before sending the request.
- Do not attempt to decode the encrypted data — the wallet cannot decrypt it without the enclave key.
Displaying confidential token balances
For a confidential ERC-20 (see Building a Confidential ERC-20), calling balanceOf(user) via a plain eth_call returns 0. To display the real balance, the wallet must:
- Detect that the token is confidential (via a well-known method or dApp hint).
- Construct a signed query: sign the
eth_callpayload with the user's private key. - Send the signed query.
- Decrypt the response with the session key.
- Display the returned balance.
This requires the wallet to hold the private key (which it already does) and to implement the OXN encryption protocol client-side.
For wallets that don't want to implement encryption themselves, delegate this to the OXN SDK:
import { wrapEthersSigner } from "@oasisprotocol/sapphire-ethers-v6";
const wallet = new ethers.Wallet(privateKey, provider);
const wrapped = wrapEthersSigner(wallet);
// Use wrapped for signed queries
Deposit and withdraw
OXN has two address formats (see Accounts and Addresses). Users need to move value between them:
- Deposit: consensus-layer
oxn1…→ EVM0x… - Withdraw: EVM
0x…→ consensus-layeroxn1…
Most wallets can skip this — the vast majority of dApp interaction is on the EVM side. The OXN Web Wallet handles the flow if a user needs it.
If your wallet targets validator staking (mainnet), you'll need to support both address formats and the deposit/withdraw operations.
Networks in a mobile wallet
For iOS / Android wallets, OXN Testnet works via WalletConnect or a direct RPC connection. The confidential-transaction encryption happens either in the dApp (browser side) or in a native SDK if your wallet wants first-class support.
For confidential features to work in a mobile wallet:
- Include the OXN SDK's native equivalent (Go / Rust wrapping X25519 + Deoxys-II), or
- Compile a WASM version of the encryption library from the TypeScript SDK.
Testing your integration
- Add OXN Testnet to your wallet.
- Fund a test address from the faucet.
- Perform a simple transfer to another address.
- Deploy or interact with a confidential contract.
- Verify balances display correctly via signed query.
- Test error handling: rejected transactions, network errors, wrong chain.
Next steps
- Testnet Parameters
- Wallet Integration — the SDK-level integration
- TypeScript SDK