Building Custom Clients
How to build custom frontends, CLIs, bots, and agents on top of Curator Studio
Building Custom Clients
Curator Studio is designed as composable infrastructure. The contracts are permissionless, the indexer exposes a standard GraphQL/REST API, and the SDK works in any JavaScript runtime — not just React apps.
The Stack
┌─────────────────────────────────────────────────────────────────┐
│ CLIENTS │
│ │
│ React apps ──▶ CuratorProvider + hooks │
│ Other web apps ──▶ CuratorSDK class │
│ CLI tools ──▶ CuratorSDK class │
│ AI agents / bots ──▶ CuratorSDK class │
│ Keepers / cron ──▶ CuratorSDK class │
│ Chat bots ──▶ CuratorSDK class │
│ Other protocols ──▶ contracts directly │
├─────────────────────────────────────────────────────────────────┤
│ @curator-studio/sdk │
│ │
│ React layer CuratorProvider, hooks (optional, needs React) │
│ Core layer CuratorSDK class, indexer client (pure TS) │
├─────────────────────────────────────────────────────────────────┤
│ @curator-studio/indexer │
│ │
│ GraphQL /graphql — strategies, distributions, etc. │
│ REST /api/strategies/trending, /api/stats │
├─────────────────────────────────────────────────────────────────┤
│ ON-CHAIN CONTRACTS │
│ │
│ StrategyFactory Deploys strategy clones (per tenant) │
│ Strategy Allocations, distribute, rebalance │
│ SplitsWarehouse ERC-6909 vault, withdraw (shared) │
│ YieldRedirector4626 Wraps ERC-4626, redirects yield │
│ ForeverSubnameRegistrar *.tenant.eth ENS subdomains │
└─────────────────────────────────────────────────────────────────┘What You Need
Install the SDK and provide a tenant name. Contract addresses, ABIs, and RPC are handled automatically.
npm install @curator-studio/sdkimport { CuratorSDK } from "@curator-studio/sdk";
const sdk = new CuratorSDK(walletClient, { tenant: "support.eth" });The indexer is hosted at https://curate-fund-dev.up.railway.app (GraphQL at /graphql, REST at /api/*). Pass it explicitly if you need indexer queries:
const sdk = new CuratorSDK(walletClient, {
tenant: "support.eth",
indexerUrl: "https://curate-fund-dev.up.railway.app",
});SDK Layers
The SDK has two layers — non-React clients are first-class.
Core layer — CuratorSDK class. Pure TypeScript, no framework dependency. Works in Node.js, Deno, Bun, browsers, serverless functions.
React layer — CuratorProvider + hooks. Wraps the core layer with React context and TanStack Query. Optional — only needed for React apps.
Client Types
React App
Wrap your app with CuratorProvider, then use hooks:
import { CuratorProvider, useStrategies } from "@curator-studio/sdk";
function App() {
return (
<CuratorProvider tenant="support.eth" indexerUrl="https://curate-fund-dev.up.railway.app">
<StrategyList />
</CuratorProvider>
);
}
function StrategyList() {
const { data, isPending } = useStrategies({ orderBy: "timesForked", orderDirection: "desc", limit: 10 });
if (isPending) return <div>Loading...</div>;
return data?.items.map((s) => <div key={s.id}>{s.metadata?.title}</div>);
}CLI, Script, or Non-React App
The CuratorSDK class works anywhere — Node.js, Deno, Bun, Vue, Svelte, etc.:
import { CuratorSDK } from "@curator-studio/sdk";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
const wallet = createWalletClient({
account: privateKeyToAccount(process.env.PRIVATE_KEY),
chain: baseSepolia,
transport: http(),
});
const sdk = new CuratorSDK(wallet, {
tenant: "support.eth",
indexerUrl: "https://curate-fund-dev.up.railway.app",
});
const { items } = await sdk.indexer.strategy.query({ limit: 5 });
await sdk.strategy.distribute(items[0].id, tokenAddress);Keeper / Cron Job
A service that periodically distributes or harvests. Since distribute() and harvest() are permissionless, anyone can call them:
for (const strategy of strategies.items) {
const balance = await sdk.strategy.balanceOf(strategy.id, tokenAddress);
if (balance > threshold) {
await sdk.strategy.distribute(strategy.id, tokenAddress);
}
}AI Agent or Bot
The SDK works as a tool for autonomous agents — MCP servers, LangChain tools, Eliza plugins, etc.:
const stats = await sdk.indexer.stats();
const trending = await sdk.indexer.trending({ period: "7d", limit: 5 });
await sdk.strategy.create({
owner: wallet.account.address,
allocations: [
{ recipient: "0x...", weight: 60n, label: "Top project" },
{ recipient: "0x...", weight: 40n, label: "Runner up" },
],
metadataURI: "https://...",
sourceStrategy: "0x0000000000000000000000000000000000000000",
});Direct Integration (No SDK)
Query the indexer GraphQL endpoint directly and call contracts via viem or ethers. Addresses and ABIs are in @curator-studio/contracts/deployments.json.
query {
strategys(where: { tenantId: "support.eth" }, limit: 10) {
items { id, owner, metadataURI, totalWeight }
}
}Permissionless Entry Points
The contracts are designed so that most operations don't require special access. This is what makes keepers, agents, and bots viable.
| Function | Access | Description |
|---|---|---|
strategy.distribute(token) | Anyone | Distribute strategy balance to recipients |
yieldRedirector.harvest() | Anyone | Skim yield surplus and distribute |
| Fund a strategy (transfer tokens) | Anyone | Send ERC-20 or ETH to the strategy address |
warehouse.withdraw(owner, token) | Owner only | Recipient claims their balance |
strategy.rebalance(allocations) | Owner only | Update allocation weights |
strategy.create(config) | Anyone (via factory) | Deploy a new strategy |
Tenant Scoping
Each tenant operates under its own ENS domain with isolated factory contracts but shared underlying infrastructure.
| Layer | Tenant-scoped | Shared |
|---|---|---|
| Contracts | StrategyFactory, SubnameRegistrar | Strategy impl, SplitsWarehouse, ENS infra |
| Indexer | tenantId filter on strategies | Same Ponder instance, same endpoint |
| SDK | tenant option resolves factory + ENS domain | Same CuratorSDK class |
| Frontend | tenant prop on provider | Same codebase serves any tenant |
A custom client just sets a different tenant value and sees only that tenant's strategies, while sharing the same warehouse, indexer, and contract infrastructure.