Skip to main content

Overview

SubWallet provides multiple functions for retrieving and managing user accounts. These functions allow you to get all accounts, subscribe to account changes, and find specific extension instances for signing operations.
All account management functions require web3Enable() to be called first. See web3Enable for details.

web3Accounts

Retrieve all accounts from all enabled extensions.

Function Signature

function web3Accounts(
  options?: Web3AccountsOptions
): Promise<InjectedAccountWithMeta[]>

Source Code Reference

packages/extension-dapp/src/bundle.ts:114

Parameters

options
Web3AccountsOptions
Optional configuration object for filtering and formatting accounts.

Return Value

accounts
InjectedAccountWithMeta[]
Array of accounts with metadata. Each account contains:

Usage Examples

Basic Usage

import { web3Enable, web3Accounts } from '@subwallet/extension-dapp';

// First, enable the extension
await web3Enable('My DApp');

// Get all accounts
const accounts = await web3Accounts();

console.log(`Found ${accounts.length} accounts`);
accounts.forEach(account => {
  console.log(`${account.meta.name}: ${account.address}`);
});

Filter by Account Type

import { web3Accounts } from '@subwallet/extension-dapp';

// Get only Ethereum accounts
const ethereumAccounts = await web3Accounts({ 
  accountType: ['ethereum'] 
});

// Get Substrate accounts (sr25519 and ed25519)
const substrateAccounts = await web3Accounts({ 
  accountType: ['sr25519', 'ed25519'] 
});

Custom Address Format

import { web3Accounts } from '@subwallet/extension-dapp';

// Get accounts with Polkadot address format
const polkadotAccounts = await web3Accounts({ 
  ss58Format: 0 
});

// Get accounts with Kusama address format
const kusamaAccounts = await web3Accounts({ 
  ss58Format: 2 
});

React Hook Example

import { useState, useEffect } from 'react';
import { web3Enable, web3Accounts } from '@subwallet/extension-dapp';

function useAccounts() {
  const [accounts, setAccounts] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function loadAccounts() {
      await web3Enable('My DApp');
      const allAccounts = await web3Accounts();
      setAccounts(allAccounts);
      setLoading(false);
    }
    
    loadAccounts();
  }, []);
  
  return { accounts, loading };
}

// Usage in component
function AccountSelector() {
  const { accounts, loading } = useAccounts();
  
  if (loading) return <div>Loading accounts...</div>;
  
  return (
    <select>
      {accounts.map(account => (
        <option key={account.address} value={account.address}>
          {account.meta.name || account.address}
        </option>
      ))}
    </select>
  );
}

web3AccountsSubscribe

Subscribe to account changes across all extensions. This is useful for keeping your UI in sync when users add, remove, or modify accounts in SubWallet.

Function Signature

function web3AccountsSubscribe(
  callback: (accounts: InjectedAccountWithMeta[]) => void | Promise<void>,
  options?: Web3AccountsOptions
): Promise<Unsubcall>

Source Code Reference

packages/extension-dapp/src/bundle.ts:146

Parameters

callback
(accounts: InjectedAccountWithMeta[]) => void | Promise<void>
required
Function called whenever accounts change. Receives the updated list of accounts as a parameter.Can be synchronous or asynchronous (return a Promise).
options
Web3AccountsOptions
Same options as web3Accounts() for filtering and formatting.

Return Value

unsubscribe
Unsubcall (function)
A function to call when you want to stop receiving updates. Call this function to unsubscribe from account changes.
type Unsubcall = () => void;

Usage Examples

Basic Subscription

import { web3Enable, web3AccountsSubscribe } from '@subwallet/extension-dapp';

await web3Enable('My DApp');

const unsubscribe = await web3AccountsSubscribe((accounts) => {
  console.log(`Accounts updated: ${accounts.length} accounts`);
  accounts.forEach(account => {
    console.log(`  - ${account.meta.name}: ${account.address}`);
  });
});

// Later, when you want to stop listening
unsubscribe();

React Hook with Subscription

import { useState, useEffect } from 'react';
import { web3Enable, web3AccountsSubscribe } from '@subwallet/extension-dapp';

function useAccountSubscription() {
  const [accounts, setAccounts] = useState([]);
  
  useEffect(() => {
    let unsubscribe;
    
    async function subscribe() {
      await web3Enable('My DApp');
      unsubscribe = await web3AccountsSubscribe(setAccounts);
    }
    
    subscribe();
    
    // Cleanup: unsubscribe when component unmounts
    return () => {
      if (unsubscribe) {
        unsubscribe();
      }
    };
  }, []);
  
  return accounts;
}

// Usage
function App() {
  const accounts = useAccountSubscription();
  
  return (
    <div>
      <h2>Active Accounts ({accounts.length})</h2>
      <ul>
        {accounts.map(account => (
          <li key={account.address}>
            {account.meta.name || 'Unnamed'} - {account.address}
          </li>
        ))}
      </ul>
    </div>
  );
}

With Custom Formatting

import { web3AccountsSubscribe } from '@subwallet/extension-dapp';

const unsubscribe = await web3AccountsSubscribe(
  (accounts) => {
    // Update your UI with Polkadot-formatted addresses
    updateAccountList(accounts);
  },
  { ss58Format: 0 } // Polkadot format
);

web3FromSource

Get the injected extension instance for a specific source (extension name). This is useful when you need to access the signer or other features of a specific extension.

Function Signature

function web3FromSource(
  source: string
): Promise<InjectedExtension>

Source Code Reference

packages/extension-dapp/src/bundle.ts:183

Parameters

source
string
required
The name of the extension source (e.g., “subwallet-js”). This value comes from the meta.source property of accounts.

Return Value

extension
InjectedExtension
The extension instance containing accounts, signer, and other interfaces. See web3Enable return value for the complete structure.

Usage Examples

Get Extension by Source

import { web3Enable, web3FromSource } from '@subwallet/extension-dapp';

await web3Enable('My DApp');

try {
  const extension = await web3FromSource('subwallet-js');
  console.log(`Found extension: ${extension.name} v${extension.version}`);
  
  // Access the signer
  const signer = extension.signer;
  // Use signer for transactions...
} catch (error) {
  console.error('Extension not found:', error);
}

web3FromAddress

Get the injected extension instance that manages a specific address. This is the most common way to get a signer for transaction signing.

Function Signature

function web3FromAddress(
  address: string
): Promise<InjectedExtension>

Source Code Reference

packages/extension-dapp/src/bundle.ts:199

Parameters

address
string
required
The account address to look up. Can be in any valid SS58 format - the function will decode and compare addresses correctly.

Return Value

extension
InjectedExtension
The extension instance that manages this address. Contains the signer needed for transaction signing.

Usage Examples

Basic Usage

import { web3Enable, web3Accounts, web3FromAddress } from '@subwallet/extension-dapp';
import { ApiPromise, WsProvider } from '@polkadot/api';

// Initialize
await web3Enable('My DApp');
const accounts = await web3Accounts();
const selectedAddress = accounts[0].address;

// Get the injected extension for this address
const injected = await web3FromAddress(selectedAddress);

// Connect to blockchain
const api = await ApiPromise.create({ 
  provider: new WsProvider('wss://rpc.polkadot.io') 
});

// Create and sign a transaction
const transfer = api.tx.balances.transfer(
  'DESTINATION_ADDRESS',
  12345
);

await transfer.signAndSend(
  selectedAddress,
  { signer: injected.signer },
  ({ status }) => {
    if (status.isInBlock) {
      console.log(`Transaction included in block`);
    }
  }
);

Complete Transaction Example

import { web3Enable, web3FromAddress } from '@subwallet/extension-dapp';
import { ApiPromise, WsProvider } from '@polkadot/api';

async function sendTransaction(fromAddress, toAddress, amount) {
  try {
    // Enable extension
    await web3Enable('My DApp');
    
    // Get the signer for this address
    const injected = await web3FromAddress(fromAddress);
    
    // Connect to chain
    const api = await ApiPromise.create({
      provider: new WsProvider('wss://rpc.polkadot.io')
    });
    
    // Create transaction
    const transfer = api.tx.balances.transfer(toAddress, amount);
    
    // Sign and send
    const hash = await transfer.signAndSend(
      fromAddress,
      { signer: injected.signer }
    );
    
    console.log('Transaction hash:', hash.toHex());
    return hash;
  } catch (error) {
    console.error('Transaction failed:', error);
    throw error;
  }
}

// Usage
await sendTransaction(
  'SENDER_ADDRESS',
  'RECIPIENT_ADDRESS',
  1000000000000 // 1 DOT (10 decimals)
);

With Error Handling

import { web3FromAddress } from '@subwallet/extension-dapp';

async function getSignerForAddress(address) {
  try {
    const injected = await web3FromAddress(address);
    return injected.signer;
  } catch (error) {
    if (error.message.includes('Unable to find injected')) {
      console.error('This address is not managed by any extension');
      // Show error to user
    } else {
      console.error('Unexpected error:', error);
    }
    return null;
  }
}

Type Definitions

InjectedAccountWithMeta

interface InjectedAccountWithMeta {
  address: string;
  meta: {
    genesisHash?: string | null;
    name?: string;
    source: string;
  };
  type?: KeypairType;
}
Source: packages/extension-inject/src/types.ts:21

Web3AccountsOptions

interface Web3AccountsOptions {
  ss58Format?: number;
  accountType?: KeypairType[];
}
Source: packages/extension-inject/src/types.ts:131

KeypairType

type KeypairType = 'ed25519' | 'sr25519' | 'ecdsa' | 'ethereum';

Best Practices

Cache Account Lists: Use web3AccountsSubscribe() instead of repeatedly calling web3Accounts() to keep your account list up to date efficiently.
Address Format Consistency: If your dApp uses a specific chain, always request accounts with the appropriate ss58Format to ensure address display consistency.
Always Check for Accounts: After calling web3Accounts(), always check if the array is empty. Users might not have any accounts created yet.
Source Names: The meta.source property identifies which extension manages an account. For SubWallet, this is typically “subwallet-js”.

See Also

Build docs developers (and LLMs) love