Skip to main content

Get started with Wallet Kit

Wallet Kit makes it easy to build Station functionality into your React application. It contains custom hooks that drastically simplify common tasks like connecting a wallet and triggering transactions for both Station mobile and the Station extension.

This guide covers how to set up a React app, integrate Wallet Kit, check the balance of the connected account, and call a token swap. If you want to integrate Station into an existing React app, jump to the Wrap your app in WalletProvider section.

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-kit package:


    _1
    npm install @terra-money/wallet-kit

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 getInitialConfig.

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


_13
import ReactDOM from 'react-dom';
_13
import './index.css';
_13
import App from './App';
_13
import { getInitialConfig, WalletProvider } from '@terra-money/wallet-kit';
_13
_13
getInitialConfig().then((defaultNetworks) => {
_13
ReactDOM.render(
_13
<WalletProvider defaultNetworks={defaultNetworks}>
_13
<App />
_13
</WalletProvider>,
_13
document.getElementById('root'),
_13
);
_13
});

3. Add support for station Mobile

To support Station Mobile:

  1. Install the @terra-money/terra-station-mobile package:


    _1
    npm install @terra-money/terra-station-mobile

  2. Add TerraStationMobileWallet to the extraWallets array prop in the WalletProvider component.


    _17
    import ReactDOM from 'react-dom';
    _17
    import './index.css';
    _17
    import App from './App';
    _17
    import TerraStationMobileWallet from '@terra-money/terra-station-mobile';
    _17
    import { getInitialConfig, WalletProvider } from '@terra-money/wallet-kit';
    _17
    _17
    getInitialConfig().then((defaultNetworks) => {
    _17
    ReactDOM.render(
    _17
    <WalletProvider
    _17
    extraWallets={[new TerraStationMobileWallet()]}
    _17
    defaultNetworks={defaultNetworks}
    _17
    >
    _17
    <App />
    _17
    </WalletProvider>,
    _17
    document.getElementById('root'),
    _17
    );
    _17
    });

4. Start the application

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] // its important to specify the version

  2. Reinstall your dependencies:


    _1
    npm install

  3. Restart your app:


    _1
    npm start

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

5. 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 and useConnectedWallet hooks to connect your Station extension to your web browser.

  1. Create a new component file called Connect.js.

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


_29
import React from 'react';
_29
import { useConnectedWallet, useWallet } from '@terra-money/wallet-kit';
_29
_29
function Connect() {
_29
const connectedWallet = useConnectedWallet();
_29
const { connect, disconnect, availableWallets } = useWallet();
_29
_29
return (
_29
<section>
_29
<h4>Connect info:</h4>
_29
{connectedWallet ? (
_29
<>
_29
<button onClick={() => disconnect()}>Disconnect</button>
_29
<code>
_29
<pre>{JSON.stringify(connectedWallet, null, 2)}</pre>
_29
</code>
_29
</>
_29
) : (
_29
availableWallets.map(({ id, name, isInstalled }) => (
_29
<button onClick={() => connect(id)} disabled={!isInstalled} key={id}>
_29
Connect {name}
_29
</button>
_29
))
_29
)}
_29
</section>
_29
);
_29
}
_29
_29
export default Connect;

  1. 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;

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

  2. 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.

6. Query 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:


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

  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.

7. Send a transaction

You can also create and send transactions to the Terra network while using Wallet Kit. 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 your Station extension, click on Networks, then select Testnets.

You can request testnet 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 retreive the baseAsset from the network object.


    _55
    import { MsgSend } from '@terra-money/feather.js';
    _55
    import { useConnectedWallet, useWallet } from '@terra-money/wallet-kit';
    _55
    import React, { useCallback, useState } from 'react';
    _55
    _55
    const TEST_TO_ADDRESS = 'terra12hnhh5vtyg5juqnzm43970nh4fw42pt27nw9g9';
    _55
    _55
    function Tx() {
    _55
    const [txResult, setTxResult] = useState(null);
    _55
    const [txError, setTxError] = useState('');
    _55
    _55
    const connectedWallet = useConnectedWallet();
    _55
    const wallet = useWallet();
    _55
    const chainID = 'phoenix-1';
    _55
    _55
    const testTx = useCallback(async () => {
    _55
    if (!connectedWallet) {
    _55
    return;
    _55
    }
    _55
    _55
    if (connectedWallet.network === 'mainnet') {
    _55
    alert(`Please only execute this example on Testnet`);
    _55
    return;
    _55
    }
    _55
    _55
    try {
    _55
    const transactionMsg = {
    _55
    chainID,
    _55
    msgs: [
    _55
    new MsgSend(connectedWallet.addresses[chainID], TEST_TO_ADDRESS, {
    _55
    uluna: 1, // parse baseAsset from network object and use here (e.g.`[baseAsset]`)
    _55
    }),
    _55
    ],
    _55
    };
    _55
    _55
    const tx = await wallet.post(transactionMsg);
    _55
    setTxResult(tx);
    _55
    } catch (error) {
    _55
    setTxError(
    _55
    'Error: ' + (error instanceof Error ? error.message : String(error)),
    _55
    );
    _55
    }
    _55
    }, [connectedWallet, wallet]);
    _55
    _55
    return (
    _55
    <>
    _55
    {connectedWallet && !txResult && !txError && (
    _55
    <button onClick={testTx}>Send 1USD to {TEST_TO_ADDRESS}</button>
    _55
    )}
    _55
    _55
    {txResult && <>{JSON.stringify(txResult, null, 2)}</>}
    _55
    {txError && <pre>{txError}</pre>}
    _55
    </>
    _55
    );
    _55
    }
    _55
    export default Tx;

    📝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. After refreshing 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.