Intro to VeChain

V. Connect Frontend to a Contract: In Detail

This section covers how to integrate VeChain’s DApp Kit into your frontend.

Connecting the Frontend with the DApp Kit

If you’re using the repository example, the frontend is located in the apps/frontend directory. It’s a Vite-powered React app.

You can start the dev server with:

cd apps/frontend
yarn dev

This opens the app at http://localhost:XXXX (the port depends on your configuration), and you’ll see the UI, which already includes a Connect Wallet button, input fields, etc. Verify that your app uses the smart contract you have deployed earlier.

In the example, contract address and ABI are updated automatically with the deploy script, but you can also define them manually inside your front-end app.

Let’s say there’s a file where you do something like:

const CONTRACT_ADDRESS = '0xYourContractAddress...';
const COFFEE_CONTRACT_ABI = [ 
  /* ... ABI JSON ... */
];

Make sure to replace '0xYourContractAddress...' with the actual address output from your Hardhat deployment, and ensure the ABI exactly matches your compiled contract’s ABI. Now, with the address and ABI set, the frontend can create a contract instance for calls.

VeChain’s DApp Kit greatly simplifies wallet connections in the browser. It provides a React context and hooks that manage the connection state.

main.tsx:
In the main React entry (App component), the app should be wrapped with a provider from DApp Kit — this is typically DAppKitProvider, which establishes a connection to the blockchain and the user’s wallet across the app.

DApp Kit is also available for Angular, Next, Remix, Svelte, Vue, and in a pure js vanilla version.

apps/frontend/src/main.tsx

import { DAppKitProvider } from '@vechain/dapp-kit-react';
import {THOR_URL} from "./config/constants.ts";
function App() {
  return (
    <DAppKitProvider node={THOR_URL}>
      {/* rest of the app components */}
    </DAppKitProvider>
  );
}

By wrapping with DAppKitProvider, all child components can access the connection and signer provided by DApp Kit (via React context).

The provider is configured to automatically connect to Testnet or prompt the user.

Wallet Selection UI:
The Dapp Kit UI library has ready-made components for wallet selection. Often, you’d include something like <ConnectButton /> or a <WalletSelectorModal /> to allow the user to pick VeWorld.

If you'd like to dive deeper into the DApp Kit documentation, you can find more information in the VeChain docs.

Once the user connects through VeWorld, the DAppProvider will hold the wallet’s connection and the currently selected account.

Let’s briefly explain what’s happening behind our calls:

Wallet Connection:
VeWorld provides an object in the window (window.vechain) that the DApp Kit uses.
When the user selects a wallet and connects, DApp Kit either uses the injected provider (VeWorld extension).

After connection, you have a signing authority.

Calling a Contract:
When you call buyCoffee with the DApp Kit, it constructs a Clause (VeChain’s term for an action) that encodes:

  • The function signature and parameters

  • The amount of VET to send

This clause is sent to the wallet for signing. VeWorld will show a transaction dialog with:

  • destination address = our contract

  • value = amount of VET

  • data = the function call

Once the user approves, the wallet signs the transaction and submits it to a VeChain node.

You can understand how Clauses are created and signed here.

Gas and VTHO:
The user must have VTHO to cover the execution of transactions.

Tip: make sure the user has some VTHO in their wallet.

  • The buyCoffee and sendCoffee functions are not computationally heavy, but they store data (write to an array), which costs gas — paid in VTHO.

  • The wallet uses the user’s VTHO to pay. No manual configuration is needed.

  • Since you’re on Testnet, and the Testnet faucet gave us VTHO, you’ll be fine.

Reading data:
When TransactionHistory calls getSales(), DApp Kit uses a read-only call.
This does not consume VTHO and does not require a signed transaction.
It queries a node for the contract state. The returned data is decoded via the ABI into JavaScript objects.

All of these complexities are handled by the DApp Kit and SDK, so you mostly interact with simple JavaScript functions or React hooks.

Incorrect Contract Address or ABI:
If the address or ABI is wrong, contract calls will fail silently or do nothing.
Double-check that you copied the correct address from Hardhat’s output.
The ABI must include the definitions for buyCoffee, sendCoffee, getSales, etc.

For example:
They provided the ABI JSON in a config. Use the one from your compiled artifacts to be sure it matches exactly.

Wallet not connecting:
Ensure the VeWorld extension is installed and that you refreshed the page after installing.
Also check that your app is being served over http://localhost or https:// — some wallets require a secure context.

Network mismatches:
If your contract is on Testnet but your wallet is on Mainnet, the calls won’t succeed.
Switch the wallet network, VeWorld shows the current network at the top of the extension. Choose Testnet.

Viewing on Explorer:
You can copy a transaction ID from the VeWorld prompt or console logs and find it in VeChain’s explorer to see details. Or check the contract address on the explorer to see event logs, the CoffeeSold events will appear there.