var img = document.createElement('img'); img.src = "https://terradocs.matomo.cloud//piwik.php?idsite=1&rec=1&url=https://docs.terra.money" + location.pathname; img.style = "border:0"; img.alt = "tracker"; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(img,s);
Skip to main content

Get started with Wallet Provider

☢️Warning

Wallet-Provider is deprecated. Use Wallet Kit instead.

Wallet Provider makes it easy to build Station (browser extension and mobile) functionality into your React application. It contains custom hooks that drastically simplify common tasks like connecting a wallet and triggering transactions.

This guide will cover how to set up a React app, integrate Wallet Provider, check the balance of the connected account, and call a token swap. If you want to integrate Station into an existing React app you can skip past the Project Setup section.

💡Just want to dive in?

Check out the getting started section for the premade templates on GitHub.

If you're using a frontend framework other than React you'll need to use Wallet Controller instead. Controller provides the sub-structure of Provider. You can see an example of how Wallet Controller works in the Vue.js template example.

Prerequisites

💡Node version 16
Most users will need to specify Node version 16 before continuing. You can manage node versions with NVM.

_1
nvm install 16 nvm use 16

1. Project Setup

  1. To get started, you'll need some basic React scaffolding. To generate this, run the following in your terminal:


    _2
    npx create-react-app my-terra-app
    _2
    cd my-terra-app

  2. Then, install the @terra-money/wallet-provider package:


    _1
    npm install @terra-money/wallet-provider

2. Wrap your app in WalletProvider

Next, you'll wrap your App with <WalletProvider> to give all your components access to useful data, hooks, and utilities. You'll also need to pass in information about Terra networks, such as the mainnet or chainId, into the provider via getChainOptions.

  1. Navigate to your Index.js in a code editor and replace the code with the following:


    _17
    import ReactDOM from 'react-dom';
    _17
    import './index.css';
    _17
    import App from './App';
    _17
    import reportWebVitals from './reportWebVitals';
    _17
    import {
    _17
    getChainOptions,
    _17
    WalletProvider,
    _17
    } from '@terra-money/wallet-provider';
    _17
    _17
    getChainOptions().then((chainOptions) => {
    _17
    ReactDOM.render(
    _17
    <WalletProvider {...chainOptions}>
    _17
    <App />
    _17
    </WalletProvider>,
    _17
    document.getElementById('root'),
    _17
    );
    _17
    });

  2. Start the application to make sure it works:


    _1
    npm start

Your browser should open to http://localhost:3000/ and you should see the react logo with a black background and some text.

Polyfill errors
Getting polyfill errors?

To solve these errors, can downgrade react-scripts: 4.0.3 in your package.json and reinstall your dependencies as a quick fix:

  1. Navigate to my-terra-app in your terminal and run the following:


    _1
    npm install [email protected]

  2. Reinstall your dependencies:


    _1
    npm install

  3. Restart your app:


    _1
    npm start

Alternatively, you can configure your webpack to include the necessary fallbacks. Here's an example that uses react-app-rewired.

  1. Create a new directory called components in the source directory. This directory will house components to trigger different actions from our connected wallet.

3. Put useWallet to work

Now that App.js has inherited the context of WalletProvider, you can start putting your imports to work. You'll use the multi-purpose useWallet hook to connect your Station extension to your web browser.

  1. Create a new file in the components directory called Connect.js.

  2. Populate the Connect.js file with the following:


    _38
    import { useWallet, WalletStatus } from '@terra-money/wallet-provider';
    _38
    import React from 'react';
    _38
    export default function Connect() {
    _38
    const {
    _38
    status,
    _38
    network,
    _38
    wallets,
    _38
    availableConnectTypes,
    _38
    connect,
    _38
    disconnect,
    _38
    } = useWallet();
    _38
    _38
    const chainID = 'phoenix-1'; // or any other mainnet or testnet chainID supported by station (e.g. osmosis-1)
    _38
    return (
    _38
    <>
    _38
    {JSON.stringify(
    _38
    { status, network: network[chainID], wallets },
    _38
    null,
    _38
    2,
    _38
    )}
    _38
    {status === WalletStatus.WALLET_NOT_CONNECTED && (
    _38
    <>
    _38
    {availableConnectTypes.map((connectType) => (
    _38
    <button
    _38
    key={'connect-' + connectType}
    _38
    onClick={() => connect(connectType)}
    _38
    >
    _38
    Connect {connectType}
    _38
    </button>
    _38
    ))}
    _38
    </>
    _38
    )}
    _38
    {status === WalletStatus.WALLET_CONNECTED && (
    _38
    <button onClick={() => disconnect()}>Disconnect</button>
    _38
    )}
    _38
    </>
    _38
    );
    _38
    }

  3. Open App.js in your code editor and replace the code with the following:


    _14
    import './App.css';
    _14
    import Connect from './components/Connect';
    _14
    _14
    function App() {
    _14
    return (
    _14
    <div className="App">
    _14
    <header className="App-header">
    _14
    <Connect />
    _14
    </header>
    _14
    </div>
    _14
    );
    _14
    }
    _14
    _14
    export default App;

  4. Refresh your browser. There should be some new text and buttons in your browser.

  5. Make sure your Station extension is connected to a wallet. Click Connect EXTENSION and the app will connect to your wallet.

The status, network, and wallets properties in your browser provide useful information about the state of the Terra wallet. Before connecting, the status variable will be WALLET_NOT_CONNECTED and upon connection the status becomes WALLET_CONNECTED. In addition, the wallets array now has one entry with the connectType and terraAddress you used to connect.

You should be able to see these changes in real-time.

4. Querying a wallet balance

It's common for an app to show the connected user's LUNA balance. To achieve this you'll need two hooks. The first is useLCDClient. An LCDClient is essentially a REST-based adapter for the Terra blockchain. You can use it to query an account balance. The second is useConnectedWallet, which tells you if a wallet is connected and, if so, basic information about that wallet such as its address.

Be aware that you will not see any tokens if your wallet is empty.

  1. Create a file in your Components folder named Query.js.

  2. Populate Query.js with the following:


    _31
    import {
    _31
    useConnectedWallet,
    _31
    useLCDClient,
    _31
    } from '@terra-money/wallet-provider';
    _31
    import React, { useEffect, useState } from 'react';
    _31
    _31
    export default function Query() {
    _31
    const lcd = useLCDClient(); // LCD stands for Light Client Daemon
    _31
    const connectedWallet = useConnectedWallet();
    _31
    const [balance, setBalance] = useState<null | string>(null);
    _31
    const chainID = 'phoenix-1'; // or any other mainnet or testnet chainID supported by station (e.g. osmosis-1)
    _31
    _31
    useEffect(() => {
    _31
    if (connectedWallet) {
    _31
    lcd.bank
    _31
    .balance(connectedWallet.addresses[chainID])
    _31
    .then(([coins]) => {
    _31
    setBalance(coins.toString());
    _31
    });
    _31
    } else {
    _31
    setBalance(null);
    _31
    }
    _31
    }, [connectedWallet, lcd]); // useEffect is called when these variables change
    _31
    _31
    return (
    _31
    <div>
    _31
    {balance && <p>{balance}</p>}
    _31
    {!connectedWallet && <p>Wallet not connected!</p>}
    _31
    </div>
    _31
    );
    _31
    }

  3. Open App.js in your code editor and add import Query from './components/Query' to line 3, and <Query /> to line 10. The whole file should look like the following:


    _16
    import './App.css';
    _16
    import Connect from './components/Connect';
    _16
    import Query from './components/Query';
    _16
    _16
    function App() {
    _16
    return (
    _16
    <div className="App">
    _16
    <header className="App-header">
    _16
    <Connect />
    _16
    <Query />
    _16
    </header>
    _16
    </div>
    _16
    );
    _16
    }
    _16
    _16
    export default App;

  4. Refresh your browser. Your wallet balance will appear in micro-denominations. Multiply by 10610^6 for an accurate balance.

5. Sending a transaction

You can also create and send transactions to the Terra network while utilizing Wallet Provider. You can use feather.js to generate a sample transaction:


_1
npm install @terra-money/feather.js

Before broadcasting this example transaction, ensure you're on the Terra testnet. To change networks click the gear icon in Station and select testnet.

You can request tesnet funds from the Terra Testnet Faucet.

To transfer LUNA, you will need to supply a message containing the sender address, recipient address, and send amount (in this case 1 LUNA), as well as fee parameters. Once the message is constructed, the post method on connectedWallet broadcasts it to the network.

📝What happens if something goes wrong?

Wallet Provider supplies useful error types. This example will handle the UserDenied error case, but you can find other cases for error handling on GitHub.

  1. Create a file in your Components folder named Tx.js.

  2. Populate Tx.js with the following. To make this example interchain retrieve the baseAsset from the network object.


    _70
    import { Fee, MsgSend } from '@terra-money/feather.js';
    _70
    import {
    _70
    useConnectedWallet,
    _70
    UserDenied,
    _70
    } from '@terra-money/wallet-provider';
    _70
    import React, { useCallback, useState } from 'react';
    _70
    _70
    const TEST_TO_ADDRESS = 'terra12hnhh5vtyg5juqnzm43970nh4fw42pt27nw9g9';
    _70
    _70
    export default function Tx() {
    _70
    const [txResult, setTxResult] = useState<TxResult | null>(null);
    _70
    const [txError, setTxError] = useState<string | null>(null);
    _70
    _70
    const connectedWallet = useConnectedWallet();
    _70
    const chainID = 'phoenix-1';
    _70
    _70
    const testTx = useCallback(async () => {
    _70
    if (!connectedWallet) {
    _70
    return;
    _70
    }
    _70
    _70
    const isMainnet = Object.keys(connectedWallet.network).some((key) =>
    _70
    key.startsWith('phoenix-'),
    _70
    );
    _70
    _70
    if (isMainnet) {
    _70
    alert(`Please only execute this example on Testnet`);
    _70
    return;
    _70
    }
    _70
    _70
    try {
    _70
    const transactionMsg = {
    _70
    fee: new Fee(1000000, '20000uluna'),
    _70
    chainID,
    _70
    msgs: [
    _70
    new MsgSend(connectedWallet.addresses[chainID], TEST_TO_ADDRESS, {
    _70
    uluna: 1000000, // parse baseAsset from network object and use here (e.g.`[baseAsset]`)
    _70
    }),
    _70
    ],
    _70
    };
    _70
    _70
    const tx = await connectedWallet.post(transactionMsg);
    _70
    setTxResult(tx);
    _70
    } catch (error) {
    _70
    if (error instanceof UserDenied) {
    _70
    setTxError('User Denied');
    _70
    } else {
    _70
    setTxError(
    _70
    'Unknown Error: ' +
    _70
    (error instanceof Error ? error.message : String(error)),
    _70
    );
    _70
    }
    _70
    }
    _70
    }, [connectedWallet]);
    _70
    _70
    return (
    _70
    <>
    _70
    {connectedWallet?.availablePost && !txResult && !txError && (
    _70
    <button onClick={testTx}>Send 1USD to {TEST_TO_ADDRESS}</button>
    _70
    )}
    _70
    _70
    {txResult && <>{JSON.stringify(txResult, null, 2)}</>}
    _70
    {txError && <pre>{txError}</pre>}
    _70
    _70
    {connectedWallet && !connectedWallet.availablePost && (
    _70
    <p>This connection does not support post()</p>
    _70
    )}
    _70
    </>
    _70
    );
    _70
    }

    📝note

    Because all coins are denominated in micro-units, you will need to multiply any coins by 10610^6 . For example, 1000000 uluna = 1 LUNA.

  3. Open App.js in your code editor and add import Tx from './components/Tx' to line 4, and <Tx /> to line 12. The whole file should look like the following:


    _18
    import './App.css';
    _18
    import Connect from './components/Connect';
    _18
    import Query from './components/Query';
    _18
    import Tx from './components/Tx';
    _18
    _18
    function App() {
    _18
    return (
    _18
    <div className="App">
    _18
    <header className="App-header">
    _18
    <Connect />
    _18
    <Query />
    _18
    <Tx />
    _18
    </header>
    _18
    </div>
    _18
    );
    _18
    }
    _18
    _18
    export default App;

  4. Refresh your browser. You'll see a new Send button. Click the button to send your transaction. Your Station extension will ask you to confirm the transaction.

That's all! You can find more examples of WalletProvider capabilities in the following example templates: