Build
Build a dApp
Connect browser wallets with EIP-6963, switch them to Lib Testnet, read balances and send transactions with viem or ethers, or drop in Reown AppKit.
A LibChain dApp is an Ethereum dApp pointed at chain 54210. This page covers the pieces you'll write: finding wallets, connecting, switching network, reading and writing.
#1. Find the user's wallets
Use EIP-6963 discovery rather than window.ethereum: several wallets can be installed at once, and each announces itself with a name and icon. Lib Wallet announces itself this way.
type Announced = { info: { uuid: string; name: string; icon: string; rdns: string }; provider: any }
const wallets = new Map<string, Announced>()
window.addEventListener('eip6963:announceProvider', (e: any) => {
wallets.set(e.detail.info.uuid, e.detail)
})
window.dispatchEvent(new Event('eip6963:requestProvider'))#2. Connect and switch to Lib Testnet
const LIB = {
chainId: '0xd3c2',
chainName: 'Lib Testnet',
nativeCurrency: { name: 'Lib Test Coin', symbol: 'tLIB', decimals: 18 },
rpcUrls: ['https://rpc-testnet.libchain.tech'],
blockExplorerUrls: ['https://testnet.libchain.tech'],
}
async function connect(provider: any) {
const [account] = await provider.request({ method: 'eth_requestAccounts' })
try {
await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: LIB.chainId }] })
} catch (e: any) {
if (e.code !== 4902) throw e // 4902: the wallet doesn't know the chain yet
await provider.request({ method: 'wallet_addEthereumChain', params: [LIB] })
}
return account as string
}Listen for accountsChanged and chainChanged on the provider and update your UI when they fire.
#3. Read and write
import { createPublicClient, createWalletClient, custom, http, parseEther, formatEther } from 'viem'
import { libTestnet } from './chains' // see Network details
const client = createPublicClient({ chain: libTestnet, transport: http() })
const wallet = createWalletClient({ chain: libTestnet, transport: custom(provider) })
const balance = await client.getBalance({ address: account })
console.log(formatEther(balance), 'tLIB')
const hash = await wallet.sendTransaction({ account, to: '0xRecipient', value: parseEther('1') })
const receipt = await client.waitForTransactionReceipt({ hash }) // final in its blockimport { BrowserProvider, JsonRpcProvider, parseEther, formatEther } from 'ethers'
const reader = new JsonRpcProvider('https://rpc-testnet.libchain.tech', 54210, { staticNetwork: true })
const signer = await new BrowserProvider(provider).getSigner()
console.log(formatEther(await reader.getBalance(await signer.getAddress())), 'tLIB')
const tx = await signer.sendTransaction({ to: '0xRecipient', value: parseEther('1') })
const receipt = await tx.wait() // one confirmation is finalRead through the public RPC (http() or JsonRpcProvider) and only use the wallet's provider to sign. That keeps reads fast and keeps working when the wallet is locked.
#4. Call a contract
import { parseAbi } from 'viem'
const abi = parseAbi([
'function balanceOf(address) view returns (uint256)',
'function deposit() payable',
])
const wrapped = await client.readContract({ address: '0x87052f1f17b2b4054b014e93e53d6ce6dc912bda', abi, functionName: 'balanceOf', args: [account] })
await wallet.writeContract({ account, address: '0x87052f1f17b2b4054b014e93e53d6ce6dc912bda', abi, functionName: 'deposit', value: parseEther('0.5') })#Using wagmi
import { createConfig, http } from 'wagmi'
import { injected } from 'wagmi/connectors'
import { libTestnet } from './chains'
export const config = createConfig({
chains: [libTestnet],
connectors: [injected()],
transports: { [libTestnet.id]: http() },
})#A ready-made connect modal
Reown AppKit gives you a connect modal with browser wallets and WalletConnect for phones. It's what Lib Explorer and LibChain Hub use. Pass the Lib Testnet chain from viem's defineChain (or AppKit's own defineChain) and your own Reown project ID, and add your domain to the project's allowlist in the Reown dashboard.
#UX that fits LibChain
- Show lib1, accept both. Display addresses in lib1 form and accept lib1 or 0x in inputs. See lib1 in your app.
- Mark success at the receipt. There's nothing to wait for after it. See Blocks and finality.
- Say it's testnet. Label balances as test coins with no value.
- Link to the explorer.
https://testnet.libchain.tech/tx/<hash>andhttps://testnet.libchain.tech/address/<address>.