react-reward-button
Version:
Drop-in React component that sends Ethereum token rewards and shows confetti animations. Built with wagmi, ethers, and ShadCN UI.
272 lines (265 loc) • 8.65 kB
TypeScript
import React from 'react';
import { ClassValue } from 'clsx';
export { ethers } from 'ethers';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
/**
* Whether the button should render as a child component (using Slot)
* This allows for composition patterns common in shadcn/ui
*/
asChild?: boolean;
/**
* Visual variants for the button
*/
variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive';
/**
* Size variants for the button
*/
size?: 'default' | 'sm' | 'lg' | 'icon';
/**
* Whether the button is in a loading state
*/
isLoading?: boolean;
/**
* Custom text to show when loading
*/
loadingText?: string;
/**
* Whether the button is in a success state
*/
isSuccess?: boolean;
}
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
interface TokenInfo {
symbol: string;
decimals: number;
name: string;
}
interface RewardButtonState {
isLoading: boolean;
error: string | null;
tokenInfo: TokenInfo | null;
isSuccess: boolean;
}
interface RewardButtonProps extends Omit<ButtonProps, 'isLoading'> {
/** The Ethereum address of the reward token contract (optional - if not provided, behaves as regular button) */
tokenAddress?: string;
/** The amount of tokens to reward (in wei or token units) (optional - if not provided, behaves as regular button) */
rewardAmount?: string;
/**
* The recipient address for the reward (optional)
* Priority: 1. Connected wallet address, 2. This recipientAddress prop
* If neither is provided, the reward claim will fail with an error
* No fallback address is used for security reasons
*/
recipientAddress?: string;
/** The sender wallet address that holds the reward tokens */
senderAddress?: string;
/** The private key of the sender wallet (for signing transactions) */
senderPrivateKey?: string;
/** RPC URL for the network (optional - uses default if not provided) */
rpcUrl?: string;
/**
* Callback function called when the reward button is clicked (for non-Web3 mode)
* If tokenAddress and rewardAmount are provided, this is ignored in favor of Web3 functionality
*/
onReward?: () => void | Promise<void>;
/** Callback function called when reward is successfully claimed */
onRewardClaimed?: (txHash: string, amount: string) => void;
/** Callback function called when reward claim fails */
onRewardFailed?: (error: Error) => void;
/** Callback function called when reward claim is initiated */
onRewardStarted?: () => void;
/** Whether to show the reward amount on the button */
showRewardAmount?: boolean;
/** Custom token symbol to display (e.g., "USDC", "ETH") */
tokenSymbol?: string;
/** Whether to require wallet connection before claiming */
requireConnection?: boolean;
/** Custom loading text for reward operations */
loadingText?: string;
/**
* Whether the user (receiver) pays gas fees instead of sender
* - true: Connected wallet pays gas fees (transferFrom pattern)
* - false: Sender wallet pays gas fees (transfer pattern - default)
*/
userPaysGas?: boolean;
/** Whether the button is in a loading state */
isLoading?: boolean;
/**
* Content to display inside the button
* @default "Claim Reward"
*/
children?: React.ReactNode;
}
declare const RewardButton: React.FC<RewardButtonProps>;
/**
* Utility function for merging class names using clsx
* This is inspired by shadcn/ui's cn() utility
*/
declare function cn(...inputs: ClassValue[]): string;
declare const ERC20_ABI: readonly [{
readonly constant: true;
readonly inputs: readonly [];
readonly name: "name";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [];
readonly name: "symbol";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [];
readonly name: "decimals";
readonly outputs: readonly [{
readonly name: "";
readonly type: "uint8";
}];
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly name: "_owner";
readonly type: "address";
}];
readonly name: "balanceOf";
readonly outputs: readonly [{
readonly name: "balance";
readonly type: "uint256";
}];
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly name: "_to";
readonly type: "address";
}, {
readonly name: "_value";
readonly type: "uint256";
}];
readonly name: "transfer";
readonly outputs: readonly [{
readonly name: "";
readonly type: "bool";
}];
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly name: "_spender";
readonly type: "address";
}, {
readonly name: "_value";
readonly type: "uint256";
}];
readonly name: "approve";
readonly outputs: readonly [{
readonly name: "";
readonly type: "bool";
}];
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly name: "_from";
readonly type: "address";
}, {
readonly name: "_to";
readonly type: "address";
}, {
readonly name: "_value";
readonly type: "uint256";
}];
readonly name: "transferFrom";
readonly outputs: readonly [{
readonly name: "";
readonly type: "bool";
}];
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly name: "_owner";
readonly type: "address";
}, {
readonly name: "_spender";
readonly type: "address";
}];
readonly name: "allowance";
readonly outputs: readonly [{
readonly name: "";
readonly type: "uint256";
}];
readonly type: "function";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly name: "from";
readonly type: "address";
}, {
readonly indexed: true;
readonly name: "to";
readonly type: "address";
}, {
readonly indexed: false;
readonly name: "value";
readonly type: "uint256";
}];
readonly name: "Transfer";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly name: "owner";
readonly type: "address";
}, {
readonly indexed: true;
readonly name: "spender";
readonly type: "address";
}, {
readonly indexed: false;
readonly name: "value";
readonly type: "uint256";
}];
readonly name: "Approval";
readonly type: "event";
}];
declare const COMMON_TOKENS: {
readonly USDC: "0xA0b86a33E6441b6b07c2fE4c2b4B8B1d8B7a0F4c";
readonly USDT: "0xdAC17F958D2ee523a2206206994597C13D831ec7";
readonly DAI: "0x6B175474E89094C44Da98b954EedeAC495271d0F";
readonly WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
};
declare const BUTTON_VARIANTS: {
readonly default: "reward-button--default";
readonly secondary: "reward-button--secondary";
readonly outline: "reward-button--outline";
readonly ghost: "reward-button--ghost";
readonly destructive: "reward-button--destructive";
};
declare const BUTTON_SIZES: {
readonly default: "reward-button--size-default";
readonly sm: "reward-button--size-sm";
readonly lg: "reward-button--size-lg";
readonly icon: "reward-button--size-icon";
};
declare const DEFAULT_BUTTON_TEXT = "Claim Reward";
declare const CSS_CLASSES: {
readonly base: "reward-button";
readonly loading: "reward-button--loading";
readonly disabled: "reward-button--disabled";
readonly loadingContent: "reward-button__loading";
readonly spinner: "reward-button__spinner";
};
export { BUTTON_SIZES, BUTTON_VARIANTS, Button, COMMON_TOKENS, CSS_CLASSES, DEFAULT_BUTTON_TEXT, ERC20_ABI, RewardButton, cn, RewardButton as default };
export type { ButtonProps, RewardButtonProps, RewardButtonState, TokenInfo };