@feyprotocol/sdk
v1.0.5
Published
TypeScript SDK for interacting with the FEY Protocol on Base. Supports both direct client usage (server-side or vanilla JS) and React hooks (built on TanStack Query).
Readme
@feyprotocol/sdk
TypeScript SDK for interacting with the FEY Protocol on Base. Supports both direct client usage (server-side or vanilla JS) and React hooks (built on TanStack Query).
Installation
npm install @feyprotocol/sdk
# or
yarn add @feyprotocol/sdk
# or
bun add @feyprotocol/sdkPeer Dependencies
The SDK requires the following peer dependencies:
{
"viem": "^2.x",
"wagmi": "^2.x",
"@tanstack/react-query": "^5.x",
"react": "^18.x || ^19.x"
}Note: If you're only using the vanilla JS client (not React hooks), you only need
viem.
Quick Start
Vanilla JS / Server-side
import { createClient } from "@feyprotocol/sdk";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";
// Create a viem public client
const publicClient = createPublicClient({
chain: base,
transport: http(),
});
// Create the FEY client
const fey = createClient({
publicClient,
app: { name: "MyApp" },
api: { key: "your-apy-key" },
});
// Fetch a token
const token = await fey.tokens.find({ id: "0x..." });
console.log(token?.name, token?.symbol);React (with wagmi)
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { FeyProvider, useFindToken } from "@feyprotocol/sdk";
const queryClient = new QueryClient();
function App() {
return (
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<FeyProvider config={{ app: { name: "MyApp" }, api: { url: "https://fey.money/api" } }}>
<TokenDisplay />
</FeyProvider>
</QueryClientProvider>
</WagmiProvider>
);
}
function TokenDisplay() {
const { data: token, isLoading } = useFindToken({ id: "0x..." });
if (isLoading) return <div>Loading...</div>;
return <div>{token?.name} ({token?.symbol})</div>;
}Core Client API
The createClient function creates a FeyClient instance with namespaced methods for all protocol operations.
createClient(params)
import { createClient } from "@feyprotocol/sdk";
const client = createClient({
// Option 1: Pass clients directly
publicClient: viemPublicClient,
walletClient: viemWalletClient, // optional, required for write operations
// Option 2: Pass getters (useful for dynamic clients)
// getPublicClient: () => publicClient,
// getWalletClient: () => walletClient,
// App metadata
app: { name: "MyApp" },
// API configuration
api: {
// url: "https://fey.money/api", (optional override)
key: "your-api-key",
},
});Client Namespaces
client.users
| Method | Description |
|--------|-------------|
| find({ address }) | Fetch user profile by wallet address |
| list({ limit?, cursor? }) | List users with pagination |
client.balances
| Method | Description |
|--------|-------------|
| find({ accountAddress, tokenAddress }) | Fetch token balance for a specific account |
| list({ accountAddress, limit?, cursor? }) | List token balances for an account |
| search({ accountAddress, query }) | Search token balances by query |
client.ceremonies
| Method | Description |
|--------|-------------|
| find({ id }) | Fetch ceremony details by ID |
| list({ ids }) | Fetch multiple ceremonies by IDs |
| search({ query?, stage?, limit?, offset?, sort?, filter? }) | Search ceremonies with filters |
| participants({ ceremonyId, limit?, cursor? }) | Fetch ceremony participants |
| create(params) | Create a new ceremony (community raise) |
| update({ ceremonyId, set }) | Update ceremony configuration |
| start({ ceremonyId }) | Start accepting contributions |
| complete({ ceremonyId }) | Complete ceremony and deploy token |
| cancel({ ceremonyId }) | Cancel ceremony and refund contributors |
| simulate({ launchpad, goal, founderBuysEth?, treasuryReserveEth? }) | Preview token allocations |
client.tokens
| Method | Description |
|--------|-------------|
| find({ id }) | Fetch token details by address |
| list({ ids }) | Fetch multiple tokens by addresses |
| search({ query?, stage?, limit?, offset?, sort?, filter? }) | Search tokens with filters |
| create(params) | Create a new token (instant launch) |
| simulate({ founderBuy }) | Preview token launch allocations |
client.prices
| Method | Description |
|--------|-------------|
| find({ id }) | Fetch current price for a token |
| list({ ids }) | Fetch prices for multiple tokens |
client.fees
| Method | Description |
|--------|-------------|
| find({ id }) | Fetch accumulated fees for a token |
client.tickets
| Method | Description |
|--------|-------------|
| find({ ceremonyId, accountAddress }) | Fetch contribution ticket for a ceremony |
client.vaults
| Method | Description |
|--------|-------------|
| find() | Fetch FEY staking vault details |
client.launchpads
| Method | Description |
|--------|-------------|
| find({ id }) | Fetch launchpad configuration |
| search() | List all available launchpads |
client.whitelists
| Method | Description |
|--------|-------------|
| find({ ceremonyId }) | Fetch whitelist for a ceremony |
| preview({ sources }) | Preview addresses in a whitelist |
| generate({ sources, customAddresses }) | Generate merkle root from sources |
| verify({ ceremonyId, address }) | Verify if address is whitelisted |
Available Sources
| Source | Key | ID | Input | Description |
|--------|-----|-----|-------|-------------|
| Farcaster Followers | farcaster | followers | { username: string } | Pull verified addresses from a Farcaster user's followers |
| FEY Stakers | fey | stakers | { minStaked: number } | List of FEY wallets that have staked at least the specified amount |
React Hooks
All hooks are built on TanStack Query and follow its patterns. They require FeyProvider as an ancestor.
Provider Setup
import { FeyProvider, useFeyClient } from "@feyprotocol/sdk";
// FeyProvider must be inside WagmiProvider
<FeyProvider config={{ app: { name: "MyApp" }, api: { key: "your-api-key" } }}>
{children}
</FeyProvider>
// Access the client directly
function MyComponent() {
const { ready, client } = useFeyClient();
// ready is true when public client is available
}Query Hooks
Query hooks use useQuery and return standard TanStack Query result objects.
Tokens
import { useFindToken, useListTokens, useSearchTokens } from "@feyprotocol/sdk";
// Fetch single token
const { data, isLoading, error } = useFindToken({ id: "0x..." });
// Fetch multiple tokens
const { data } = useListTokens({ ids: ["0x...", "0x..."] });
// Search tokens
const { data } = useSearchTokens({
query: "FEY",
stage: "deployed", // or "ceremony"
limit: 10,
sort: { by: "market-cap", direction: "desc" },
});Ceremonies
import {
useFindCeremony,
useListCeremonies,
useSearchCeremonies,
useCeremonyParticipants,
} from "@feyprotocol/sdk";
const { data: ceremony } = useFindCeremony({ id: 123 });
const { data: ceremonies } = useListCeremonies({ ids: [1, 2, 3] });
const { data: participants } = useCeremonyParticipants({ ceremonyId: 123 });Balances
import { useFindBalance, useListBalances, useSearchBalances } from "@feyprotocol/sdk";
const { data: balance } = useFindBalance({
accountAddress: "0x...",
tokenAddress: "0x...",
});
const { data: balances } = useListBalances({ accountAddress: "0x..." });Prices
import { useFindPrice, useListPrices } from "@feyprotocol/sdk";
const { data: price } = useFindPrice({ id: "0x..." });
const { data: prices } = useListPrices({ ids: ["0x...", "0x..."] });Other Query Hooks
import {
useFindUser,
useListUsers,
useFindFee,
useFindTicket,
useFindVault,
useFindLaunchpad,
useSearchLaunchpads,
useFindWhitelist,
usePreviewWhitelist,
useVerifyWhitelist,
} from "@feyprotocol/sdk";Mutation Hooks
Mutation hooks use useMutation and return standard TanStack Query mutation objects.
Token Creation
import { useCreateToken, useSimulateToken } from "@feyprotocol/sdk";
function CreateToken() {
const { mutateAsync: createToken, isPending } = useCreateToken();
const handleCreate = async () => {
const { hash, predictedAddress } = await createToken({
name: "My Token",
symbol: "MTK",
image: "ipfs://...",
rewards: [
{ recipient: "0x...", bps: 10000 }, // 100% to single recipient
],
founderBuy: { ethAmount: 0.1, recipient: "0x..." }, // optional
});
};
}Ceremony Management
import {
useCreateCeremony,
useUpdateCeremony,
useStartCeremony,
useCompleteCeremony,
useCancelCeremony,
useSimulateCeremony,
} from "@feyprotocol/sdk";
function CreateCeremony() {
const { mutateAsync: createCeremony } = useCreateCeremony();
const handleCreate = async () => {
const hash = await createCeremony({
name: "My Token",
symbol: "MTK",
image: "ipfs://...",
launchpad: "fey", // or "clanker"
goal: 1.0, // ETH
rewards: [{ recipient: "0x...", bps: 10000 }],
// Optional fields:
description: "Token description",
minContribution: 0.01,
maxContribution: 0.5,
founderAllocations: [{ ethAmount: 0.1, recipient: "0x..." }],
treasury: { recipient: "0x...", ethAmount: 0.1 },
whitelistRoot: "0x...",
});
};
}Whitelist Generation
import { useGenerateWhitelist, usePreviewWhitelist } from "@feyprotocol/sdk";
function WhitelistManager() {
const { mutateAsync: generateWhitelist } = useGenerateWhitelist();
const handleGenerate = async () => {
const merkleRoot = await generateWhitelist({
sources: [
{ id: "followers", key: "farcaster", input: { username: "feyprotocol" } },
],
customAddresses: ["0x...", "0x..."],
});
};
}Types
All entity types are exported for TypeScript usage.
Token
import type { Token } from "@feyprotocol/sdk";
interface Token {
stage: "launched" | "funding" | "deploying" | "cancelled";
tokenAddress: string | null;
ceremonyId: number | null;
launchpad: Launchpad;
name: string;
symbol: string;
image: string;
description: string;
decimals: number;
totalSupply: number;
createdAt: Date;
admin: string;
totalHolders: number;
socials: {
website: string | null;
twitter: string | null;
farcaster: string | null;
};
}Ceremony
import type { Ceremony } from "@feyprotocol/sdk";
interface Ceremony {
id: number;
tokenAddress: string | null;
name: string;
symbol: string;
image: string;
description: string;
launchpad: Launchpad;
admin: string;
createdAt: Date;
status: "funding" | "started" | "completed" | "cancelled";
raise: {
goal: TokenAmount;
current: TokenAmount;
percentage: number;
ticket: { min: TokenAmount; max: TokenAmount };
};
founderAllocations: Array<{
accountAddress: string;
allocationIndex: number;
amount: TokenAmount;
}>;
bond: TokenAmount;
whitelistRoot: string;
totalParticipants: number;
reserveEth: TokenAmount;
socials: { website: string | null; twitter: string | null; farcaster: string | null };
}Balance
import type { Balance } from "@feyprotocol/sdk";
interface Balance {
accountAddress: string;
tokenAddress: string;
amount: { unstaked: TokenAmount; staked: TokenAmount };
percentageTotalSupply: number;
percentageHoldingsStaked: number;
}Price
import type { Price } from "@feyprotocol/sdk";
interface Price {
id: string;
price: number | null;
priceChange: { h1: number | null; h6: number | null; h24: number | null };
marketCap: number | null;
volume: { h24: number | null };
topPool: string | null;
liquidityUsd: number | null;
}Contract ABIs
ABIs are exported for direct contract interaction with viem.
import {
FeyFactoryAbi, // Token factory - deploy tokens
TGCSAbi, // Token Generation Ceremony System
XFeyVaultAbi, // FEY staking vault
FeyFeeLockerAbi, // Fee distribution contract
FeyTokenAbi, // FEY token contract
} from "@feyprotocol/sdk";
// Example: Read from contract
import { readContract } from "viem/actions";
const totalStaked = await readContract(publicClient, {
address: contracts.XFeyVault[base.id].address,
abi: XFeyVaultAbi,
functionName: "totalAssets",
});Configuration
Contract Addresses
import { contracts, supportedChains, type SupportedChain } from "@feyprotocol/sdk";
// Access contract addresses per chain
contracts.FeyFactory[8453].address; // Base mainnet
contracts.FeyFactory[84532].address; // Base Sepolia
// Available contracts:
// - WETH
// - FeeRecipient
// - FeyFactory
// - FeyToken
// - XFeyVault
// - FeyFeeLocker
// - FeyLPLocker
// - TGCS
// - FeyUniswapPoolManager
// - FeyMevModule
// - FeyDevBuyExtension
// - FeyStaticFeeHook
// - ClankerFactory
// - ClankerStaticFeeHookV2
// - ClankerDynamicFeeHookV2
// - ClankerLPLocker
// - ClankerMevModuleSupported Chains
import { supportedChains, type SupportedChain } from "@feyprotocol/sdk";
// supportedChains = [base, baseSepolia]Launchpads
import { launchpads } from "@feyprotocol/sdk";
// launchpads[chainId] returns available launchpad configs
// Each launchpad has: { id, name, image, modes }Constants
Protocol constants for calculations and configurations.
import {
TARGET_MARKET_CAP_USD, // 32,000 - Target market cap in USD
RANGE_WIDTH_TICKS, // 110,400 - Uniswap V4 range width
TICK_SPACING, // 200 - Uniswap V4 tick spacing
FEY_FEE_PPM, // 10,000 (1%) - FEY token fee
PAIRED_FEE_PPM, // 10,000 (1%) - Paired token fee
DYNAMIC_FEE_FLAG, // 0x800000 - Dynamic fee hook flag
CEREMONY_PROTOCOL_FEE_BPS, // 250 (2.5%) - Protocol fee on ceremonies
MAX_TREASURY_RESERVE_ETH_BPS, // 5,000 (50%) - Max treasury reserve
} from "@feyprotocol/sdk";Examples
Fetching Token Data
const fey = createClient({ publicClient, api: { url: "https://fey.money/api" } });
// Get token details
const token = await fey.tokens.find({ id: "0xD09cf0982A32DD6856e12d6BF2F08A822eA5D91D" });
console.log(`${token?.name} (${token?.symbol})`);
console.log(`Stage: ${token?.stage}`);
console.log(`Holders: ${token?.totalHolders}`);
// Get price
const price = await fey.prices.find({ id: token?.tokenAddress! });
console.log(`Price: $${price?.price}`);
console.log(`24h Change: ${price?.priceChange.h24}%`);Creating a Token (Instant Launch)
const { hash, predictedAddress } = await fey.tokens.create({
name: "My Token",
symbol: "MTK",
image: "ipfs://QmYourImageHash",
rewards: [
{ recipient: "0xCreator...", bps: 8000 }, // 80% to creator
{ recipient: "0xTreasury...", bps: 2000 }, // 20% to treasury
],
founderBuy: {
ethAmount: 0.5,
recipient: "0xCreator...",
},
metadata: {
description: "My awesome token",
socials: {
twitter: "mytoken",
website: "https://mytoken.com",
},
},
});
console.log(`TX: ${hash}`);
console.log(`Token will be at: ${predictedAddress}`);Creating a Ceremony (Community Raise)
// First, simulate to preview allocations
const simulation = await fey.ceremonies.simulate({
launchpad: "fey",
goal: 2.0, // 2 ETH
founderBuysEth: [0.5], // Founder buys 0.5 ETH worth
treasuryReserveEth: 0.2,
});
console.log(`Projected MCap: $${simulation?.mcapUsd}`);
console.log(`Community allocation: ${simulation?.allocations.community.percentage}%`);
// Create the ceremony
const hash = await fey.ceremonies.create({
name: "Community Token",
symbol: "COM",
image: "ipfs://...",
launchpad: "fey",
goal: 2.0,
rewards: [{ recipient: "0xCreator...", bps: 10000 }],
minContribution: 0.01,
maxContribution: 1.0,
founderAllocations: [{ ethAmount: 0.5, recipient: "0xFounder..." }],
treasury: { recipient: "0xTreasury...", ethAmount: 0.2 },
});Managing Whitelists
// Preview whitelist sources
const preview = await fey.whitelists.preview({
sources: [
{
id: "followers",
key: "farcaster",
input: { username: "feyprotocol" },
},
],
});
console.log(`Total addresses: ${preview.totalAddresses}`);
// Generate merkle root
const merkleRoot = await fey.whitelists.generate({
sources: preview.sources,
customAddresses: ["0xABC...", "0x123..."],
});
// Use in ceremony creation
await fey.ceremonies.create({
// ... other params
whitelistRoot: merkleRoot,
});
// Verify an address
const verification = await fey.whitelists.verify({
ceremonyId: 123,
address: "0xUser...",
});
if (verification.verified) {
console.log("Address is whitelisted with proof:", verification.proof);
}