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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@metalend/widget

v2.0.0

Published

MetaLend widget - A reusable React component for integrating MetaLend DeFi functionality into any application.

Readme

MetaLend Widget

A drop-in React component for integrating MetaLend DeFi yield optimization rebalancer into any application. The widget provides a complete interface for depositing, withdrawing, and rebalancing positions across multiple chains and lending protocols — powered by the MetaLend Rebalancing API.

Access

MetaLendWidget component requires API key which you can obtain in MetaLend developer dashboard.

Features

  • Single-Component Integration — one <MetaLendWidget /> with an API key and connectors
  • Multi-Chain — Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, Linea, Arc
  • Multi-Token — USDC, USDT, RLUSD, MUSD, PYUSD, USDG, USDE
  • Multi-Protocol — Aave, Morpho, Euler with automatic rebalancing
  • Project Settings — supported tokens, chains, and protocols are configured per API key via the MetaLend dashboard; no prop-level filtering needed
  • Flexible Wallet Support — works with any wagmi-compatible connector (MetaMask, Coinbase Wallet, WalletConnect, Privy, etc.)
  • RPC Failover — multiple RPC endpoints per chain with automatic fallback
  • Coinbase Miniapp Mode — smart wallet + paymaster-sponsored transactions out of the box
  • Analytics Ready — plug in any analytics SDK via the TrackingProvider interface

Installation

npm install @metalend/widget

or with yarn:

yarn add @metalend/widget

Peer Dependencies

These must be installed in your application:

| Package | Version | | ----------------------- | -------------------- | | react | ^18.0.0 || ^19.0.0 | | react-dom | ^18.0.0 || ^19.0.0 | | wagmi | ^2.19.5 | | viem | ^2.51.0 | | @tanstack/react-query | ^5.90.16 |

npm install react react-dom wagmi@2 viem @tanstack/react-query

Quick Start

import { MetaLendWidget } from '@metalend/widget'
import '@metalend/widget/style.css'

function App() {
  return <MetaLendWidget apiKey="your-metalend-api-key" />
}

That's it. The widget handles wallet connection, chain management, deposits, withdrawals, rebalancer configuration, and rewards — all scoped to the tokens, chains, and protocols enabled for your API key in the MetaLend dashboard.

With no connectors prop the widget owns wagmi, uses its built-in connectors, and shows the Welcome → Connect → SIWE flow. As soon as you pass your own connectors, that flow is off by default — add showWelcomeAuthFlow to keep it, or the widget renders without any way to sign in. showWalletConnect is not a substitute: it renders the wallet button (connect, address, disconnect) but never runs the SIWE challenge, so the user stays unauthenticated and balances, deposits and withdrawals remain unavailable.

import { injected } from 'wagmi/connectors'

;<MetaLendWidget apiKey="your-metalend-api-key" connectors={[injected()]} showWelcomeAuthFlow={true} />

Use Cases

1. Full DApp Integration (with Privy) - injecting existing wagmi context

For DApps that already manage their own wagmi provider (f.e. via Privy):

import { MetaLendWidget } from '@metalend/widget'
import '@metalend/widget/style.css'
import { PrivyProvider } from '@privy-io/react-auth'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider, createConfig, http } from 'wagmi'
import { arbitrum, base, mainnet, optimism, polygon } from 'wagmi/chains'

const wagmiConfig = createConfig({
  chains: [base, mainnet, arbitrum, optimism, polygon],
  transports: {
    [base.id]: http(),
    [mainnet.id]: http(),
    [arbitrum.id]: http(),
    [optimism.id]: http(),
    [polygon.id]: http(),
  },
})

const queryClient = new QueryClient()

function App() {
  return (
    <PrivyProvider appId="your-privy-app-id">
      <QueryClientProvider client={queryClient}>
        <WagmiProvider config={wagmiConfig}>
          <MetaLendWidget apiKey="your-metalend-api-key" useExternalWagmiProvider={true} />
        </WagmiProvider>
      </QueryClientProvider>
    </PrivyProvider>
  )
}

Key points:

  • Set useExternalWagmiProvider={true} so the widget uses your existing wagmi context
  • All wallet connectors configured in your wagmi config work automatically
  • Privy handles the wallet connection UI

2. Coinbase Miniapp

For miniapps running inside the Coinbase Wallet with sponsored transactions:

import { MetaLendWidget } from '@metalend/widget'
import '@metalend/widget/style.css'
import { coinbaseWallet } from 'wagmi/connectors'

const MINIAPP_CONNECTORS = [
  coinbaseWallet({
    appName: 'Your Miniapp',
    preference: { options: 'smartWalletOnly' },
  }),
]

function MiniApp() {
  return (
    <MetaLendWidget
      apiKey="your-metalend-api-key"
      connectors={MINIAPP_CONNECTORS}
      showWelcomeAuthFlow={true}
      showWalletConnect={true}
      paymasterUrl="https://api.developer.coinbase.com/rpc/v1/base/YOUR_KEY"
    />
  )
}

Key points:

  • Pass the coinbaseWallet connector via connectors — the widget builds its own wagmi config around it, so no parent WagmiProvider is needed
  • If your app already owns a WagmiProvider, set useExternalWagmiProvider={true} and wrap the widget in it; without a parent provider that flag alone leaves the widget with no wagmi context
  • The widget auto-detects the Coinbase Smart Wallet at runtime (on-chain ERC-1271 bytecode probe, with a coinbaseWalletSDK connector fallback) and uses the correct signing path (plain hash vs { raw: hash }) — no extra prop needed
  • paymasterUrl enables gasless (sponsored) transactions
  • Typically scoped to a single chain and token via project settings
  • URL: portal.cdp.coinbase.com

3. Default Connectors (Zero Config)

If you omit the connectors prop and useExternalWagmiProvider is false, the widget uses sensible defaults:

  • [injected, baseAccount] — suitable for standard web integrations.
  • For specialized contexts (e.g. Coinbase miniapp with coinbaseWallet), pass your own connectors or use useExternalWagmiProvider with your own Wagmi config.
<MetaLendWidget apiKey="your-metalend-api-key" />

Wagmi, welcome flow, and wallet UI

Pick useExternalWagmiProvider, showWelcomeAuthFlow, and optional connectors together. The table is about who owns WagmiProvider and whether the widget shows the root Welcome → Connect → SIWE flow.

| useExternalWagmiProvider | showWelcomeAuthFlow | Who provides WagmiProvider | Root welcome + connector + SIWE | | -------------------------- | --------------------- | ------------------------------------ | -------------------------------------------------------------------- | | false | false | Widget | Yes if you use default connectors (no connectors prop, or empty) | | false | true | Widget | Yes (always, even with custom connectors) | | true | false | Your app (required) | No — your wagmi handles connection | | true | true | Widget (no parent wrap required) | Yes — widget builds wagmi from connectors or built-in defaults |

showWalletConnect (top-right wallet control):

  • If showWalletConnect is off: no built-in wallet chrome.
  • If on and welcome-style gate is active (default connectors path or showWelcomeAuthFlow): the wallet button appears only after the user is authenticated (welcome + modals cover pre-auth).
  • If on with useExternalWagmiProvider only (showWelcomeAuthFlow off): the wallet button is shown whenever showWalletConnect is true (your app owns connection UX). The widget runs no SIWE challenge in this mode, so your app must supply the MetaLend session itself — otherwise enable showWelcomeAuthFlow.

Note: If you wrap your own WagmiProvider and set useExternalWagmiProvider={true} with showWelcomeAuthFlow={true}, the widget subtree uses the widget’s inner wagmi config. Prefer one owner: either parent-only external wagmi, or widget-owned welcome mode without a duplicate parent WagmiProvider around the widget.

API Reference

<MetaLendWidget />

| Prop | Type | Required | Default | Description | | -------------------------- | --------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | apiKey | string | Yes | — | MetaLend API key. Determines project settings (tokens, chains, protocols). | | connectors | CreateConnectorFn[] | No | Built-in | Wagmi connectors. Omitted or empty with widget-owned wagmi → [injected, baseAccount]. With useExternalWagmiProvider alone, parent config defines connectors. | | useExternalWagmiProvider | boolean | No | false | Use parent WagmiProvider instead of creating one — unless showWelcomeAuthFlow is true, then the widget still creates its own provider. | | showWelcomeAuthFlow | boolean | No | false | Root Welcome → Connect → SIWE flow. With external wagmi flag, still mounts internal WagmiProvider so no parent wagmi wrapper is required. | | showWalletConnect | boolean | No | false | Show the built-in wallet button (connect, address, disconnect). Wallet UI only — it does not run SIWE, so it cannot replace showWelcomeAuthFlow. | | customRpcUrls | CustomRpcUrls | No | Built-in | Custom RPC endpoints per chain name (see below). | | paymasterUrl | string | No | — | Paymaster URL for sponsored (gasless) transactions. Typically used by parents integrating a Coinbase Smart Wallet / miniapp. | | trackingProvider | TrackingProvider | No | — | Analytics integration (see below). | | theme | WidgetTheme | No | MetaLend | Theme overrides — merged with the default theme. | | className | string | No | '' | CSS class name for the widget container. |

CustomRpcUrls

type ChainKind = 'base' | 'ethereum' | 'polygon' | 'arbitrum' | 'optimism' | 'avalanche' | 'linea' | 'arc'
type CustomRpcUrls = Partial<Record<ChainKind, string[]>>

Provide an array of RPC URLs per chain. The widget ensures at least 3 endpoints per chain by merging your URLs with built-in defaults:

<MetaLendWidget
  apiKey="your-api-key"
  customRpcUrls={{
    base: ['https://my-base-rpc.example.com', 'https://my-base-rpc-2.example.com'],
    ethereum: ['https://my-eth-rpc.example.com'],
  }}
/>

WidgetTheme

interface WidgetTheme {
  colors?: {
    primary?: string
    secondary?: string
    background?: string
    backgroundLight?: string
    backgroundHeader?: string
    text?: string
    border?: string
    error?: string
    success?: string
  }
  borderRadius?: string
  fontFamily?: string
}

Only specified properties are overridden — the rest use the MetaLend defaults:

<MetaLendWidget
  apiKey="your-api-key"
  theme={{
    colors: {
      primary: '#8B5CF6',
      background: '#0A0A0F',
    },
    borderRadius: '16px',
    fontFamily: 'Inter, sans-serif',
  }}
/>

TrackingProvider

interface TrackingProvider {
  init?: () => void | Promise<void>
  identify?: (userId: string, properties?: Record<string, unknown>) => void | Promise<void>
  track: (event: string, properties?: Record<string, unknown>) => void | Promise<void>
}

Wrap any analytics SDK behind this interface:

import mixpanel from 'mixpanel-browser'

;<MetaLendWidget
  apiKey="your-api-key"
  trackingProvider={{
    init: () => mixpanel.init('your-mixpanel-token'),
    identify: (userId) => mixpanel.identify(userId),
    track: (event, props) => mixpanel.track(event, props),
  }}
/>

Events emitted by the widget:

| Event | Description | | ------------------------------------------------ | ---------------------------------------------- | | UserLoggedIn | Wallet connected and authenticated | | PageView \| URL: {path} \| Hash: {hash} | Route view (event name includes path and hash) | | Open ToS/Privacy Modal | ToS/Privacy link opened | | RebalancingCreated | Rebalancer config created (first setup) | | RebalancingUpdated | Rebalancer config updated | | RebalancingUpdated: Failed | Rebalancer config update failed | | RebalancingCreated - Deposit (default) | Config created as part of a deposit | | RebalancingUpdated - Deposit (default) | Config updated as part of a deposit | | RebalancingUpdated - Deposit (default): Failed | Config update during deposit failed | | RebalancingDeposit | Deposit completed successfully | | RebalancingDepositBridging | Deposit required a cross-chain bridge | | RebalancingDeposit: Failed | Deposit transaction failed | | RebalancingDepositFailed | Deposit failed | | DepositBlockedByCountry | Deposit blocked due to Geography regulations | | RebalancingWithdraw | Withdrawal completed successfully | | RebalancingClaimRewardsSuccess | Rewards claimed successfully | | RebalancingClaimRewardsError | Rewards claim failed | | ErrorLoadingBlockchainData | Error fetching blockchain data from RPC |

Geography Limitations

MetaLend complies with international regulations by restricting deposit functionality in certain countries. When a user attempts to make a deposit, the widget performs an IP-based geolocation check. If the user is detected to be in one of the restricted jurisdictions listed below, deposits will be blocked. Users can still view their balances and withdraw funds regardless of their location.

Countries currently restricted from deposits:

  • Bosnia and Herzegovina (BA)
  • Serbia (RS)
  • Belarus (BY)
  • Myanmar (MM)
  • Côte d’Ivoire / Ivory Coast (CI)
  • Cuba (CU)
  • Congo (Democratic Republic) (CD)
  • Iran (IR)
  • Iraq (IQ)
  • Liberia (LR)
  • North Korea (KP)
  • Sudan (SD)
  • Syria (SY)
  • Zimbabwe (ZW)

How It Works

Project Settings

Supported tokens, chains, and protocols are configured per API key through the MetaLend dashboard. When the widget mounts, it fetches your project settings from the API and scopes all UI and blockchain interactions accordingly.

This means two integrators with different API keys can show different token/chain combinations without changing any code.

The widget also merges in the user's own signed rebalancer configuration, so users can always see balances for tokens/chains they previously set up — even if you later disable them in your project settings. This ensures users can still view their positions and withdraw at any time.

Example: your project settings enable USDC on Base and Ethereum; a user previously configured USDT on Ethereum. The widget shows USDC (Base, Ethereum) + USDT (Ethereum) for that user.

Provider Architecture

<MetaLendWidget>
  └── QueryClientProvider
       └── WagmiProvider (skipped only when useExternalWagmiProvider is true AND showWelcomeAuthFlow is false)
            └── ProjectAndUserSettingsProvider
                 └── ToastProvider
                      └── AutoConnect (session restore + forced config re-sign)
                           └── RouterProvider (TanStack Router, in-memory)
                                └── Dashboard / Deposit / Withdraw / Rewards views

Authentication Flow

The widget uses a challenge-verify flow for JWT issuance:

  1. Wallet connects via wagmi
  2. Widget requests a challenge from the MetaLend API
  3. User signs the challenge message
  4. Widget verifies the signature and receives a JWT
  5. JWT is used for deposit, withdrawal, and config update operations
  6. JWT is automatically invalidated when the user disconnects their wallet

The session survives a page reload: the JWT is kept in localStorage and the widget reconnects the wallet the user last used. If that wallet cannot be restored (locked, permission revoked), the session stays valid and the user is offered a reconnect instead of having to sign in again.

Session invalidation on upgrade: the widget stores its own version alongside the JWT. When you ship a release built on a different widget version, existing sessions are cleared and users sign in again — this is how updated Terms of Service get re-signed. Expect one sign-in prompt per widget version bump.

Wallet Support

The widget works with any wagmi-compatible connector:

  • MetaMask
  • Coinbase Wallet (including Smart Wallet)
  • WalletConnect
  • Brave Wallet
  • Trust Wallet
  • Rainbow Wallet
  • Any EIP-6963 compliant wallet

When using useExternalWagmiProvider={true}, all connectors from the parent wagmi config work automatically.

API Documentation

The MetaLend Rebalancing API documentation is available at: https://metalend-defi.github.io/public-api-swagger/

License

MIT © MetaLend

Support