Handling accounts

On this page, you’ll learn how to create a new account and how to fetch details of an account through a frontend.

On this page, you’ll learn:

  • How to create a new account through a UI.

  • How to fetch details of an account and display them on a UI.

The relevant files discussed in this guide are the newAccount.js and the getAccountDetails.js.

1. Creating a new account

The newAccount.js in the hello_frontend/src/components/ directory is specifically created to implement the account creation process.

The new accounts page will create a new account on a page load. For that, we will use the passphrase and cryptography libraries of the lisk-client.

hello_frontend/src/components/newAccount.js
// [...]
// UI libraries import
import React, { useState, useEffect } from "react";
// Lisk libraries import
import { passphrase, cryptography } from '@liskhq/lisk-client/browser';

function NewAccount() {

    // State variables and function to store new account
    const [accounts, createNewAccount] = useState('');

    useEffect(() => {
        createAccount()
    }, [])

    const createAccount = async () => {
        // Default key path
        const accountKeyPath = "m/44'/134'/0'";
        // Randomly generated passphrase
        const mnemonicPassphrase = passphrase.Mnemonic.generateMnemonic(256);
        // Private key of new account
        const privateKey = await cryptography.ed.getPrivateKeyFromPhraseAndPath(
            mnemonicPassphrase,
            accountKeyPath,
        );
        // Public key of new account
        const publicKey = cryptography.ed.getPublicKeyFromPrivateKey(privateKey);
        // Lisk32 address
        const address = cryptography.address.getLisk32AddressFromPublicKey(publicKey);
        const credentials = {
            address,
            passphrase: mnemonicPassphrase,
            privateKey: privateKey.toString('hex'),
            publicKey: publicKey.toString('hex'),
        };
        createNewAccount(credentials);
        return credentials;
    };
    // [...]
}
export default NewAccount;

The createAccount function will generate a passphrase, a key pair (public and private), and a Lisk32 address of a new account by using the passphrase and cryptography libraries available in the lisk-client package.

To display the credentials generated above, it will also be necessary to update the return function.

hello_frontend/src/components/newAccount.js
// [...]

function NewAccount() {
    // [...]
    return (
        <div>
            <FixedMenuLayout />
            <Container>

                <div>

                    <div class="ui green segment">
                        <i class="lightbulb outline icon"></i><strong>TIP:</strong> Reload the page to generate a new account.
                    </div>

                    <h2>New account created!</h2>
                    <Divider></Divider>
                    <div className='App'>
                        <pre>{JSON.stringify(accounts, null, 2)}</pre>
                    </div>
                </div>

            </Container>
        </div>
    );
}
// [...]

Start the hello_frontend, and then click on the Account→Create Account option in the menu bar. Once the page has loaded, the credentials of the new account will be visible.

new account page
Figure 1. Create a new account page

2. Getting account details

With a working account creation feature, let’s update the getAccountDetails.js in the hello_frontend/src/components/ directory to support the fetching account details feature.

hello_frontend/src/components/getAccountDetails.js
// [...]
// UI libraries import
import React, { useState } from "react";
// Import api.js
import * as api from '../api';

function GetAccountDetails() {
    // State variables and function to store account details.
    const [state, updateState] = useState({
        address: '',
        error: '',
        account: {},
        auth: {},
        hello: {}
    });
    // Will get triggered when the value is changed in the input.
    const handleChange = (event) => {
        const { name, value } = event.target;
        updateState({
            ...state,
            [name]: value,
        });
    };
    // Will get triggered on 'Submit'.
    const handleSubmit = async (event) => {
        event.preventDefault();
        const client = await api.getClient();
        let responseError = '';
        let authenticationDetails;
        let accountBalance;
        let latestHello;

        // Retrieves the account details from the blockchain, based on the provided address.
        await client.invoke("token_getBalance", {
            address: state.address,
            tokenID: "0000000100000000" // It can be found in the genesis_assets.json file of the client.
        }).then(async response => {
            if (typeof response.error !== 'undefined') {
                responseError = response.error.message
            } else {
                accountBalance = response;
                const authDetails = await client.invoke("auth_getAuthAccount", {
                    address: state.address,
                    tokenID: "0000000100000000"
                });
                authenticationDetails = authDetails;
            }
            const helloMessage = await client.invoke("hello_getHello", {
                address: state.address,
            })
            if (typeof helloMessage.message === 'string') {
                latestHello = helloMessage;
            }
            else if (helloMessage.error.message.includes("does not exist")) {
                latestHello = "message not found";
            }
            return [response, authenticationDetails, latestHello];
        })

        updateState({
            ...state,
            error: responseError,
            account: accountBalance,
            auth: authenticationDetails,
            hello: latestHello
        });
    };
    // [...]
}
export default GetAccountDetails;

The handleSubmit function will use the apiClient to invoke the token_getBalance and auth_getAuthAccount endpoints. It will also invoke the hello_getHello endpoint to fetch the latest hello message sent from the given address.

The response to these requests will be shown to the user with the displayData function described in the following snippet:

hello_frontend/src/components/getAccountDetails.js
// [...]

function GetAccountDetails() {
        // [...]
        const displayData = () => {
        // If an error occurs, display the appropriate error.
        if (state.error !== '') {
            return (
                <>
                    <div className="ui red segment" style={{ overflow: 'auto' }}>
                        <h3>Something went wrong! :(</h3>
                        <pre><strong>Error:</strong> {JSON.stringify(state.error, null, 2)}</pre>
                    </div>
                </>
            )
        }
        // If no hello message is found, only show account and auth details.
        else if (state.hello === 'message not found') {
            return (
                <>
                    <h3>Your account details are:</h3>
                    <div className="ui green segment" style={{ overflow: 'auto' }}>
                        <pre>Account: {JSON.stringify(state.account, null, 2)}</pre>
                        <pre>Authentication details: {JSON.stringify(state.auth, null, 2)}</pre>
                    </div>
                </>
            )
        }
        // Check the values of the response received and display data accordingly.
        else if (typeof state.account !== 'undefined' && state.account.availableBalance >= 0 && state.hello !== 'message not found') {
            return (
                <>
                    <h3>Your account details are:</h3>
                    <div className="ui green segment" style={{ overflow: 'auto' }}>
                        <pre>Account: {JSON.stringify(state.account, null, 2)}</pre>
                        <pre>Authentication details: {JSON.stringify(state.auth, null, 2)}</pre>
                        <pre>Latest Hello message: {JSON.stringify(state.hello, null, 2)}</pre>
                    </div>
                </>
            )
        }
        else {
            return (<p></p>)
        }
    }
    // [...]
}
// [...]

Finally, in the return function, we will call the displayData function to display the appropriate response.

hello_frontend/src/components/getAccountDetails.js
// [...]

function GetAccountDetails() {
        // [...]
    return (
        <div>
            <FixedMenuLayout />
            <Container>
                <h2>Account details</h2>
                <p>Get account details by submitting a Lisk32 address.</p>
                <Divider></Divider>
                <div className="ui two column doubling stackable grid container">
                    <div className="column">

                        <Form onSubmit={handleSubmit}>
                            <Form.Field>
                                <label>Lisk32 address:</label>
                                <input placeholder="Lisk32 address" id="address" name="address" onChange={handleChange} value={state.address} />
                            </Form.Field>
                            <Button type='submit' fluid size='large' style={{ backgroundColor: '#2BD67B', color: 'white' }}>Submit</Button>
                        </Form>
                    </div>

                    <div className='column'>
                        <>
                            {displayData()}
                        </>
                    </div>
                </div>
            </Container >
        </div >
    );
}
// [...]

Start the hello_client and ensure that the hello_frontend is running as well.

Create a new account using the Create Account page, copy the address, and open the Account→Account details page.

Paste the copied Lisk32 address and click on the Submit button. The UI will display the account details similar to the following snapshot:

get details page
Figure 2. Get account details

In the case whereby an error occurs, it will be displayed in the UI, as in the displayData function we have also implemented error handling.

get details page-error
Figure 3. Error in fetching details on an account