Appearance
dApp integration
This document is the reference for engineers building dApps that talk to TaoApp Wallet.
The wallet injects a provider that follows the Polkadot.js extension injectedWeb3 convention, with a few TaoApp-specific additions.
Detection
The wallet registers window.injectedWeb3['wallet.tao.app'] and dispatches wallet#initialized on window when installation completes (src/inpage/index.ts).
javascript
window.addEventListener('wallet#initialized', () => {
const wallet = window.injectedWeb3['wallet.tao.app'];
console.log('TaoApp Wallet version:', wallet.version);
});
if (window.injectedWeb3?.['wallet.tao.app']) {
// already initialized if your script loads late
}version comes from __APP_VERSION__ at build time, with a '0.1.0' fallback in src/inpage/index.ts. name is always 'wallet.tao.app'.
Connecting
Call enable() or connect() (they share the same implementation) to request access. That opens the approval window so the user can choose accounts.
javascript
const wallet = window.injectedWeb3['wallet.tao.app'];
const extension = await wallet.enable('My dApp Name');The parameter is an optional display string shown in the approval UI.
The background wallet_enable handler also understands forceReauth on the payload (src/background/controller/approval.ts). The public enable() / connect() wrappers currently forward only { appName } (src/inpage/index.ts). To force a fresh approval from JavaScript today, call disconnect() (or have the user revoke the site) and then enable() again.
The returned extension exposes accounts and signer.
Accounts
accounts.get()
Returns the accounts the user authorized for your origin.
javascript
const accounts = await extension.accounts.get();
// WalletAccountPublic[] - fields in `src/shared/types.ts`address- SS58 with prefixBITTENSOR_SS58_PREFIX(42) fromsrc/shared/constants.tsname- user label (mapped from the vault label intoPublicAccounts,src/domain/accounts.ts)type-sr25519for software,ed25519for Ledger,sr25519ored25519for Vault depending on the key imported from the device (getCryptoTypeinsrc/shared/types.ts, called fromsrc/domain/accounts.ts)genesisHash- currently alwaysnullfor dApp exports (toPublicAccounts)
accounts.subscribe(callback)
Re-fetches accounts on an interval. The first callback runs immediately; later updates use a 10 second timer (src/inpage/index.ts).
javascript
const unsubscribe = extension.accounts.subscribe((accounts) => {
console.log('Updated accounts:', accounts);
});
unsubscribe();On failure, subscribers receive an empty array. Implementation detail: each tick calls wallet_getAccounts, so the same origin authorization rules apply as for get().
Signing
signer.signRaw(request)
Signs arbitrary bytes. Opens the approval window.
javascript
const result = await extension.signer.signRaw({
address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
data: '0x68656c6c6f',
type: 'bytes',
});
// { id?, signature }Limits such as MAX_SIGN_RAW_BYTES are enforced in src/shared/constants.ts.
signer.signPayload(request)
Standard Polkadot extrinsic signing. Opens the approval window.
javascript
const result = await extension.signer.signPayload({
address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
blockHash: '0x...',
blockNumber: '0x...',
era: '0x...',
genesisHash: '0x...',
method: '0x...',
nonce: '0x...',
specVersion: '0x...',
tip: '0x...',
transactionVersion: '0x...',
signedExtensions: [...],
version: 4,
withSignedTransaction: true,
});
// { id?, signature, signedTransaction? }If the signing account has proxy or multisig configuration inside the wallet, the approval UI walks through the right wrapping path. The wallet may embed the call in proxy.proxy or multisig pallets before signing.
When withSignedTransaction is true and the adapter can produce it (Ledger always can; software and Vault use buildSignedExtrinsic in src/background/signing/build-extrinsic.ts), signedTransaction contains the hex-encoded extrinsic ready for submission.
signer.notifyTxSubmitted(params)
Tells the wallet about broadcast progress so the UI can track operations. Payload shape matches WalletNotifyTxSubmittedParams in src/shared/types.ts (also mirrored in src/inpage/index.ts).
javascript
await extension.signer.notifyTxSubmitted({
txHash: '0x...',
phase: 'submitted', // 'submitted' | 'in_block' | 'finalized'
address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
kind: 'transfer', // optional: 'transfer' | 'staking' | 'other'
});Rate limiting is per dApp origin: consumeNotifyRateLimit in src/background/controller/tx-ops.ts enforces TX_NOTIFY_RATE_LIMIT_MAX_EVENTS events inside each rolling TX_NOTIFY_RATE_LIMIT_WINDOW_MS window (src/shared/constants.ts).
Disconnecting
disconnect()
Revokes the origin entirely and notifies subscribers with an empty list.
javascript
await extension.disconnect();disconnectAccounts(addresses)
Drops specific addresses. If none remain, the origin is fully revoked.
javascript
await extension.disconnectAccounts(['5GrwvaEF...', '5HGjWAeF...']);Approval lifecycle
- The wallet answers with
{ status: 'pending', requestId }for interactive calls. - The inpage helper polls
wallet_pollRequestevery 900 ms (src/inpage/index.ts). - Approval or rejection ends the loop and resolves the Promise.
- User-facing timeout: 10 minutes, matching
PENDING_REQUEST_TTL_MSinsrc/shared/constants.ts(the inpage waiter uses the same duration literally). - Transport timeout for a single
postMessagehop: 30 seconds (src/inpage/index.ts).
Error handling
Typical failure modes:
- Wallet locked - background returns
errorCode: 'WALLET_LOCKED'when applicable; the Promise rejects with the message from the bridge. - User rejection - approval returns
status: 'rejected'. - Approval timeout -
"Approval request timeout."after the window above. - Missing authorization - calling
accounts.get()or signing without a successfulenable().
Exact codes surface through the { ok: false, error, errorCode } envelope.
Compatibility with @polkadot/extension-dapp
Standard methods (enable, accounts.get, signPayload, signRaw) behave like other injectedWeb3 providers. TaoApp-specific additions:
connect()alias forenable()accounts.subscribe()polling helpersigner.notifyTxSubmitted()lifecycle hookdisconnect()/disconnectAccounts()permission helpers- Background-only
forceReauthflag until the inpage wrapper exposes it
dApps that only rely on the common subset should work unchanged. Opt into the extras when you need them.
Address format
All addresses use SS58 prefix 42 (Bittensor). The wallet does not expose other prefixes for dApp accounts.