Skip to content

Web3 Integration Guide

Learn how to integrate Web3 functionality into your Civra applications.

Wallet Connection

Basic Setup

Civra provides built-in wallet connection components:

typescript
import { WalletButton } from '@civra/web3'

export function Header() {
  return (
    <nav>
      <WalletButton />
    </nav>
  )
}

Supported Wallets

  • MetaMask
  • WalletConnect
  • Coinbase Wallet
  • Rainbow Wallet
  • Trust Wallet

Custom Wallet Integration

typescript
import { useWallet } from '@civra/web3'

export function CustomConnect() {
  const { connect, disconnect, address, isConnected } = useWallet()

  return (
    <div>
      {isConnected ? (
        <div>
          <span>{address}</span>
          <button onClick={disconnect}>Disconnect</button>
        </div>
      ) : (
        <button onClick={() => connect('metamask')}>
          Connect MetaMask
        </button>
      )}
    </div>
  )
}

Smart Contract Interaction

Reading Contract Data

typescript
import { useContract } from '@civra/web3'

const CONTRACT_ADDRESS = '0x...'
const ABI = [...]

export function TokenBalance() {
  const contract = useContract(CONTRACT_ADDRESS, ABI)
  const { data: balance } = contract.read.balanceOf(address)

  return <div>Balance: {balance}</div>
}

Writing to Contracts

typescript
export function MintButton() {
  const contract = useContract(CONTRACT_ADDRESS, ABI)

  const handleMint = async () => {
    try {
      const tx = await contract.write.mint({
        value: parseEther('0.1')
      })
      await tx.wait()
      console.log('Minted successfully!')
    } catch (error) {
      console.error('Mint failed:', error)
    }
  }

  return <button onClick={handleMint}>Mint NFT</button>
}

Network Management

Detecting Network

typescript
import { useNetwork } from '@civra/web3'

export function NetworkIndicator() {
  const { chain } = useNetwork()

  return (
    <div>
      Connected to: {chain?.name}
    </div>
  )
}

Switching Networks

typescript
import { useSwitchNetwork } from '@civra/web3'

export function NetworkSwitcher() {
  const { switchNetwork } = useSwitchNetwork()

  return (
    <div>
      <button onClick={() => switchNetwork(1)}>
        Switch to Ethereum
      </button>
      <button onClick={() => switchNetwork(137)}>
        Switch to Polygon
      </button>
    </div>
  )
}

Transaction Handling

Monitoring Transactions

typescript
import { useWaitForTransaction } from '@civra/web3'

export function TransactionStatus({ hash }) {
  const { data, isLoading, isSuccess } = useWaitForTransaction({
    hash
  })

  if (isLoading) return <div>Transaction pending...</div>
  if (isSuccess) return <div>Transaction confirmed!</div>

  return null
}

Transaction Receipts

typescript
const { data: receipt } = useWaitForTransaction({ hash })

console.log('Gas used:', receipt.gasUsed)
console.log('Block number:', receipt.blockNumber)

Token Operations

ERC-20 Tokens

typescript
// Check balance
const { data: balance } = useTokenBalance({
  token: '0x...',
  address: userAddress
})

// Approve spending
const { write: approve } = useTokenApprove({
  token: '0x...',
  spender: '0x...',
  amount: parseEther('100')
})

// Transfer tokens
const { write: transfer } = useTokenTransfer({
  token: '0x...',
  to: '0x...',
  amount: parseEther('10')
})

NFTs (ERC-721)

typescript
// Get NFT metadata
const { data: nft } = useNFT({
  contract: '0x...',
  tokenId: '1'
})

// Transfer NFT
const { write: transfer } = useNFTTransfer({
  contract: '0x...',
  from: address,
  to: '0x...',
  tokenId: '1'
})

Gas Optimization

Estimating Gas

typescript
const gasEstimate = await contract.estimateGas.mint()
console.log('Estimated gas:', gasEstimate)

Setting Gas Price

typescript
const tx = await contract.write.mint({
  gasLimit: 100000,
  maxFeePerGas: parseGwei('50'),
  maxPriorityFeePerGas: parseGwei('2')
})

Events and Logs

Listening to Events

typescript
import { useContractEvent } from '@civra/web3'

useContractEvent({
  address: CONTRACT_ADDRESS,
  abi: ABI,
  eventName: 'Transfer',
  listener: (from, to, amount) => {
    console.log(`Transfer: ${from} → ${to}: ${amount}`)
  }
})

Querying Past Events

typescript
const { data: events } = useContractRead({
  address: CONTRACT_ADDRESS,
  abi: ABI,
  functionName: 'getPastEvents',
  args: ['Transfer', { fromBlock: 0 }]
})

IPFS Integration

Uploading to IPFS

typescript
import { uploadToIPFS } from '@civra/ipfs'

const file = await fetch(imageUrl).then(r => r.blob())
const cid = await uploadToIPFS(file)
console.log('IPFS CID:', cid)

Fetching from IPFS

typescript
import { getFromIPFS } from '@civra/ipfs'

const data = await getFromIPFS(cid)
const metadata = JSON.parse(data)

Security Best Practices

  1. Never expose private keys - Always use wallet connections
  2. Validate user input - Sanitize addresses and amounts
  3. Handle errors gracefully - Show user-friendly error messages
  4. Use proper types - TypeScript helps prevent errors
  5. Test on testnets - Always test before mainnet deployment
  6. Audit contracts - Get professional audits for financial apps
  7. Implement access controls - Use proper permission systems
  8. Monitor transactions - Show clear transaction status

Common Patterns

Loading States

typescript
const { data, isLoading, error } = useContractRead(...)

if (isLoading) return <Spinner />
if (error) return <Error message={error.message} />
return <Data value={data} />

Error Handling

typescript
try {
  await contract.write.mint()
} catch (error) {
  if (error.code === 4001) {
    // User rejected
  } else if (error.code === -32603) {
    // Execution reverted
  }
}

Examples

Check out our template library for complete Web3 application examples.

Next Steps

Built with Civra - Web3 Development Platform