npm package: @metalend/widget
Description: MetaLend widget - A reusable React component for integrating MetaLend DeFi functionality into any application.
Author: metalend
Latest version: 1.0.2

# 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](https://metalend-defi.github.io/public-api-swagger/).

## Access

MetaLendWidget component requires API key which you can obtain in [MetaLend developer dashboard](https://developer.metalend.tech/developer).

## Features

- **Single-Component Integration** — one `<MetaLendWidget />` with an API key and connectors
- **Multi-Chain** — Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, Linea
- **Multi-Token** — USDC, USDT, RLUSD, MUSD
- **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

```bash
npm install @metalend/widget
```

or with yarn:

```bash
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.27.0              |
| `@tanstack/react-query` | ^5.90.16             |

```bash
npm install react react-dom wagmi viem @tanstack/react-query
```

## Quick Start

```tsx
import { MetaLendWidget } from '@metalend/widget'
import '@metalend/widget/style.css'
import { injected } from 'wagmi/connectors'

function App() {
  return <MetaLendWidget apiKey="your-metalend-api-key" connectors={[injected()]} />
}
```

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.

## 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):

```tsx
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:

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

function MiniApp() {
  return (
    <MetaLendWidget
      apiKey="your-metalend-api-key"
      connectors={[
        coinbaseWallet({
          appName: 'My MiniApp',
          preference: 'smartWalletOnly',
        }),
      ]}
      isMiniappMode={true}
      paymasterUrl="https://api.developer.coinbase.com/rpc/v1/base/YOUR_KEY"
    />
  )
}
```

**Key points:**

- `isMiniappMode` enables Coinbase Smart Wallet defaults
- `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:

- **Standard mode**: `injected` (MetaMask, Brave, etc.) + `baseAccount`
- **Miniapp mode** (`isMiniappMode={true}`): `injected` + `coinbaseWallet`

```tsx
<MetaLendWidget apiKey="your-metalend-api-key" />
```

## 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 for wallet connections. Required when `useExternalWagmiProvider` is `false` and you want to override the defaults. |
| `useExternalWagmiProvider` | `boolean`             | No       | `false`  | Skip creating an internal WagmiProvider — use the parent app's provider instead.                                                    |
| `showWalletConnect`        | `boolean`             | No       | `false`  | Show the built-in wallet connection UI inside the widget.                                                                           |
| `customRpcUrls`            | `CustomRpcUrls`       | No       | Built-in | Custom RPC endpoints per chain name (see below).                                                                                    |
| `isMiniappMode`            | `boolean`             | No       | `false`  | Enable Coinbase miniapp mode (smart wallet defaults + paymaster support).                                                           |
| `paymasterUrl`             | `string`              | No       | —        | Paymaster URL for sponsored (gasless) transactions. Used with `isMiniappMode`.                                                      |
| `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`

```typescript
type ChainKind = 'base' | 'ethereum' | 'polygon' | 'arbitrum' | 'optimism' | 'avalanche' | 'linea'
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:

```tsx
<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`

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

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

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

### `TrackingProvider`

```typescript
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:

```tsx
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`                   | User view given URL                          |
| `Open ToS/Privacy Modal`         | ToS/Privacy link opened                      |
| `RebalancingCreated`             | Rebalancer config created (first setup)      |
| `RebalancingUpdated`             | Rebalancer config updated                    |
| `RebalancingDeposit`             | Deposit completed successfully               |
| `DepositBlockedByCountry`        | Deposit blocked due to Geography regulations |
| `RebalancingDepositFailed`       | Deposit failed                               |
| `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](https://developer.metalend.tech/developer). 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>
  └── WagmiProvider (conditional — skipped when useExternalWagmiProvider is true)
       └── QueryClientProvider
            └── ProjectAndUserSettingsProvider
                 └── ToastProvider
                      └── 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 on wallet disconnect or account switch

## 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/](https://metalend-defi.github.io/public-api-swagger/)

## License

MIT © MetaLend

## Support

- **API Docs**: [MetaLend API Documentation](https://metalend-defi.github.io/public-api-swagger/)
- **Email**: [support@metalend.tech](mailto:support@metalend.tech)
- **Litepaper**: [MetaLend Litepaper](https://metalend-inc.gitbook.io/litepaper)
- **Terms of Service**: [MetaLend Terms of Service](https://metalend-inc.gitbook.io/litepaper/terms-of-service)