Observed since 21 Oct, 08:57 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Official TypeScript SDK for 0xio Wallet - Secure Octra blockchain integration for dApps
Version 2.10.0
The official TypeScript SDK for building dapps on the 0xio Wallet and the Octra Network. It works with the browser extension, inside the 0xio Desktop browser and inside the 0xio App, and picks the right transport on its own.
What changed in each release is in CHANGELOG.md. The full API is in DOCUMENTATION.md.
npm install @0xio/sdk
import { ZeroXIOWallet } from '@0xio/sdk';
const wallet = new ZeroXIOWallet({
appName: 'My DApp',
requiredPermissions: ['accounts', 'public_transactions'],
});
await wallet.initialize();
// Connect. The wallet shows an approval the first time.
const connection = await wallet.connect();
console.log(connection.address);
console.log(connection.publicKey); // base64 Ed25519 key
// Balance, in OCT.
const balance = await wallet.getBalance();
console.log(balance.public, balance.private, balance.total);
// Sign a message. The wallet frames it (see Message signing below).
const signature = await wallet.signMessage('Hello, 0xio!');
// Send 10.5 OCT.
const result = await wallet.sendTransaction({
to: 'oct1recipient...',
amountOct: '10.5',
message: 'Payment',
});
console.log(result.hash);
The wallet counts in raw micro-OCT: one OCT is 1000000 units. Every raw field is passed to the wallet exactly as you give it, so existing integrations keep working. Where you would rather write OCT, use the OCT field and the SDK converts it with exact decimal arithmetic.
| Method | Raw field (sent as is) | OCT field (converted by the SDK) |
|---|---|---|
sendTransaction, signTransaction | amount | amountOct |
callContract | amount | amountOct |
sendPrivateTransfer | amountRaw | amount |
getBalance | returns OCT |
Pass one field or the other, not both. A number that cannot be written in six decimals (such as 0.1 + 0.2) is rejected; pass a string.
Ask for what the dapp uses. The wallet enforces these names:
| Scope | Grants |
|---|---|
accounts | address, balance, public key |
public_transactions | sends and message signing |
contract_calls | state-changing contract calls |
contract_views | read-only contract calls |
private_balance_read | private balance, decrypting values, pending transfers |
private_proofs | encrypting values, zero and range proofs |
private_transfers | sending private transfers |
private_claims | claiming private transfers |
The private scopes show a warning in the connection dialog. Older names such as read_balance or stealth_claim still work: the SDK translates them, and they come back in the granted list as aliases.
Connection: initialize(), connect(options?), disconnect(), isConnected(), getConnectionStatus(), getAddress(), getPublicKey(), canSign() (2.10.0).
Balance and network: getBalance(forceRefresh?), getNetworkInfo(), getNetworkId(), switchNetwork(id) (connected dapps only; the wallet asks the user first).
Transactions: sendTransaction(data), signTransaction(data) then submitTransaction(signedTx), getTransactionHistory(page?, limit?).
Contracts: callContract(data) (signed, approval shown), deployContract({ bytecode, params?, ou? }) (approval shows the code size, the contract address from the node and the fee; returns { txHash, contractAddress }), contractCallView(data) (read-only, no approval), getContractStorage(contract, key), sendContractTransactionSequence(data) (several calls under one approval; every step is listed in it).
Messages: signMessage(message), signAuthMessage(service, nonce), and the verifiers verifyMessage, getSignedMessageBytes, buildAuthMessage.
Private: sendPrivateTransfer(data), getPendingPrivateTransfers(), claimPrivateTransfer(id) (approval shown), getPrivateBalanceInfo(), registerPrivateViewKey({ address }).
Private primitives (2.8.0): getPrivateCapabilities(), encryptValue(), decryptValue(), makeZeroProof(), makeRangeProof(), getPrivateBalance(). Keys never leave the wallet; the dapp receives ciphertexts, proofs and hashes.
Passthrough: request(method, params) sends any wallet method; rpcCall(method, params) reaches the wallet's read-only node RPC allow-list, such as octra_balance.
encryptBalance and decryptBalance remain for other wallets; the 0xio extension answers NOT_AVAILABLE, and users encrypt from its Privacy screen.
A watch-only wallet connects and reads, but cannot sign. The connection, the connect event and accountChanged carry canSign, and wallet.canSign() returns it:
true: the wallet signs.false: watch-only. Show a read-only state; every signing call fails with WATCH_ONLY.undefined: unknown (not connected, or an extension older than 3.0.3). A missing publicKey then hints at watch-only, and older extensions refuse signing with PERMISSION_DENIED.await wallet.connect();
const canSign = wallet.canSign() ?? !!wallet.getConnectionInfo().publicKey;
sendButton.disabled = !canSign;
wallet.on('accountChanged', (event) => {
sendButton.disabled = event.data.canSign === false;
});
The wallet never signs a raw message. It signs a framed payload, so a signed message can never be a transaction (a transaction is JSON and starts with {):
"Octra Signed Message:\n" + utf8ByteLength(message) + "\n" + message
The signature is an Ed25519 detached signature over the UTF-8 bytes of that string. Verify it with the SDK:
import { verifyMessage } from '@0xio/sdk';
const publicKey = await wallet.getPublicKey();
const ok = await verifyMessage(message, signature, publicKey);
Or with any Ed25519 library, over the exact bytes from getSignedMessageBytes(message). For signAuthMessage(service, nonce), rebuild the signed string with buildAuthMessage(service, nonce, origin) first.
wallet.on('connect', (event) => console.log('Connected:', event.data.address));
wallet.on('disconnect', (event) => console.log('Disconnected:', event.data.reason));
wallet.on('accountChanged', (event) => console.log('Account:', event.data.newAddress));
wallet.on('balanceChanged', (event) => console.log('Balance:', event.data.newBalance.total));
wallet.on('networkChanged', (event) => console.log('Network:', event.data.newNetwork.name));
wallet.on('transactionConfirmed', (event) => console.log('Confirmed:', event.data.txHash));
wallet.on('transactionFailed', (event) => console.log('Failed:', event.data.error));
wallet.on('extensionLocked', () => console.log('Locked'));
Every failure is a ZeroXIOWalletError with a code.
import { ZeroXIOWalletError, ErrorCode } from '@0xio/sdk';
try {
await wallet.sendTransaction({ to: 'oct1...', amountOct: '10' });
} catch (error) {
if (error instanceof ZeroXIOWalletError) {
switch (error.code) {
case ErrorCode.NOT_CONNECTED: // connect() first
case ErrorCode.WALLET_LOCKED: // the user has to unlock the wallet
case ErrorCode.USER_REJECTED: // the user declined the approval
case ErrorCode.WATCH_ONLY: // the wallet is watch-only and cannot sign
case ErrorCode.INVALID_AMOUNT: // bad unit or precision
case ErrorCode.NONCE_TOO_FAR: // node rejected the transaction
console.log(error.code, error.message);
}
}
}
deployContract adds two codes: DEPLOY_CHANGED when another transaction moved the nonce after the review, so the contract address would differ (nothing is sent), and DEPLOY_FAILED when the node refuses the deploy.
The wallet refuses anything that signs, submits or changes state until the page has connected, and opens its unlock screen at most once a minute for a page that is not connected. While the wallet is locked, getBalance and the private balance reads return WALLET_LOCKED (extension 3.0.0 and newer).
import { getNetworkConfig } from '@0xio/sdk';
const devnet = getNetworkConfig('devnet');
console.log(devnet.rpcUrl); // https://devnet.octrascan.io
console.log(devnet.isTestnet); // true
| Network | RPC | Explorer | Privacy |
|---|---|---|---|
| Mainnet | https://octra.network | octrascan.io | yes |
| Devnet | https://devnet.octrascan.io | devnet.octrascan.io | yes |
connect() returns the wallet's active network in networkInfo; the SDK never assumes one.
trustedParentOrigins in production; localhost is trusted by default for development.No code changes are needed; the SDK detects the environment.
Transport is pluggable, so another wallet can be supported without touching the core.
import { detectWalletAdapter, ZeroXIOWallet, OctraProviderAdapter } from '@0xio/sdk';
// Detect: the 0xio bridge first, then any RFC-O-1 provider on window.octra.
const adapter = detectWalletAdapter();
const wallet = new ZeroXIOWallet({ appName: 'My DApp', adapter });
// Or choose one explicitly.
const rfc = new ZeroXIOWallet({ appName: 'My DApp', adapter: OctraProviderAdapter });
The 0xio bridge carries every SDK method. The RFC-O-1 provider carries what the RFC names (deployContract maps to octra_deployContract), so getBalance, getPublicKey, getTransactionHistory, getContractStorage, getPendingPrivateTransfers and rpcCall have no equivalent there. The table in DOCUMENTATION.md lists coverage per method.
To add a wallet, copy src/supports/template.ts, fill in its constants and message mapping, register it in src/supports/index.ts, and export it from src/index.ts if it belongs in the public API.
Approvals wait up to three minutes, deployContract included. A private transfer waits up to ten, because the wallet builds proofs after the approval. Interactive methods are never retried, so a slow approval never produces a second popup.
canSign and WATCH_ONLYdeployContractMIT License. Copyright 2026 0xio Labs.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 2.10.0Registry latest | 18 Oct 2026 | 11 | |
| 2.9.0 | 16 Oct 2026 | 11 | |
| 2.8.1 | 22 Sept 2026 | 11 | |
| 2.8.0 | 3 Sept 2026 | 11 | |
| 2.7.1 | 4 Jun 2026 | 11 | |
| 2.7.0 | 18 May 2026 | 11 | |
| 2.6.0 | 13 May 2026 | 11 | |
| 2.5.0 | 9 May 2026 | 11 | |
| 2.4.5 | 7 May 2026 | 11 | |
| 2.4.4 | 5 May 2026 | 11 | |
| 2.4.3 | 26 Apr 2026 | 11 | |
| 2.4.2 | 15 Apr 2026 | 11 | |
| 2.4.1 | 14 Apr 2026 | 11 | |
| 2.4.0 | 24 Mar 2026 | 11 | |
| 2.3.0 | 10 Mar 2026 | 11 | |
| 2.2.0 | 9 Mar 2026 | 11 | |
| 2.1.8 | 17 Feb 2026 | 11 | |
| 2.1.7 | 26 Jan 2026 | 11 | |
| 2.1.6 | 26 Jan 2026 | 11 | |
| 2.1.5 | 26 Jan 2026 | 11 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 08:57 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:bfdece7f83a4368d68c7895353a53eefaea45d545deef198d611e3e298fc9781