Wallet Integration
Building a dApp frontend that talks to a user's wallet is nearly identical to Ethereum. The wallet handles signing, your dApp handles the OXN-specific encryption via the client-side SDK. This page covers the wallet-integration paths.
MetaMask via wallet_addEthereumChain
Prompt users to add OXN Testnet to their MetaMask:
async function addOxnTestnet() {
try {
await window.ethereum.request({
method: "wallet_addEthereumChain",
params: [{
chainId: "0xba", // 186
chainName: "OXN Testnet",
nativeCurrency: {
name: "TBLUAI",
symbol: "TBLUAI",
decimals: 18
},
rpcUrls: ["https://rpc.bout.network"],
blockExplorerUrls: ["https://explorer.bout.network"]
}]
});
} catch (err) {
console.error("Failed to add network:", err);
}
}
Trigger this from a user gesture (button click) — MetaMask blocks the popup otherwise. Note that some MetaMask versions do not show the popup at all when served over plain HTTP; use HTTPS or provide manual instructions as fallback.
Requesting account access
async function connect() {
const accounts = await window.ethereum.request({
method: "eth_requestAccounts"
});
console.log("Connected:", accounts[0]);
}
Standard EIP-1102. Ensures the user has authorized your dApp to read their address.
Signing transactions via MetaMask
When the user is connected to MetaMask on OXN Testnet, use ethers.js with a browser provider:
import { ethers } from "ethers";
import { wrapEthersProvider, wrapEthersSigner } from "@oasisprotocol/sapphire-ethers-v6";
const browserProvider = new ethers.BrowserProvider(window.ethereum);
const signer = wrapEthersSigner(await browserProvider.getSigner());
// Now every transaction is encrypted end-to-end
const tx = await signer.sendTransaction({
to: "0xRecipient",
value: ethers.parseEther("0.1"),
gasLimit: 100_000n
});
The wrapping is client-side. MetaMask signs the outer transaction (with encrypted data) but does not decrypt or process the payload.
WalletConnect
WalletConnect v2 supports OXN Testnet as a custom EVM chain. Register the chain metadata in your project's WalletConnect configuration:
const projectId = "your-walletconnect-project-id";
const metadata = {
name: "My OXN dApp",
description: "...",
url: "https://...",
icons: ["https://.../icon.png"]
};
const chains = [{
chainId: 186,
name: "OXN Testnet",
currency: "TBLUAI",
explorerUrl: "https://explorer.bout.network",
rpcUrl: "https://rpc.bout.network"
}];
Wrap the resulting provider with the OXN SDK for encrypted calls.
EIP-6963 (Multi-Wallet Discovery)
Modern dApps should support wallet discovery via EIP-6963 rather than assuming window.ethereum is present:
window.addEventListener("eip6963:announceProvider", (event) => {
const provider = event.detail.provider;
const info = event.detail.info;
console.log("Wallet:", info.name, info.icon);
// Use this specific provider
});
window.dispatchEvent(new Event("eip6963:requestProvider"));
Any EVM-compatible wallet (including MetaMask, Rabby, others) that supports OXN can be discovered this way.
OXN Web Wallet
Users without an existing wallet can use the OXN Web Wallet. It comes pre-configured for OXN and does not require the "add network" flow.
If your dApp is targeted at users who may not have a wallet installed, provide both paths:
- "Connect Wallet" — MetaMask, WalletConnect, etc.
- "Use OXN Wallet" — deep link to
wallet.bout.networkwith your dApp URL
UX for encrypted transactions
Users signing an encrypted transaction see:
- The
toaddress (visible). - The
valuefield (visible). - The
datafield — a large hex blob (the encrypted envelope).
MetaMask does not decode the encrypted data because it cannot — the payload is encrypted to the enclave's key. Your dApp UI should explain what the user is signing before they hit the confirm button in MetaMask, so they don't have to inspect opaque hex bytes.
Recommended pre-signing summary:
You are about to:
- Call `transfer(0xRecipient, 100 tokens)` on `0xToken...`
- Send: 0 TBLUAI
- Gas limit: 500,000
- Payload will be encrypted end-to-end.
Next steps
- TypeScript SDK — the ethers wrapper details
- Confidentiality Model — what users' signatures actually authorize