Web3.0 Development: Practical Code Examples for Blockchain Integration

·

Web3.0 is transforming how users interact with the internet by decentralizing control, empowering ownership through blockchain technology, and enabling peer-to-peer interactions without intermediaries. For developers, mastering Web3.0 means understanding how to connect frontend applications to blockchain networks using tools like web3.js, interact with wallets such as MetaMask, and execute smart contract functions securely.

This guide dives into practical code examples that form the backbone of modern Web3 development—covering everything from initializing a Web3 instance to sending transactions and querying blockchain data. Whether you're building decentralized applications (dApps), NFT marketplaces, or DeFi platforms, these patterns are essential.

Core Keywords


Initializing the Web3 Instance

The foundation of any Web3 application is establishing a connection to the Ethereum blockchain via a provider. The web3.js library allows developers to create a Web3 instance by specifying a service provider—typically an RPC endpoint.

Understanding Service Providers

A service provider acts as a bridge between your app and the Ethereum network. There are three types:

While you can manually instantiate providers:

const httpProvider = new Web3.providers.HttpProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');
const websocketProvider = new Web3.providers.WebsocketProvider('wss://mainnet.infura.io/ws');

In practice, you can directly pass the RPC URL to the Web3 constructor:

const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');

👉 Discover powerful tools to test your Web3 integrations seamlessly.

Using MetaMask as a Provider

Modern dApps primarily rely on browser wallets like MetaMask. When installed, MetaMask injects window.ethereum, which serves as a ready-to-use provider.

if (window.ethereum) {
  const web3 = new Web3(window.ethereum);
}

To ensure compatibility across environments:

const web3 = new Web3(window.ethereum || 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID');
Note: Always verify the network chain ID matches your app’s requirements.

Switching Providers Dynamically

You can change providers at runtime:

web3.setProvider(newProvider);

This flexibility allows apps to switch between testnets, mainnets, or fallback nodes seamlessly.


Connecting User Accounts via MetaMask

To enable user interaction, your app must request access to their Ethereum accounts.

Requesting Account Access

Use the eth_requestAccounts method to prompt users:

const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
console.log(accounts); // ['0x...', ...]
⚠️ Avoid deprecated methods like ethereum.enable().

Once connected, retrieve accounts via web3.js:

const accounts = await web3.eth.getAccounts();

If no accounts are connected, this returns an empty array.


Listening to Wallet Events

Reacting to user actions enhances UX. Listen for key events emitted by MetaMask:

function addEventListeners() {
  if (!window.ethereum) return;

  window.ethereum.on('accountsChanged', (accounts) => {
    console.log('Account switched:', accounts[0]);
  });

  window.ethereum.on('chainChanged', (chainId) => {
    const id = parseInt(chainId, 16);
    console.log('Network changed to:', id);
    // Optionally reload page or update context
  });

  window.ethereum.on('disconnect', (error) => {
    console.error('Disconnected:', error);
  });
}

Ensure cleanup on component unmount:

function removeEventListeners() {
  window.ethereum?.removeAllListeners();
}

Managing Network and Token Interactions

Users may be on the wrong network or lack required tokens. Help them configure their wallet correctly.

Switching Networks

Prompt users to switch chains:

try {
  await window.ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: '0x1' }], // Ethereum Mainnet
  });
} catch (error) {
  if (error.code === 4902) {
    console.log('Network not available; adding it...');
  }
}

Adding Custom Networks

If the target network isn’t preset (e.g., Goerli testnet):

await window.ethereum.request({
  method: 'wallet_addEthereumChain',
  params: [
    {
      chainId: '0x5',
      chainName: 'Goerli Testnet',
      nativeCurrency: { name: 'GoerliETH', symbol: 'ETH', decimals: 18 },
      rpcUrls: ['https://goerli.infura.io/v3/YOUR_KEY'],
      blockExplorerUrls: ['https://goerli.etherscan.io'],
    },
  ],
});

Adding Tokens (ERC-20)

Allow users to track custom tokens:

await window.ethereum.request({
  method: 'wallet_watchAsset',
  params: {
    type: 'ERC20',
    options: {
      address: '0xb60e8dd61c5d32be8058bb8eb970870f07233155',
      symbol: 'FOO',
      decimals: 18,
      image: 'https://foo.io/token.svg',
    },
  },
});

👉 Explore how leading platforms streamline blockchain connectivity.


Handling Balances and Unit Conversions

Blockchain data uses wei (1 ETH = 10¹⁸ wei). Convert values safely using libraries like decimal.js.

Utility Functions

import Decimal from 'decimal.js';

export function format2Balance(amount, decimals) {
  if (!amount || !decimals) return amount;
  const factor = Math.pow(10, decimals);
  return new Decimal(amount).div(factor).toString();
}

export function format2Amount(balance, decimals) {
  if (!balance || !decimals) return balance;
  const factor = Math.pow(10, decimals);
  return new Decimal(balance).mul(factor).toString();
}

Fetching Account Data

async function getAccountInfo(web3) {
  const accounts = await web3.eth.getAccounts();
  const account = accounts[0];

  const balanceWei = await web3.eth.getBalance(account);
  const balanceEth = format2Balance(balanceWei, 18);

  const chainId = await web3.eth.getChainId();

  return { account, balanceEth, chainId };
}

Signing Messages and Verifying Identity

Message signing proves ownership without transferring funds.

Sign with MetaMask

const message = 'Login to MyApp';
const signature = await window.ethereum.request({
  method: 'personal_sign',
  params: [message, account],
});

Recover Signed Address

const signer = await web3.eth.personal.ecRecover(message, signature);
// Compare signer === expected address

Interacting with Smart Contracts

All tokens (ERC-20) and NFTs (ERC-721) are smart contracts.

Connect to a Contract

const contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS);

Read Data (Call)

For non-state-changing calls:

const balance = await contract.methods.balanceOf(account).call();

Write Data (Send)

To transfer WETH:

const amount = format2Amount('1', 18);
const tx = contract.methods.transfer(toAddress, amount);

await tx.send({ from: account });

Alternatively, use sendTransaction:

await web3.eth.sendTransaction({
  from: account,
  to: CONTRACT_ADDRESS,
  data: tx.encodeABI(),
});

👉 See how top developers deploy secure smart contract interactions.


Sending ETH Between Accounts

To send native ETH:

const amountWei = format2Amount('0.5', 18);

await web3.eth.sendTransaction({
  from: sender,
  to: receiver,
  value: amountWei,
});

No contract interaction needed—this uses the base layer protocol.


Querying Transaction Status

After sending a transaction, monitor its status using the transaction hash:

const receipt = await web3.eth.getTransactionReceipt(hash);
if (!receipt) {
  console.log('Pending...');
} else if (receipt.status) {
  console.log('Success!');
} else {
  console.log('Failed.');
}

Implement polling every 2–5 seconds until the receipt is available.


Frequently Asked Questions

How do I check if MetaMask is installed?

Check for window.ethereum:

if (typeof window.ethereum !== 'undefined') {
  console.log('MetaMask is available');
}

Can I send transactions without MetaMask?

Yes—using private key signing on backend services:

const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
await web3.eth.sendSignedTransaction(signedTx.rawTransaction);

What's the difference between Chain ID and Network ID?

Chain ID prevents replay attacks across forks (introduced in EIP-155). Network ID is legacy and used for P2P networking.

Why use format2Balance instead of built-in methods?

Built-in methods may lose precision. Using decimal.js avoids floating-point errors when handling large numbers.

How do I handle user disconnection from my dApp?

Listen to the disconnect event and reset UI state accordingly:

window.ethereum.on('disconnect', () => {
  alert('Wallet disconnected');
});

Is it safe to expose my Infura key?

Infura keys aren’t secret—they’re rate-limited but can’t be used to steal funds. Still, avoid hardcoding in public repos.


With these foundational code patterns, you’re equipped to build robust, interactive dApps that communicate securely with Ethereum and user wallets. Always prioritize security, validate inputs, and test across networks before deployment.