Skip to content

Repository files navigation

Answallet Button

A reusable, modular wallet connect button for Apertum (EVM, chain 2786) apps. Originally extracted from the OpenPlaza NFT Marketplace UI and packaged so any platform on Apertum can drop it in and pick only the features it wants.

What's included

The full set of features OpenPlaza ships in its navbar button, exposed as independently togglable props or contracts:

Feature Prop / Config Description
EIP-6963 + WalletConnect connect always on Discovers injected wallets (MetaMask, Rabby, Coinbase, Trust, Xova, …) and falls back to WalletConnect.
Wallet selection modal always on One modal instance shared across multiple button instances on a page.
ANS domain display showSections.domain, contracts.ansRegistry Shows the user's .aptm domain in place of the raw 0x… address.
ANS-themed inline styles contracts.ansRegistry If the domain has theme colors, the button uses inline gradient + accent color.
APTM balance showSections.balance Auto-refreshes every 15s (configurable).
APTM send modal enableSend Send to a 0x… address or to an *.aptm ANS name.
Music library + mini player contracts.audioNft, <AudioPlayerProvider> Lazy-loads owned audio NFTs + artist albums; "Shuffle My Music" plays them in the shared AudioPlayerContext.
Pending offers badge / dropdown contracts.marketplace Polls your marketplace listings every 60s, shows a red badge on the button + a dropdown list of active offers, and auto-opens a modal on connect.
Privacy toggle (hide balance/address) always on Eye / EyeOff icon in the dropdown header.
Custom actions customActions Inject any extra label + icon + onClick(address) into the dropdown.

Installation

npm install ethers@5.7.2 @walletconnect/ethereum-provider react-hot-toast lucide-react react-router-dom

(Those are peer dependencies — they're what OpenPlaza already used.)

Minimal drop-in

import { BrowserRouter } from 'react-router-dom';
import { Toaster } from 'react-hot-toast';
import {
  ANSWalletButton,
  ANSWalletProvider,
  AudioPlayerProvider,
  WalletSelectionModal,
} from 'answallet-button'; // (or relative import while running locally)

export function AppShell() {
  return (
    <BrowserRouter>
      <ANSWalletProvider>
        <AudioPlayerProvider>
          <YourApp />
          <WalletSelectionModal />
          <Toaster position="top-center" />

          <ANSWalletButton
            contracts={{
              ansRegistry: '0xEE041dF9A7CF6435c049F80F6D7c052dC4580475',
              publicResolver: '0xd98F3e67960a9671FF69baf265CbCC26c6E88263',
              reverseRegistrar: '0x7b1dB4AAfd7531e267c0f4b68C69c97BF7d1D36f',
              rpcUrl: 'https://rpc.apertum.io/ext/bc/YDJ1r9RMkewATmA7B35q1bdV18aywzmdiXwd9zGBq3uQjsCnn/rpc',
              chainId: 2786,
              chainName: 'Apertum',
              // optional, only needed if you want offers / music:
              marketplace: '0x9D6818758Bf0419C4C3f8500959569781aDD303c',
              audioNft: '0x0000000000000000000000000000000000000000',
            }}
            enableSend
            showBalanceInButton
            onConnect={(address) => console.log('connected', address)}
            onDisconnect={() => console.log('disconnected')}
          />
        </AudioPlayerProvider>
      </ANSWalletProvider>
    </BrowserRouter>
  );
}

Props

interface WalletButtonConfig {
  contracts: {
    ansRegistry: string;       // required for ANS domain lookups
    publicResolver: string;
    reverseRegistrar: string;
    rpcUrl: string;            // public RPC for ANS reads
    chainId: number;
    chainName?: string;
    marketplace?: string;      // optional: enables pending offers
    audioNft?: string;         // optional: enables music library
  };

  showSections?: {
    balance?: boolean;         // default true
    domain?: boolean;          // default true
    address?: boolean;         // default true
    textRecords?: boolean;     // default false
    network?: boolean;         // default true
  };

  customActions?: Array<{     // appended to the dropdown
    label: string;
    icon?: React.ReactNode;
    onClick: (walletAddress: string) => void;
    className?: string;
  }>;

  theme?: {                   // override defaults
    primaryColor?: string;
    backgroundColor?: string;
    textColor?: string;
    borderRadius?: string;
    buttonHoverColor?: string;
  };

  onConnect?: (address: string) => void;
  onDisconnect?: () => void;
  showBalanceInButton?: boolean;       // default true
  themeUpdateInterval?: number;        // default 30000ms
  enableSend?: boolean;                // default false
  balanceRefreshInterval?: number;     // default 15000ms
  refreshBalanceOnDropdownOpen?: boolean; // default true
}

Custom actions (add your own button item)

<ANSWalletButton
  contracts={contracts}
  customActions={[
    {
      label: 'My NFTs',
      icon: <Gem size={14} />,
      onClick: (addr) => navigate(`/profile/${addr}`),
    },
    {
      label: 'View on Explorer',
      icon: <ExternalLink size={14} />,
      onClick: (addr) =>
        window.open(`https://explorer.apertum.io/address/${addr}`, '_blank'),
    },
  ]}
/>

The button automatically prepends the built-in items (balance, address, copy, disconnect, send, shuffle, offers) so your custom items appear at the bottom of the dropdown.

Adding a brand-new feature to the button

The button is intentionally one file (src/components/wallet/ANSWalletButton.tsx). The most common pattern to add a new section:

  1. Add a new optional field to WalletButtonConfig (e.g. myFeature?: boolean).
  2. In the dropdown JSX, conditionally render a new section that calls a feature hook you bring in.
  3. If the feature needs a contract, add it to contracts.* and thread it through.
  4. If the feature needs shared state across the app, wrap it in a new context (see AudioPlayerContext.tsx for the pattern) and add it to the required providers in the README example.

That's it. No plugin loader, no overengineered API — the file is small enough that forking and adding a section is the supported path.

Customizing the theme

Two layers:

  • Per-instance theme via the theme prop (overrides the defaults for this one button render).
  • Domain theme: if the connected wallet has an ANS domain with theme colors, the button uses those colors via inline styles. To opt out, pass a theme prop and the component will prefer it.

Default theme is gold-on-dark to match OpenPlaza. Override in one prop to match your brand.

Configuration files

File What it does
src/config/walletConfig.ts Chain definition (RPC, chainId, explorer), WalletConnect projectId, known-wallet RDNS map.
src/config/ansConfig.ts ANS contract addresses + display defaults.
src/config/audioContracts.ts Audio NFT contract addresses, IPFS gateway list.
src/lib/themes.ts Built-in ColorTheme enum (for ANS domain themes).

Standalone pieces

The repo also exports smaller, drop-in pieces you can use outside the main button:

  • <ANSDomainCard /> — a Pokemon-style card for displaying a single ANS domain. Great for "browse my domains" pages.
  • <WalletSelectionModal /> — the wallet picker. Renders once for the whole app; the button uses a hook to claim it.
  • useUnifiedWallet(), useWalletDiscovery(), useWalletModal() — the underlying hooks. Use them if you want to build your own custom button.
  • usePendingOffers(address) — gives you the same offer data the button uses, so you can render your own UI.

Demo

npm install
npm run dev

The dev page shows the button in the top-right, feature toggles to flip sections on/off, a sample ANS card render, and a code snippet showing the minimal integration.

Production CSP

vite.config.ts already includes the Web3 CSP entries you need. If you deploy behind your own hosting, make sure the production CSP still allows:

  • connect-srchttps://rpc.apertum.io (or your own RPC), wss://relay.walletconnect.com, https://*.walletconnect.com, https://explorer.apertum.io
  • img-srchttps://ipfs.io, https://gateway.pinata.cloud

License

MIT. Use it, fork it, ship it.

About

Reusable ANS Wallet Button component for Apertum platforms. Modular wallet connect button with ANS domain integration, music, offers, send, and extensible feature system. Easy to drop into any React dapp on Apertum.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages