npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@visualizevalue/vveb-layer-evm

v1.0.10

Published

A comprehensive Nuxt layer for Ethereum/EVM integration, providing wallet connection, account management, and guided transaction flows using modern wagmi and viem libraries.

Readme

@visualizevalue/vveb-layer-evm

A comprehensive Nuxt layer for Ethereum/EVM integration, providing wallet connection, account management, and guided transaction flows using modern wagmi and viem libraries.

Features

  • Multi-Wallet Support: MetaMask, Coinbase Wallet, WalletConnect, and injected wallets
  • Modern Web3 Stack: Built with viem 2.38+ and @wagmi/vue with Nuxt module
  • Transaction Flow Component: Guided multi-step transaction execution with automatic chain validation
  • ENS Integration: Automatic ENS name resolution for addresses
  • Multi-Chain Support: Mainnet, Sepolia, Holesky, and localhost
  • Resilient RPC: Automatic fallback between multiple RPC endpoints
  • SSR Compatible: Cookie-based storage for server-side rendering
  • Batch Multicall: Optimized contract calls with automatic batching

Installation

pnpm add @visualizevalue/vveb-layer-evm viem @wagmi/vue @tanstack/vue-query

Add to your Nuxt config:

export default defineNuxtConfig({
  extends: ['@visualizevalue/vveb-layer-evm'],
})

Configuration

Environment Variables

# Required
NUXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="your-walletconnect-project-id"

# Optional (with defaults)
NUXT_PUBLIC_TITLE="My App"
NUXT_PUBLIC_CHAIN_ID=1
NUXT_PUBLIC_BLOCK_EXPLORER="https://etherscan.io"

# RPC endpoints (fallback chain)
NUXT_PUBLIC_RPC1="https://eth.llamarpc.com"
NUXT_PUBLIC_RPC2="https://ethereum-rpc.publicnode.com"
NUXT_PUBLIC_RPC3="https://eth.drpc.org"

Runtime Config

You can also configure via nuxt.config.ts:

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      title: 'My Web3 App',
      chainId: 1, // or 11155111 for Sepolia
      blockExplorer: 'https://etherscan.io',
      walletConnectProjectId: 'your-project-id',
    },
  },
})

Components

<Connect>

Wallet connection button with modal selector for choosing between wallets.

<template>
  <Connect>
    <!-- Default slot: shown when disconnected -->
    <template #default>
      Connect Wallet
    </template>

    <!-- Connected slot: shown when wallet is connected -->
    <template #connected="{ address, ensName }">
      <Account :address="address" />
    </template>
  </Connect>
</template>

Props:

  • None (uses slots for customization)

Slots:

  • default: Content shown when disconnected
  • connected({ address, ensName }): Content shown when connected

<Account>

Display Ethereum address with automatic ENS name resolution and copy-to-clipboard.

<template>
  <Account :address="userAddress" />
</template>

<script setup>
const { address: userAddress } = useAccount()
</script>

Props:

  • address (string, required): Ethereum address to display

Features:

  • Automatically resolves ENS names
  • Shows shortened address as fallback
  • Click to copy address
  • Displays ENS avatar if available

<TransactionFlow>

Guided transaction execution with automatic chain checking, user confirmation, and status tracking.

<template>
  <TransactionFlow
    :request="mintNFT"
    :text="{
      title: {
        confirm: 'Confirm Mint',
        requesting: 'Awaiting Signature',
        waiting: 'Minting...',
        complete: 'Minted!'
      },
      lead: {
        confirm: 'This will mint 1 NFT for 0.1 ETH.',
        complete: 'Your NFT has been minted successfully.'
      },
      action: {
        confirm: 'Mint NFT',
        complete: 'View on OpenSea'
      },
    }"
    @complete="handleComplete"
    @error="handleError"
  >
    <!-- Trigger button -->
    <template #start="{ start }">
      <Button @click="start">Mint NFT</Button>
    </template>

    <!-- Optional: customize confirmation step -->
    <template #confirm="{ data, next, cancel }">
      <div>
        <p>Minting {{ data.amount }} NFT(s)</p>
        <p>Cost: {{ data.cost }} ETH</p>
        <Button @click="next">Confirm</Button>
        <Button @click="cancel">Cancel</Button>
      </div>
    </template>

    <!-- Optional: customize complete step -->
    <template #complete="{ receipt, close }">
      <div>
        <p>Transaction: {{ receipt.transactionHash }}</p>
        <Button @click="close">Done</Button>
      </div>
    </template>
  </TransactionFlow>
</template>

<script setup>
import { writeContract } from '@wagmi/core'

const mintNFT = async () => {
  const hash = await writeContract({
    address: '0x1234...',
    abi: [...],
    functionName: 'mint',
    args: [1],
    value: parseEther('0.1'),
  })
  return hash
}

const handleComplete = (receipt) => {
  console.log('Mint successful!', receipt)
}

const handleError = (error) => {
  console.error('Mint failed:', error)
}
</script>

Props:

  • request (function, required): Async function that executes the transaction and returns a transaction hash
  • text (object, optional): Customize text for each step
    • title: Step titles (confirm, chain, requesting, waiting, complete, error)
    • lead: Step descriptions
    • action: Button text
  • requireChainId (number, optional): Specific chain ID required (defaults to main chain)

Events:

  • @complete(receipt): Fired when transaction is confirmed
  • @error(error): Fired when an error occurs
  • @cancel(): Fired when user cancels

Slots:

  • start({ start }): Trigger button/element
  • confirm({ data, next, cancel }): Custom confirmation UI
  • chain({ switchChain }): Custom chain switching UI
  • requesting(): Custom waiting for signature UI
  • waiting({ hash }): Custom waiting for confirmation UI
  • complete({ receipt, close }): Custom completion UI
  • error({ error, retry, cancel }): Custom error UI

Flow States:

  1. start: Initial state, waiting for user to trigger
  2. confirm: Show transaction details, user can review
  3. chain: Check/prompt chain switching if needed
  4. requesting: Waiting for wallet signature
  5. waiting: Transaction submitted, waiting for confirmation
  6. complete: Transaction confirmed successfully
  7. error: An error occurred

Composables & Helpers

useMainChainId()

Returns the configured main chain ID from runtime config.

const chainId = useMainChainId()
console.log(chainId) // 1 (mainnet) or configured value

useEnsureChainIdCheck()

Returns a function that checks if the user is on the correct chain and prompts to switch if needed.

const ensureChain = useEnsureChainIdCheck()

// Check and switch to main chain if needed
const isCorrectChain = await ensureChain()
// Returns true if on correct chain, false if user cancelled switch

Returns: Async function that returns a Promise. Automatically uses the configured main chain ID.

delay(ms)

Promise-based delay helper for async operations.

import { delay } from '#imports'

await delay(1000) // Wait 1 second

Wagmi Composables (Auto-imported)

All standard wagmi/vue composables are available:

import {
  useAccount,
  useConnect,
  useDisconnect,
  useBalance,
  useReadContract,
  useWriteContract,
  useWaitForTransactionReceipt,
  useSwitchChain,
} from '@wagmi/vue'

const { address, isConnected } = useAccount()
const { connect } = useConnect()
const { disconnect } = useDisconnect()

Utilities

shortAddress(address, length?)

Shorten Ethereum addresses for display.

import { shortAddress } from '#imports'

shortAddress('0x1234567890abcdef1234567890abcdef12345678')
// Returns: "0x1234...678"

shortAddress('0x1234567890abcdef1234567890abcdef12345678', 6)
// Returns: "0x12345678...345678"

Parameters:

  • address (Address): Ethereum address
  • length (number, optional): Characters to show on each side (default: 3)

Viem Functions

Common viem functions can be imported:

import {
  parseEther,
  parseUnits,
  formatEther,
  formatUnits,
  isAddress,
  getAddress,
  encodeFunctionData,
  decodeFunctionResult,
} from 'viem'

Wagmi Actions

Wagmi actions can be imported from @wagmi/core:

import {
  readContract,
  writeContract,
  getBalance,
  getEnsName,
  getEnsAvatar,
  waitForTransactionReceipt,
  switchChain,
} from '@wagmi/core'

Advanced Usage

Custom Transaction with Data

<script setup>
import { writeContract, parseEther } from '#imports'

const mintWithData = async () => {
  const hash = await writeContract({
    address: '0x...',
    abi: myContractABI,
    functionName: 'mintWithData',
    args: [
      '0x...', // recipient
      tokenId,
      metadata,
    ],
    value: parseEther('0.1'),
  })
  return hash
}
</script>

Reading Contract Data

const { data: totalSupply } = useReadContract({
  address: '0x...',
  abi: myContractABI,
  functionName: 'totalSupply',
})

// Or using actions
const supply = await readContract({
  address: '0x...',
  abi: myContractABI,
  functionName: 'totalSupply',
})

Multi-Step Transactions

<template>
  <TransactionFlow
    :request="approveAndMint"
    :text="{ title: { confirm: 'Approve & Mint' } }"
  >
    <template #start="{ start }">
      <Button @click="start">Approve & Mint</Button>
    </template>
  </TransactionFlow>
</template>

<script setup>
const approveAndMint = async () => {
  // First approve
  const approveHash = await writeContract({
    address: tokenAddress,
    abi: erc20ABI,
    functionName: 'approve',
    args: [nftContract, parseEther('0.1')],
  })

  // Wait for approval
  await waitForTransactionReceipt({ hash: approveHash })

  // Then mint
  const mintHash = await writeContract({
    address: nftContract,
    abi: nftABI,
    functionName: 'mint',
    args: [1],
  })

  return mintHash // Return final hash
}
</script>

Supported Chains

  • Mainnet (chainId: 1)
  • Sepolia (chainId: 11155111)
  • Holesky (chainId: 17000)
  • Localhost (chainId: 31337)

Development

# Install dependencies
pnpm install

# Run playground
cd evm && pnpm dev

# Type check
cd evm && pnpm typecheck

# Build playground
cd evm && pnpm build

Stack

  • viem: 2.38.4 (Ethereum library)
  • @wagmi/vue: 0.2.14 (Vue composables for Ethereum)
  • @tanstack/vue-query: 5.62.3 (Async state management)
  • qrcode: 1.5.4 (QR code generation for WalletConnect)
  • Nuxt: 4.2.0

WalletConnect Setup

  1. Get a project ID from WalletConnect Cloud
  2. Set NUXT_PUBLIC_WALLET_CONNECT_PROJECT_ID in your .env
  3. Configure your app metadata in the wagmi plugin if needed

TypeScript

The layer includes full TypeScript support with auto-generated types from wagmi and viem.

import type { Address, Hash, TransactionReceipt } from 'viem'
import type { Config } from '@wagmi/vue'

const address: Address = '0x...'
const hash: Hash = '0x...'

License

MIT