Skip to main content

dApp Integration Guide

Learn how to integrate TeQoin L2 into your web application and enable users to interact with your smart contracts.
What You’ll Learn:
  • Connect wallets (MetaMask, WalletConnect)
  • Interact with smart contracts
  • Handle transactions
  • Listen to events
  • Best practices for production dApps

🎯 Integration Stack

Ethers.js v6

RecommendedModern, lightweight library

Web3.js

ClassicOriginal Ethereum library

Wagmi + Viem

React HooksModern React integration

🚀 Quick Start Template

A minimal dApp to get you started quickly.

Complete Working Example

<!DOCTYPE html>
<html>
<head>
    <title>TeQoin dApp</title>
    <script src="https://cdn.ethers.io/lib/ethers-5.7.umd.min.js"></script>
</head>
<body>
    <h1>TeQoin dApp Example</h1>
    
    <!-- Connect Wallet -->
    <button id="connectBtn">Connect Wallet</button>
    <p>Connected: <span id="account">Not connected</span></p>
    <p>Network: <span id="network">Unknown</span></p>
    
    <!-- Contract Interaction -->
    <h2>Contract Interaction</h2>
    <input id="addressInput" placeholder="Contract Address" />
    <button id="getBalanceBtn">Get Balance</button>
    <p>Balance: <span id="balance">-</span></p>
    
    <script src="app.js"></script>
</body>
</html>

Modern, lightweight library for Ethereum interaction.

Installation

# Install ethers.js v6
npm install ethers

# Or use CDN
<script src="https://cdn.ethers.io/lib/ethers-5.7.umd.min.js"></script>

Connect to TeQoin

import { ethers } from 'ethers';

// Connect to TeQoin L2
const provider = new ethers.JsonRpcProvider('https://rpc.teqoin.io');

// Check connection
const network = await provider.getNetwork();
console.log('Connected to chain ID:', network.chainId); // 420377n

// Get latest block
const blockNumber = await provider.getBlockNumber();
console.log('Latest block:', blockNumber);

Interact with Smart Contracts

import { ethers } from 'ethers';

// Contract ABI (only the functions you need)
const abi = [
    "function totalSupply() view returns (uint256)",
    "function balanceOf(address) view returns (uint256)",
    "function name() view returns (string)",
    "function symbol() view returns (string)"
];

// Connect to contract
const provider = new ethers.JsonRpcProvider('https://rpc.teqoin.io');
const contract = new ethers.Contract(
    '0x5E3A9432a2D6eb0c5D362A0A2F58Bc02Db45850D', // Contract address
    abi,
    provider
);

// Call view functions (no gas cost)
const totalSupply = await contract.totalSupply();
const balance = await contract.balanceOf('0x...');
const name = await contract.name();

console.log('Total Supply:', ethers.formatUnits(totalSupply, 18));
console.log('Balance:', ethers.formatUnits(balance, 18));
console.log('Name:', name);

🔷 Web3.js Integration

Classic Ethereum library, still widely used.

Installation

npm install web3

Basic Usage

const Web3 = require('web3');

// Connect to TeQoin L2
const web3 = new Web3('https://rpc.teqoin.io');

// Check connection
const chainId = await web3.eth.getChainId();
console.log('Chain ID:', chainId); // 420377

// Get latest block
const blockNumber = await web3.eth.getBlockNumber();
console.log('Latest block:', blockNumber);

⚛️ Wagmi + Viem Integration (React)

Modern React hooks for Ethereum.

Installation

npm install wagmi viem @tanstack/react-query

Setup

import { http, createConfig } from 'wagmi';
import { teqoin } from './chains';

export const config = createConfig({
  chains: [teqoin],
  transports: {
    [teqoin.id]: http('https://rpc.teqoin.io'),
  },
});

React Components

import { useAccount, useConnect, useDisconnect } from 'wagmi';
import { injected } from 'wagmi/connectors';

export function ConnectButton() {
  const { address, isConnected } = useAccount();
  const { connect } = useConnect();
  const { disconnect } = useDisconnect();

  if (isConnected) {
    return (
      <div>
        <p>Connected: {address}</p>
        <button onClick={() => disconnect()}>Disconnect</button>
      </div>
    );
  }

  return (
    <button onClick={() => connect({ connector: injected() })}>
      Connect Wallet
    </button>
  );
}

🎨 Complete React dApp Example

A production-ready React + Wagmi dApp template:
import { useState } from 'react';
import { useAccount, useConnect, useDisconnect, useReadContract, useWriteContract } from 'wagmi';
import { injected } from 'wagmi/connectors';
import { parseEther, formatEther } from 'viem';

const CONTRACT_ADDRESS = '0x5E3A9432a2D6eb0c5D362A0A2F58Bc02Db45850D';
const CONTRACT_ABI = [
  {
    name: 'balanceOf',
    type: 'function',
    stateMutability: 'view',
    inputs: [{ name: 'account', type: 'address' }],
    outputs: [{ type: 'uint256' }],
  },
  {
    name: 'transfer',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'to', type: 'address' },
      { name: 'amount', type: 'uint256' },
    ],
    outputs: [{ type: 'bool' }],
  },
];

function App() {
  const { address, isConnected } = useAccount();
  const { connect } = useConnect();
  const { disconnect } = useDisconnect();
  const [recipient, setRecipient] = useState('');
  const [amount, setAmount] = useState('');

  // Read balance
  const { data: balance } = useReadContract({
    address: CONTRACT_ADDRESS,
    abi: CONTRACT_ABI,
    functionName: 'balanceOf',
    args: address ? [address] : undefined,
  });

  // Write transaction
  const { writeContract, isPending } = useWriteContract();

  const handleTransfer = () => {
    if (!recipient || !amount) return;
    
    writeContract({
      address: CONTRACT_ADDRESS,
      abi: CONTRACT_ABI,
      functionName: 'transfer',
      args: [recipient, parseEther(amount)],
    });
  };

  return (
    <div style={{ padding: '20px' }}>
      <h1>TeQoin dApp</h1>
      
      {/* Connect Wallet */}
      {!isConnected ? (
        <button onClick={() => connect({ connector: injected() })}>
          Connect Wallet
        </button>
      ) : (
        <div>
          <p>Connected: {address}</p>
          <p>Balance: {balance ? formatEther(balance) : '0'} MTK</p>
          <button onClick={() => disconnect()}>Disconnect</button>
          
          {/* Transfer Form */}
          <div style={{ marginTop: '20px' }}>
            <h2>Transfer Tokens</h2>
            <input
              placeholder="Recipient Address"
              value={recipient}
              onChange={(e) => setRecipient(e.target.value)}
              style={{ width: '100%', marginBottom: '10px' }}
            />
            <input
              placeholder="Amount"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
              style={{ width: '100%', marginBottom: '10px' }}
            />
            <button onClick={handleTransfer} disabled={isPending}>
              {isPending ? 'Sending...' : 'Transfer'}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

export default App;

🔐 Best Practices

Security

    // ❌ BAD: No validation
    const tx = await contract.transfer(userInput, amount);
    
    // ✅ GOOD: Validate addresses
    import { ethers } from 'ethers';
    
    if (!ethers.isAddress(userInput)) {
      throw new Error('Invalid address');
    }
    
    const tx = await contract.transfer(userInput, amount);
    try {
      const tx = await contract.transfer(to, amount);
      await tx.wait();
      alert('Transfer successful!');
    } catch (error) {
      if (error.code === 'ACTION_REJECTED') {
        alert('Transaction cancelled');
      } else if (error.code === 'INSUFFICIENT_FUNDS') {
        alert('Insufficient balance');
      } else {
        alert('Transaction failed: ' + error.message);
      }
    }
    const provider = new ethers.BrowserProvider(window.ethereum);
    const network = await provider.getNetwork();
    
    if (network.chainId !== 420377n) {
      alert('Please switch to TeQoin L2');
      await switchToTeQoin();
    }

Performance

Use Read-Only Provider for View Functions
// ❌ BAD: Using wallet provider for reads (slower)
const provider = new ethers.BrowserProvider(window.ethereum);

// ✅ GOOD: Use direct RPC for reads (faster)
const readProvider = new ethers.JsonRpcProvider('https://rpc.teqoin.io');
const contract = new ethers.Contract(address, abi, readProvider);
Cache Contract Instances
// ❌ BAD: Creating new instance every time
function getBalance() {
  const contract = new ethers.Contract(...);
  return contract.balanceOf(address);
}

// ✅ GOOD: Reuse contract instance
const contract = new ethers.Contract(...);
function getBalance() {
  return contract.balanceOf(address);
}

📱 Mobile Wallet Integration

WalletConnect Support

npm install @walletconnect/web3-provider
import WalletConnectProvider from '@walletconnect/web3-provider';
import { ethers } from 'ethers';

const walletConnectProvider = new WalletConnectProvider({
  rpc: {
    420377: 'https://rpc.teqoin.io',
  },
  chainId: 420377,
});

// Enable session
await walletConnectProvider.enable();

// Create ethers provider
const provider = new ethers.providers.Web3Provider(walletConnectProvider);
const signer = provider.getSigner();

🎯 Testing Your dApp

Local Testing

# Use Hardhat local node
npx hardhat node --fork https://rpc.teqoin.io

# Your dApp can connect to:
# http://localhost:8545

Testnet Testing

// Configure for testnet
const provider = new ethers.JsonRpcProvider('https://rpc-testnet.teqoin.io');

📚 Additional Resources

Ethers.js Docs

Official Ethers.js documentation

Wagmi Docs

React hooks for Ethereum

Web3.js Docs

Web3.js documentation

Network Info

TeQoin network details

🎯 Next Steps

Deploy Your dApp

Host on Vercel, Netlify, or IPFS

Add Analytics

Track user interactions

Build Backend

Add off-chain components

Get Users

Market your dApp

🎉 Developer Documentation Complete!

You’ve completed all developer guides:
  • ✅ Network Information
  • ✅ Smart Contracts
  • ✅ Deploy Contract
  • ✅ Verify Contract
  • ✅ Integration Guide
Ready to build amazing dApps on TeQoin L2! 🚀