This site requires Javascript to be enabled.

Building a dApp frontend

For building web frontends, you'll need the arch3.js npm package to connect your web page to the Archway Network.

Connecting to Archway

We’ll need our dapp to connect to users’ wallets with a browser extension like Keplr.

After installing the extension, you’ll notice Keplr is exposed to web pages as a property of the JavaScript window object.

Keplr also needs specific metadata regarding the chain it is connecting to. Below are the necessary parameters for establishing a connection with Archway's Constantine testnet.

const ChainInfo = {  chainId: 'constantine-3',  chainName: 'Constantine Testnet',  rpc: '',  rest: '',  stakeCurrency: { coinDenom: 'CONST', coinMinimalDenom: 'aconst', coinDecimals: 18 },  bip44: { coinType: 118 },  bech32Config: {    bech32PrefixAccAddr: 'archway',    bech32PrefixAccPub: 'archwaypub',    bech32PrefixValAddr: 'archwayvaloper',    bech32PrefixValPub: 'archwayvaloperpub',    bech32PrefixConsAddr: 'archwayvalcons',    bech32PrefixConsPub: 'archwayvalconspub',  },  currencies: [{ coinDenom: 'CONST', coinMinimalDenom: 'aconst', coinDecimals: 18 }],  feeCurrencies: [{ coinDenom: 'CONST', coinMinimalDenom: 'aconst', coinDecimals: 18 }],  coinType: 118,  gasPriceStep: { low: 0, average: 0.1, high: 0.2 },  features: ['cosmwasm'],};

Now we can use ChainInfo to set up Keplr for Constantine testnet.

import { SigningArchwayClient } from '@archwayhq/arch3.js';let accounts, CosmWasmClient, queryHandler;async function connectKeplrWallet() {  if (window['keplr']) {    if (window.keplr['experimentalSuggestChain']) {      await window.keplr.experimentalSuggestChain();      await window.keplr.enable(ChainInfo.chainId);      window.keplr.defaultOptions = {        sign: {          preferNoSetFee: true,        }      }      const offlineSigner = await window.getOfflineSignerAuto(ChainInfo.chainId);      CosmWasmClient = await SigningArchwayClient.connectWithSigner(ChainInfo.rpc, offlineSigner);      // This async waits for the user to authorize your dapp      // it returns their account address only after permissions      // to read that address are granted      accounts = await this.offlineSigner.getAccounts();      // A less verbose reference to handle our queries      queryHandler = CosmWasmClient.queryContractSmart;      console.log('Wallet connected', {        offlineSigner: offlineSigner,        CosmWasmClient: CosmWasmClient,        accounts: accounts,        chain: ChainInfo,        queryHandler: queryHandler,      });    } else {      console.warn('Error accessing experimental features, please update Keplr');    }  } else {    console.warn('Error accessing Keplr, please install Keplr');  }}


One thing to note is that, by default, Keplr overrides the fees set by the frontend. To prevent Keplr from overriding these fees, set the Interactive Option value of preferNoSetFee to true, as shown in the example above. You can find more information on these override options here.

Querying the counter

In the previous step we saved a reference to CosmWasmClient.queryContractSmart. We'll use it to query our QueryMsg::GetCount entrypoint of the Increment contract.

Just like when we queried from CLI, we need to convert entrypoints to lowercase and snake case. In JavaScript the arguments become {get_count: {}}.

const getCount = async () => {  // Your contract address  const ContractAddress = process.env.CONTRACT_ADDRESS;  // Query arguments  let entrypoint = {    get_count: {}  };  // Do query type 'smart'  let queryResult = await queryHandler.query(ContractAddress, entrypoint);  console.log('GetCount Query', queryResult);},

Incrementing the counter

To broadcast transactions we call the execute function using our previous CosmWasmClient reference. We call this function with the following parameters:

  1. userAddress - the address broadcasting the transaction
  2. ContractAddress - the address of the contract with which the user is carrying out a transaction.
  3. entrypoint - arguments to be executed which match an entrypoint in the contract
  4. Fee - with arch3.js transaction fees can be automatically calculated using "auto".

We convert the case of entrypoint arguments to lowercase and snake case again, so ExecuteMsg::Increment {} from our Rust contract becomes {increment: {}} in our JavaScript.

const incrementCounter = async () => {  // Your contract address  const ContractAddress = process.env.CONTRACT_ADDRESS;  // Tx arguments  let entrypoint = {    increment: {},  };  // Send Tx  let tx = await CosmWasmClient.execute(userAddress, ContractAddress, entrypoint, 'auto');  console.log('Increment Tx', tx);};

Clone it and try yourself

You will find working examples of dapp frontends for the Increment starter code template in the dapp examples repository.

Optimising dApp Functionality with Indexers

After completing this guide, integrate SubQuery for efficient data retrieval and enhanced functionality. This blockchain indexer goes beyond historical data, enabling quick queries, supporting smart contracts, and providing real-time data for applications. Enhance user experiences and unlock the full potential of your dapp across diverse use cases by leveraging these powerful indexers.