Front end

This tutorial will show you how to develop a front-end app (JavaScript in our case) that will demonstrate how to interact with a contract that was developed with Boilerplate.

At the top-level Boilerplate contains two folders:

  • chain : used for developing the contracts.
  • web : used for developing the front-end.

The web folder already contains some projects that can serve as examples. This tutorial presents a front-end for the Greeter contract shown in the previous tutorials.

Run the front-end

After you run Boilerplate, open another terminal at the repo’s root and navigate to the greeter project:

cd web/greeter

From here, you can install and run the Greeter’s front end:

npm i
npm start

And a page will be opened by webpack in your default browser.

Front-end code

The code is straightforward, it uses aelf-sdk + webpack. You can check out more here.

Warning: be careful, this code is in no way production-ready and is for demonstration purposes only.

It demonstrates the following capabilities of the js sdk:

  • getting the chain status.
  • getting a contract object.
  • calling a contract method.
  • calling a view method.

Getting the chain status

The following code snippet shows how to call the nodes API to get the chains status:

aelf.chain.getChainStatus()
    .then(res => {
        if (!res) {
            throw new Error('Error occurred when getting chain status');
        }
        // use the chain status
    })
    .catch(err => {
        console.log(err);
    });

For more information about the chain status API : GET /api/blockChain/chainStatus.

As we will see next, the chain status is very useful for retrieving the genesis contract.

getting a contract object

The following code snippet shows how to get a contract object with the js-sdk:

async function getContract(name, walletInstance) {

    // if not loaded, load the genesis
    if (!genesisContract) {
        const chainStatus = await aelf.chain.getChainStatus();
        if (!chainStatus) {
            throw new Error('Error occurred when getting chain status');
        }
        genesisContract = await aelf.chain.contractAt(chainStatus.GenesisContractAddress, walletInstance);
    }

    // if the contract is not already loaded, get it by name.
    if (!contract[name]) {
        const address = await genesisContract.GetContractAddressByName.call(sha256(name));
        contract = {
            ...contract,
            [name]: await aelf.chain.contractAt(address, walletInstance)
        };
    }
    return contract[name];
}

As seen above, the following steps will enable you to build a contract object:

  • use getChainStatus to get the genesis contract’s address.
  • use contractAt to build an instance of the genesis contract.
  • use the genesis contract to get the address of the greeter contract with the GetContractAddressByName method.
  • with the address use contractAt again to build a greeter contract object.

Once you have a reference to the greeter contract, you can use it to call the methods.

calling a contract method

The following snippet shows how to send a transaction to the contract:

    greetToButton.onclick = () => {

        getContract('AElf.ContractNames.Greeter', wallet)
            .then(greeterContract => greeterContract.GreetTo({
                value: "SomeName"
            }))
            .then(tx => pollMining(tx.TransactionId))
            .then(ret => {
                greetToResponse.innerHTML = ret.ReadableReturnValue;
            })
            .catch(err => {
                console.log(err);
            });
    };

Here the getContract retrieves the greeter contract instance. On the instance it calls GreetTo that will send a transaction to the node. The pollMining method is a helper method that will wait for the transaction to be mined. After mined the transaction results, ReadableReturnValue will be used to see the result.

calling a view method

The following snippet shows how to call a view method on the contract:

    getGreeted.onclick = () => {

        getContract('AElf.ContractNames.Greeter', wallet)
            .then(greeterContract => greeterContract.GetGreetedList.call())
            .then(ret => {
                greeted.innerHTML = JSON.stringify(ret, null, 2);
            })
            .catch(err => {
                console.log(err);
            });
    };

Here the getContract retrieves the greeter contract instance. On the instance, it calls GetGreetedList with “.call” appended to it, which will indicate a read-only execution (no broadcasted transaction).