Tronwallet Adapter

Overview

Tronwallet Adapter is a set of packages that contain wallet adapters and components for Tron DApps. With out-of-box components and unified methods, developers can easily interact with multiple kinds of wallets, select/connect/disconnect wallets and sign message or transaction.

Adapters

Wallet adapters help you access to TRON wallets with consistent API.

There are many wallets supporting TRON network such as TronLink, Ledger and so on . Different wallets and different versions of one wallet may have different interface to use. The aim of Adapters relavant pacakges is to shield these differences and offer consistent interface for DApp developers. DApps don't need to change their code frequently if they have accessed to the tron wallet dapters code.

For example if you want to connect to different wallets, you have to use different methods:

// TronLink
window.tronLink.request({ method: 'tron_requestAccounts' });

// Ledger
const transport = await TransportWebHID.create();
const app = new Trx(transport);

// WalletConnect
const wallet = new WalletConnectWallet({
   network: this._config.network,
   options: this._config.options,
});

With adapter, you can use consistent APIs for different wallets:

// TronLink
const tronlinkAdapter = new TronLinkAdapter();
await tronlinkAdapter.connect();
await tronlinkAdapter.signMessage(message);

// Ledger
const ledgerAdapter = new LedgerAdapter();
await ledgerAdapter.connect();
await ledgerAdapter.signMessage(message);

// WalletConnect
const walletconnectAdapter = new WalletConnectAdapter();
await walletconnectAdapter.connect();
await walletconnectAdapter.signMessage(message);

React Hooks

Adapter wallet hooks exports a useWallet() hook which manages the global state of wallet, such as current selected wallet and the connection state, address, and so on. It also provides some methods to interact with wallet.

When your dapp supports multiple wallets, with the help of useWallet() hook you can easily:

  • select which wallet to use
  • connect to the selected wallet
  • disconnect to the selected wallet
  • call signMessage or signTransaction of the selected wallet

Examples:

function Comp() {
   const { wallet, address, connected, select, connect, disconnect, signMessage, signTransaction } = useWallet();
   return (
       <div>
           <button onClick={() => select('TronLink')}>Select Wallet</button>
           <button onClick={connect}>Connect</button>
           <button onClick={disconnect}>Disconnect</button>
           <button onClick={() => signMessage('Hello World')}>Sign Message</button>
       </div>
   );
}

React UI Components

useWallet() only contains logic to manage wallet state. Besides, we provide a set of out-of-box components to help you interact with wallets:

  • WalletSelectButton: Show wallets dialog to select a wallet.
  • WalletConnectButton: Connect to the selected wallet.
  • WalletDisconnectButton: Disconnect to the selected wallet.
  • WalletActionButton: A Button with multiple actions include select/connect/disconnect.

You can find react demos here.

Here is the demo image:
demo.png

Wallet Adapters

@tronweb3/tronwallet-adapters provides multiple wallet adapters to help developers connect to Tron wallet like TronLink with consistent API.

Supported wallets

As @tronweb3/tronwallet-adapters exports adapter of each wallet , you can use this package, or use the individual wallet adapter you want.

Installation

npm install @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters
# or pnpm install @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters
# or yarn install @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters

Usage

React

You can use @tronweb3/tronwallet-adapters in your component. Use useMemo to memorize the adapter to improve your web performance.

import { TronLinkAdapter } from '@tronweb3/tronwallet-adapters';

function App() {
   const [connectState, setConnectState] = useState(AdapterState.NotFound);
   const [account, setAccount] = useState('');
   const [netwok, setNetwork] = useState({});
   const [signedMessage, setSignedMessage] = useState('');

   const adapter = useMemo(() => new TronLinkAdapter(), []);
   useEffect(() => {
       setConnectState(adapter.state);
       setAccount(adapter.address!);

       adapter.on('connect', () => {
           setAccount(adapter.address!);
       });

       adapter.on('stateChanged', (state) => {
           setConnectState(state);
       });

       adapter.on('accountsChanged', (data) => {
           setAccount(data);
       });

       adapter.on('chainChanged', (data) => {
           setNetwork(data);
       });

       adapter.on('disconnect', () => {
           // when disconnect from wallet
       });
       return () => {
           // remove all listeners when components is destroyed
           adapter.removeAllListeners();
       };
   }, []);

   async function sign() {
       const res = await adapter!.signMessage('helloworld');
       setSignedMessage(res);
   }

   return (
       <div className="App">
           <div>connectState: {connectState}</div>
           <div>current address: {account}</div>
           <div>current network: {JSON.stringify(netwok)}</div>
           <button disabled={adapter.connected} onClick={() => adapter.connect()}>
               Connect to TronLink
           </button>
           <button onClick={sign}>sign message</button>
           <br />
           SignedMessage: {signedMessage}
       </div>
   );
}

Vue

In Vue, as the created/mounted hook just can be executed once, you can init the adapter in mounted or created hook.

// vue2.x
export default {
   created() {
       this.adapter = new TronLinkAdapter();
       this.adapter.on('connect', () => {
           // here you can do something
       });
   },
   beforeDestroy() {
       this.adapter.removeAllListeners();
   }
}

// vue3
export default {
   setup() {
       onMounted(function() {
           const adapter = new TronLinkAdapter();
           adapter.on('connect', () => {
               // here you can do something
           });
       });
       onBeforeUnmount(function() {
           // remove all listeners when components is destroyed
           adapter.removeAllListeners();
       });
       return {};
   }
}

API Reference

Adapter Interface

The Adapter class defines the common interface for all adapters of specified wallets.

Constructor

  • constructor(config): adapter constructor method, an optional config is valid. For detailed config type, refer to the following adapter section.

Properties

  • name: The name of the adapter.
  • url: The website of the adapter's wallet.
  • icon: The icon of the adapter's wallet.
  • state: The adapter's state, which includes three value:
  • NotFound: The wallet is not detected in current browser.
  • Disconnected: The wallet is detected in current browser but the adapter has not connected to wallet yet.
  • Connected: The adapter is connected to wallet.
  • address: The address of current account when the adapter is connected.
  • connecting: Whether the adapter is trying to connect to the wallet.
  • connected: Whether the adapter is connected to the wallet.

Methods

  • connect(): Promise<void>: connect to the wallet.
  • disconnect(): Promise<void>: disconnect to the wallet.
  • signMessage(message): Promise<string>: sign a string, return the signature result.
  • signTransaction(transaction): sign a transaction, return the signature result of the transaction.

Events

Adapter extends the EventEmitter class in eventemitter3 package. So you can listen to the events by adapter.on('connect', function() {}).

Events are as follows:

  • connect(address): Emit when adapter is connected to the wallet. The parameter is the address of current account.
  • disconnect(): Emit when adapter is disconnected to the wallet.
  • stateChanged(state: AdapteraState): Emit when adapter's state is changed. The parameter is the state of adapter:
enum AdapterState {
    NotFound = 'NotFound',
    Disconnect = 'Disconnected',
    Connected = 'Connected',
}
  • accountsChanged(address: string): Emit when users change the current selected account in wallet. The parameter is the address of new account.
  • chainChanged(chainInfo: ChainInfo): Emit when users change the current selected chain in wallet. The parameter is the new network config:
interface ChainInfo {
    node: {
        chain: string;
        fullNode: string;
        solidityNode: string;
        eventServer: string;
    };
}
  • error(ConnectionError): Emit when there are some errors when call the adapter's method. The WalletError Types is defined as follows.

WalletError

WalletError is a superclass which defines the error when using adapter. All error types are extended from this class. Developers can check the error type according to the error instance.

try {
   // do something here
} catch (error: WalletError) {
   if (error instanceof WalletNotFoundError) {
       console.log('Wallet is not found');
   }
}

All errors are as follows:

  • WalletNotFoundError: Occurs when wallet is not installed.
  • WalletNotSelectedError: Occurs when connect but there is no selected wallet.
  • WalletDisconnectedError: Occurs when wallet is disconnected. Used by some wallets which won't connect automatically when call signMessage() or signTransaction().
  • WalletConnectionError: Occurs when try to connect a wallet.
  • WalletDisconnectionError: Occurs when try to disconnect a wallet.
  • WalletSignMessageError: Occurs when call signMessage().
  • WalletSignTransactionError: Occurs when call signTransaction().
  • WalletWalletLoadError: Occurs when load wallet. For WalletConnectAdapter.
  • WalletWindowClosedError: Occurs when walletconnect QR window is closed. For WalletConnectAdapter.

TronLinkAdapter

  • Constructor(config: TronLinkAdapterConfig)
interface TronLinkAdapterConfig {
    /**
    * The icon of your dapp. Used when open TronLink app in mobile device browsers.
    */
    dappIcon?: string;
    /**
    * The name of your dapp. Used when open TronLink app in mobile device browsers.
    */
    dappName?: string;
}
  • Unsupport disconnect by DApp. As TronLinkAdapter doesn't support disconnect by DApp website, call adapter.disconnect() won't disconnect from TronLink extension really.
  • Auto open TronLink app in mobile browser. If developers call connect() method in mobile browser, it will open DApp in TronLink app to get tronlink wallet.

WalletConnectAdapter

  • Constructor(config: WalletConnectAdapterConfig)
interface WalletConnectAdapterConfig {
    /**
    * Network to use, one of Mainnet, Shasta, Nile
    * Default: Nile
    */
    network: 'Mainnet' | 'Shasta' | 'Nile';
    /**
    * Options passed to WalletConnect client
    */
    options: {
        projectId: '<YOUR PROJECT ID>';
        // optional parameters
        relayUrl: '<YOUR RELAY URL>';
        metadata: {
            name: 'Wallet name';
            description: 'A short description for your wallet';
            url: "<YOUR WALLET'S URL>";
            icons: ["<URL TO WALLET'S LOGO/ICON>"];
        };
    };
}

More detail about WalletConnect client options please refer to the WalletConnect document.

LedgerAdapter

  • Constructor(config: LedgerAdapterConfig)
interface LedgerAdapterConfig {
    // Initial total accounts to get once connection is created
    accountNumber: number;
}

Adapter React Hooks

@tronweb3/tronwallet-adapter-react-hooks provides a useWallet() hook which will make it easy to "Connect Wallet" and listen to the state change for developers.

Installation

npm install @tronweb3/tronwallet-adapter-react-hooks @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters
# or pnpm install @tronweb3/tronwallet-adapter-react-hooks @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters
# or yarn install @tronweb3/tronwallet-adapter-react-hooks @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters

Usage

@tronweb3/tronwallet-adapter-react-hooks uses Context of React to maintain a shared data. So developers need to wrap App content within the WalletProvider.

You can provide a onError callback to handle various errors such as WalletNotFoundError,WalletConnectionError.

import { useWallet, WalletProvider } from '@tronweb3/tronwallet-adapter-react-hooks';
import { WalletDisconnectedError, WalletError, WalletNotFoundError } from '@tronweb3/tronwallet-abstract-adapter';
import toast, { Toaster } from 'react-hot-toast';

function App() {
   // use `react-hot-toast` npm package to notify user what happened here
   function onError(e: WalletError) {
       if (e instanceof WalletNotFoundError) {
           toast.error(e.message);
       } else if (e instanceof WalletDisconnectedError) {
           toast.error(e.message);
       } else toast.error(e.message);
   }
   return (
       <WalletProvider onError={onError}>
           <ConnectComponent></ConnectComponent>
           <Profile></Profile>
       </WalletProvider>
   );
}
function ConnectComponent() {
   const { connect, disconnect, select, connected } = useWallet();
   return (<div>
     <button type="button" onClick={() => select('TronLink Adapter' as any)}> Select TronLink</button>
     <button type="button" disabled={connected} onClick={connect}>Connect</button><br>
     <button type="button" disabled={!connected} onClick={disconnect}>Disconnect</button>
   </div>);
}
function Profile() {
   const { address, connected, wallet } = useWallet();
   return (<div>
       <p> <span>Connection Status:</span> {connected ? 'Connected' : 'Disconnected'}</p>
       <p> <span>Your selected Wallet:</span> {wallet?.adapter.name} </p>
       <p> <span>Your Address:</span> {address} </p>
   </div>);
}

API Reference

WalletProvider and useWallet work together like Context.Provider and useContext(). There is a WalletProviderContext underlying which maintains some state and can be obtained with useWallet. So developers need to wrap application components with WalletProvider.

function App() {
   return (
       <div>
           <WalletProvider>/* here is application components */</WalletProvider>
       </div>
   );
}

WalletProvider Props

adapters

  • Required: false
  • Type: Adapter[]
  • Default: [ new TronLinkAdapter() ]

Used to specify what wallet adapters are supported. All wallet adapters can be imported from @tronweb3/tronwallet-adapters package or their standalone package.

  • Example
import { TronLinkAdapter } from '@tronweb3/tronwallet-adapters';
function App() {
    const adapters = useMemo(() => [new TronLinkAdapter()]);
    return (
        <div>
            <WalletProvider adapters={adapters}>/* here is application components */</WalletProvider>
        </div>
    );
}

onError

  • Required: false
  • Type: (error: WalletError): void
  • Default: function(error) { console.error(error); }

Used to handle errors occured when use wallet. Developers can use the callback to tell users what happened according to the error type. All error types can be found here.

  • Example
functon onError(e) {
if (e instanceof WalletNotFoundError) {
        console.error(e.message);
    } else if (e instanceof WalletDisconnectedError) {
        console.error(e.message);
    } else console.error(e.message);
}

autoConnect

  • Required: false
  • Type: boolean
  • Default: true

Whether connect to the specified wallet automatically when loading the page and selecting a wallet.

localStorageKey

  • Required: false
  • Type: string
  • Default: tronAdapterName

Specified the key used to cache wallet name in localStorage. When user select a wallet, applications will cache the wallet name to localStorage.

useWallet()

useWallet is a react hook providing a set of properties and methods which can be used to select and connect wallet, get wallet state and so on.

useWallet() must be used in the descendant components of WalletProvider!

useWallet Returns

autoConnect

  • Type: boolean
    Synchronous with autoConnect property passed to WalletProvider.

wallet

  • Type: Wallet | null
    The wallet current selected. If no wallet is selected, the value is null.

Wallet is defined as follow:

interface Wallet {
   adapter: Adapter; // wallet adapter
   state: AdapterState;
}
enum AdapterState {
   NotFound = 'NotFound',
   Disconnect = 'Disconnected',
   Connected = 'Connected',
}

address

  • Type: string | null
    Address of current selected wallet. If no wallet is selected, the value is null.

wallets

  • Type: Wallet[]
    Wallet list based on current used adapters when initial WalletProvider.

connecting

  • Type: boolean
    Indicate if is connecting to the wallet.

connected

  • Type: boolean
    Indicate if is connected with the wallet.

disconnecting

  • Type: boolean
    Indicate if is connecting to the wallet.

select

  • Type: (walletAdapterName: AdapterName) => void
    Select a wallet by walletAdapterName. Valid adapters can be found here

connect

  • Type: () => Promise<void>
    Connect to current selected wallet.

disconnect

  • Type: () => Promise<void>
    Disconnect from current selected wallet.

signTransaction

  • Type: (transaction: Transaction) => Promise<SignedTransaction>
    Sign a unsigned transaction. This method is the same as TronWeb API.

signMessage

  • Type: (message: string) => Promise<string>
    Sign a message.

Example

import { useWallet } from '@tronweb3/tronwallet-adapter-react-hooks';

function Content() {
   const { connect, disconnect, select, connected } = useWallet();
   return (
       <div>
           <button type="button" onClick={() => select('TronLink Adapter')}>
               Select TronLink
           </button>
           <button type="button" disabled={connected} onClick={connect}>
               Connect
           </button>
           <button type="button" disabled={!connected} onClick={disconnect}>
               Disconnect
           </button>
       </div>
   );
}

Adapter React UI Component

@tronweb3/tronwallet-adapter-react-ui provides a set of out-of-the-box components to make it easy to select, change, connect and disconnect wallet.

This package depends @tronweb3/tronwallet-adapter-react-hooks to work. So developers must wrap App content within the WalletProvider.

Installation

npm install @tronweb3/tronwallet-adapter-react-ui @tronweb3/tronwallet-adapter-react-hooks @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters

# or pnpm install @tronweb3/tronwallet-adapter-react-ui @tronweb3/tronwallet-adapter-react-hooks @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters

# or yarn install @tronweb3/tronwallet-adapter-react-ui @tronweb3/tronwallet-adapter-react-hooks @tronweb3/tronwallet-abstract-adapter @tronweb3/tronwallet-adapters

Usage

@tronweb3/tronwallet-adapter-react-ui provide a Select Wallet Modal by Context.Provider. Developers must wrap App content within the WalletProvider and WalletModalProvider.

import { useWallet, WalletProvider } from '@tronweb3/tronwallet-adapter-react-hooks';
import { WalletModalProvider, WalletActionButton } from '@tronweb3/tronwallet-adapter-react-ui';
import { WalletDisconnectedError, WalletError, WalletNotFoundError } from '@tronweb3/tronwallet-abstract-adapter';
import toast, { Toaster } from 'react-hot-toast';

function App() {
   // here use `react-hot-toast` npm package to notify user what happened
   function onError(e: WalletError) {
       if (e instanceof WalletNotFoundError) {
           toast.error(e.message);
       } else if (e instanceof WalletDisconnectedError) {
           toast.error(e.message);
       } else toast.error(e.message);
   }
   return (
       <WalletProvider onError={onError}>
           <WalletModalProvider>
               <ConnectComponent></ConnectComponent>
               <Profile></Profile>
           </WalletModalProvider>
       </WalletProvider>
   );
}
function ConnectComponent() {
   const { connect, disconnect, select, connected } = useWallet();
   return <WalletActionButton></WalletActionButton>;
}
function Profile() {
   const { address, connected, wallet } = useWallet();
   return (
       <div>
           <p>
               <span>Connection Status:</span> {connected ? 'Connected' : 'Disconnected'}
           </p>
           <p>
               <span>Your selected Wallet:</span> {wallet?.adapter.name}
           </p>
           <p>
               <span>Your Address:</span> {address}
           </p>
       </div>
   );
}

API Reference

WalletModalProvider and useWalletModal

WalletModalProvider provide a Select Wallet Modal by Context.Provider. The modal can be controled by useWalletModal.

function App() {
   const { visible, setVisible } = useWalletModal();
   function toggle() {
       setVisible((visible) => !visible);
   }
   return (
       <div>
           <button onClick={toggle}>{visible ? 'Close Modal' : 'Open Modal'}</button>
       </div>
   );
}

WalletConnectButton

Button to connect to the selected wallet. The button is disabled when:

  • no wallet is selected
  • is connecting to wallet
  • is connected
  • disabled by props

Props

type ButtonProps = PropsWithChildren<{
   className?: string,
   disabled?: boolean,
   onClick?: (e: MouseEvent<HTMLButtonElement>) => void,
   style?: CSSProperties,
   tabIndex?: number,
   icon?: string,
}>;

WalletDisconnectButton

Button to connect to the selected wallet. The button is disabled when:

  • no wallet is selected
  • is connecting to wallet
  • disabled by props

Props

Same as WalletConnectButton.

WalletSelectButton

Button to open Select Wallet Modal.

Props

Same as WalletConnectButton.

WalletActionButton

Button with multiple functions including:

  • Select wallet
  • Connect to wallet
  • Disconnect from wallet
  • Show current selected wallet and address
  • Copy address

It's recommended to use this component to connect wallet easily.
Here is the demo:
example

Props

Same as WalletConnectButton.