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 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.
nvm install 16 nvm use 16
Copy

1. Project Setup

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

    npx create-react-app my-terra-app
    cd my-terra-app
    Copy
  2. Then, install the @terra-money/wallet-kit package:

    npm install @terra-money/wallet-kit
    Copy

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:

import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { getInitialConfig, WalletProvider } from '@terra-money/wallet-kit';

getInitialConfig().then((defaultNetworks) => {
ReactDOM.render(
<WalletProvider defaultNetworks={defaultNetworks}>
<App />
</WalletProvider>,
document.getElementById('root'),
);
});
Copy

3. Add support for station Mobile

To support Station Mobile:

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

    npm install @terra-money/terra-station-mobile
    Copy
  2. Add TerraStationMobileWallet to the extraWallets array prop in the WalletProvider component.

    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import TerraStationMobileWallet from '@terra-money/terra-station-mobile';
    import { getInitialConfig, WalletProvider } from '@terra-money/wallet-kit';

    getInitialConfig().then((defaultNetworks) => {
    ReactDOM.render(
    <WalletProvider
    extraWallets={[new TerraStationMobileWallet()]}
    defaultNetworks={defaultNetworks}
    >
    <App />
    </WalletProvider>,
    document.getElementById('root'),
    );
    });
    Copy

4. Start the application

Start the application to make sure it works:

npm start
Copy

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:

    npm install react-scripts@4.0.3 // its important to specify the version
    Copy
  2. Reinstall your dependencies:

    npm install
    Copy
  3. Restart your app:

    npm start
    Copy

  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:

import React from 'react';
import { useConnectedWallet, useWallet } from '@terra-money/wallet-kit';

function Connect() {
const connectedWallet = useConnectedWallet();
const { connect, disconnect, availableWallets } = useWallet();

return (
<section>
<h4>Connect info:</h4>
{connectedWallet ? (
<>
<button onClick={() => disconnect()}>Disconnect</button>
<code>
<pre>{JSON.stringify(connectedWallet, null, 2)}</pre>
</code>
</>
) : (
availableWallets.map(({ id, name, isInstalled }) => (
<button onClick={() => connect(id)} disabled={!isInstalled} key={id}>
Connect {name}
</button>
))
)}
</section>
);
}

export default Connect;
Copy
  1. Open App.js in your code editor and replace the code with the following:
import './App.css';
import Connect from './components/Connect';

function App() {
return (
<div className="App">
<header className="App-header">
<Connect />
</header>
</div>
);
}

export default App;
Copy
  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:

    import { useConnectedWallet, useLcdClient } from '@terra-money/wallet-kit';
    import React, { useEffect, useState } from 'react';

    export default function Query() {
    const lcd = useLcdClient(); // LCD stands for Light Client Daemon
    const connected = useConnectedWallet();
    const [balance, setBalance] = useState('');
    const chainID = 'phoenix-1'; // or any other mainnet or testnet chainID supported by station (e.g. osmosis-1)

    useEffect(() => {
    if (connected) {
    lcd.bank.balance(connected.addresses[chainID]).then(([coins]) => {
    setBalance(coins.toString());
    });
    } else {
    setBalance(null);
    }
    }, [connected, lcd]); // useEffect is called when these variables change

    return (
    <div>
    {balance && <p>{balance}</p>}
    {!connected && <p>Wallet not connected!</p>}
    </div>
    );
    }
    Copy
  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:

    import './App.css';
    import Connect from './components/Connect';
    import Query from './components/Query';

    function App() {
    return (
    <div className="App">
    <header className="App-header">
    <Connect />
    <Query />
    </header>
    </div>
    );
    }

    export default App;
    Copy
  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:

npm install @terra-money/feather.js
Copy

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.

    import { MsgSend } from '@terra-money/feather.js';
    import { useConnectedWallet, useWallet } from '@terra-money/wallet-kit';
    import React, { useCallback, useState } from 'react';

    const TEST_TO_ADDRESS = 'terra12hnhh5vtyg5juqnzm43970nh4fw42pt27nw9g9';

    function Tx() {
    const [txResult, setTxResult] = useState(null);
    const [txError, setTxError] = useState('');

    const connectedWallet = useConnectedWallet();
    const wallet = useWallet();
    const chainID = 'phoenix-1';

    const testTx = useCallback(async () => {
    if (!connectedWallet) {
    return;
    }

    if (connectedWallet.network === 'mainnet') {
    alert(`Please only execute this example on Testnet`);
    return;
    }

    try {
    const transactionMsg = {
    chainID,
    msgs: [
    new MsgSend(connectedWallet.addresses[chainID], TEST_TO_ADDRESS, {
    uluna: 1, // parse baseAsset from network object and use here (e.g.`[baseAsset]`)
    }),
    ],
    };

    const tx = await wallet.post(transactionMsg);
    setTxResult(tx);
    } catch (error) {
    setTxError(
    'Error: ' + (error instanceof Error ? error.message : String(error)),
    );
    }
    }, [connectedWallet, wallet]);

    return (
    <>
    {connectedWallet && !txResult && !txError && (
    <button onClick={testTx}>Send 1USD to {TEST_TO_ADDRESS}</button>
    )}

    {txResult && <>{JSON.stringify(txResult, null, 2)}</>}
    {txError && <pre>{txError}</pre>}
    </>
    );
    }
    export default Tx;
    Copy
    📝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:

    import './App.css';
    import Connect from './components/Connect';
    import Query from './components/Query';
    import Tx from './components/Tx';

    function App() {
    return (
    <div className="App">
    <header className="App-header">
    <Connect />
    <Query />
    <Tx />
    </header>
    </div>
    );
    }

    export default App;
    Copy
  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.