Skip to main content
The Turtle Earn Widget is a ready-made, customizable, and self-contained component that allows Turtle distribution partners to earn rewards by sharing Turtle Earn products with their users. It provides a seamless integration experience similar to payment providers like Stripe but for Web3 applications.

Overview

The EarnWidget component is a self-contained package that:
  • Handles wallet connections and authentication
  • Fetches and displays available earning opportunities
  • Manages transaction flows for deposits
  • Provides a customizable UI that matches your brand
  • Third provider agnostic, you can use it with any provider you want (more on that later).

Installation

bun add @turtleclub/earn-widget

Required Setup

Important: The EarnWidget component requires several providers to be configured in your application. Make sure to wrap your component with all the required providers or use our default provider package.
The EarnWidget depends on the following:
  1. An EVM library provider - For blockchain interactions
  2. A wallet connection provider - For wallet management
  3. An adapter - To connect the widget with your providers
Don’t have these providers? We recommend using @turtleclub/earn-provider which provides everything you need out of the box. Check the Required Setup section below.

How it Works

  1. The EarnWidget component renders based on your chosen configuration and adapter
  2. Users connect their wallet through your adapter’s openConnectionModal method
  3. The widget fetches pre-filtered Turtle Earn opportunities based on your unique distributor ID
  4. Users can browse and select opportunities to deposit into
  5. Transactions are handled through your adapter’s sendTransaction method
  6. The widget manages all UI states: loading, errors, and success states
The widget is completely self-contained and handles the entire user flow from connection to earning.

Basic Usage

Here’s a simple example showing how to implement the EarnWidget with a custom adapter:
MyEarnWidget.tsx
import { EarnWidget } from "@turtleclub/earn-widget";
import type { Adapter, WidgetStyleConfig } from "@turtleclub/earn-widget";

// Custom adapter implementation
const customAdapter: Adapter = {
  user: undefined, // User's wallet address when connected
  network: 1, // Current network ID
  
  openConnectionModal: () => {
    console.log("Opening wallet connection modal...");
    // Implement your wallet connection logic here
  },
  
  signMessage: async (message: string) => {
    console.log("Signing message:", message);
    // Implement your message signing logic here
    return "0x...signed-message";
  },
  
  sendTransaction: async (transaction) => {
    console.log("Sending transaction:", transaction);
    // Implement your transaction sending logic here
    return "0x...transaction-hash";
  },
  
  changeNetwork: async (networkId: number) => {
    console.log("Changing to network:", networkId);
    // Implement your network switching logic here
  }
};

// Widget configuration
const widgetConfig: WidgetStyleConfig = {
  theme: "dark",
  widgetWidth: "default",
  showNavigation: true,
  padding: "default",
  rounding: "lg",
};

export function MyEarnWidget() {
  return (
    <EarnWidget
      config={widgetConfig}
      adapter={customAdapter}
      distributorId={{ /* Your unique distributor ID from https://dashboard.turtle.xyz/ */ }}
    />
  );
}

Required Setup Section

If you don’t have the required providers already configured in your application, we recommend using @turtleclub/earn-provider which provides everything you need:

Earn Provider

The easiest way to implement the required providers for the Earn Widget

Types

EarnWidgetProps Interface

widget-props.ts
export interface EarnWidgetProps {
  // Widget configuration
  config: WidgetStyleConfig;
  adapter: Adapter;
  distributorId: string;
}

Adapter Interface

adapter.ts
export interface Adapter {
  // User information
  user: string | undefined;
  network: number | undefined;

  // Required adapter methods
  openConnectionModal: () => void;
  signMessage: (message: string) => Promise<string>;
  sendTransaction: (transaction: Transaction) => Promise<string>;
  changeNetwork: (network: number) => Promise<void>;
}

WidgetStyleConfig Interface

style-config.ts
export interface WidgetStyleConfig {
  // Theme
  theme?: "light" | "dark" | "auto";

  // Widget width
  widgetWidth?: "default" | "full" | "custom";
  customWidth?: string;

  // Navigation
  showNavigation?: boolean;

  // Layout
  padding?: "none" | "sm" | "default" | "md" | "lg";
  rounding?: "none" | "sm" | "default" | "lg" | "xl" | "full";

  // Typography
  fontFamily?: string;
  fontSecondary?: string;

  // Logo
  logo?: {
    light?: string;
    dark?: string;
    fallback?: string; // Fallback to text if no logo is provided
  };

  // Deals & Campaigns
  // @deprecated As of v0.4.0 - The widget now automatically lists all available opportunities
  deals?: string[];
  // @deprecated As of v0.4.0 - The widget now automatically lists all available opportunities
  campaigns?: string[];

  // Colors
  styles?: WidgetStyles;
}

export interface WidgetStyles {
  background: HexColor;
  background_dark: HexColor;
  foreground: HexColor;
  foreground_dark: HexColor;
  primary: HexColor;
  primary_dark: HexColor;
  card?: HexColor;
  card_dark?: HexColor;
  muted_foreground?: HexColor;
  muted_foreground_dark?: HexColor;
}

Advanced Usage

Custom Adapter Implementation

If you’re not using Wagmi or our default provider, you can implement your own adapter:
custom-adapter.tsx
import { ethers } from 'ethers';
import type { Adapter } from '@turtleclub/earn-widget';

export function useCustomAdapter(): Adapter {
  const [provider, setProvider] = useState<ethers.BrowserProvider>();
  const [account, setAccount] = useState<string>();
  const [chainId, setChainId] = useState<number>();
  
  return {
    user: account,
    network: chainId,
    
    openConnectionModal: async () => {
      // Your wallet connection logic
      const web3Provider = new ethers.BrowserProvider(window.ethereum);
      const accounts = await web3Provider.send("eth_requestAccounts", []);
      setAccount(accounts[0]);
      // ...
    },
    
    signMessage: async (message: string) => {
      const signer = await provider!.getSigner();
      return signer.signMessage(message);
    },
    
    sendTransaction: async (tx) => {
      const signer = await provider!.getSigner();
      const response = await signer.sendTransaction(tx);
      const receipt = await response.wait();
      return receipt.hash;
    },
    
    changeNetwork: async (networkId: number) => {
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: `0x${networkId.toString(16)}` }],
      });
    }
  };
}

Migration from Previous Version

If you’re migrating from the old EarnPage component:
  1. Package Change: Install @turtleclub/earn-widget instead of @turtleclub/react
  2. Component Name: Use EarnWidget instead of EarnPage
  3. Props Structure:
    • Replace individual props with config and adapter objects
    • referral is now distributorId
    • Remove header prop (use config.logo instead)
  4. Adapter Pattern: Instead of spreading adapter props, pass the adapter object directly
// Old
<EarnPage
  referral="YOUR_CODE"
  user={address}
  {...adapter}
/>

// New
<EarnWidget
  distributorId={{ /* Your unique distributor ID from https://dashboard.turtle.xyz/ */ }}
  config={config}
  adapter={adapter}
/>