Marketing site and analytics dashboard for Yearn’s partner program. The landing page highlights fees and vault counts, the Team Up form pings a Telegram bot, and partner dashboards (e.g. /dashboard/0x...treasury) display balances and payouts pulled via the local API routes.
- Live site: https://partners.yearn.fi
- Tech: Next.js 15 + TypeScript, TailwindCSS, SWR, Yearn Web Lib components
- Token/chain icons: loaded from
https://token-assets-one.vercel.app(seelib/crypto/tokenLogos.tsandnext.config.js)
- Copy environment defaults:
cp .env.example .env - Install dependencies (pnpm recommended because the lockfile is present):
pnpm install - Run the dev server:
pnpm devthen open http://localhost:3000 - Use address 0x93A62dA5a14C80f265DAbC077fCEE437B1a0Efde for login testing
Other scripts:
pnpm lint– run ESLintpnpm build– type-check and build for productionpnpm start– start the built apppnpm export– generate a static export (if needed)
- Public metadata is set in
pages/_app.tsx(site name, description, theme color, OG image). Update those values to rebrand the site. - Runtime environment variables live in
.env:YVISION_BASE_URI– legacy (currently unused; historical Yearn Vision base)ENVIO_GRAPHQL_URL– required Envio GraphQL endpoint used by/api/partner-feesKONG_GRAPHQL_URL– optional Kong GraphQL endpoint for vault metadata (defaults to https://kong.yearn.fi/api/gql)RPC_URL_MAINNET_PUBLIC,RPC_URL_MAINNET_PRIVATE– preferred public/latest and private/archive RPCsRPC_URL_BASE_PUBLIC,RPC_URL_BASE_PRIVATE– preferred public/latest and private/archive RPCsRPC_URL_ARBITRUM_PUBLIC,RPC_URL_ARBITRUM_PRIVATE– preferred public/latest and private/archive RPCsRPC_URL_POLYGON_PUBLIC,RPC_URL_POLYGON_PRIVATE– preferred public/latest and private/archive RPCsRPC_URL_MAINNET,RPC_URL_BASE,RPC_URL_ARBITRUM,RPC_URL_POLYGON– legacy fallback RPCs if the split envs are unsetNEXTAUTH_SECRET– secret for NextAuth usageCOINGECKO_API_KEY– optional API key for Coingecko price lookups (used to convert non-USD vault values to USD)TELEGRAM_BOT,TELEGRAM_RECIPIENT_USERID– required bypages/api/telegram.tsto deliver Team Up form submissionsIP_TO_BLOCK– optional comma-separated IPs to deny from the contact form
Partner metadata (name, treasury address, logo) is defined in utils/Partners.tsx. The login modal expects a treasury address that maps to an entry in PARTNERS; successful login routes to /dashboard/[partnerID] where vault balances and payouts are fetched via:
/api/partner-tvl/api/partner-fees(with/without snapshots)
These endpoints aggregate over the vault + depositor configuration in PARTNER_VAULT_CONFIG and return normalized totals, asset metadata, and per-account breakdowns.
To add a new partner to the dashboard, edit utils/Partners.tsx and add entries to two objects:
const PARTNERS: TDict<TPartner> = {
sturdy: { ... }, // existing partner
// Add your new partner here
yourpartner: {
name: 'Your Partner Name', // Display name
shortName: 'yourpartner', // URL-safe identifier (lowercase, no spaces)
treasury: [toAddress('0xYourPartnerTreasuryAddress')], // Partner's treasury address(es)
logo: <LogoYourPartner className={'text-900'} /> // Partner logo component
}
};The treasury address will be used for authentication and URL routing (e.g., /dashboard/0xYourPartnerTreasuryAddress).
Note: SHAREABLE_ADDRESSES is auto-generated from PARTNERS, so you don't need to add anything there.
const PARTNER_VAULT_CONFIG: TPartnerVaultConfig = {
sturdy: { ... }, // existing partner
// Add your new partner's vault configuration
yourpartner: {
1: { // Chain ID (1 = Ethereum mainnet, 8453 = Base, 137 = Polygon, etc.)
[toAddress('0xVaultAddress1')]: [ // Yearn V3 vault address
// List of depositor addresses to track for this vault
toAddress('0xDepositorAddress1'),
toAddress('0xDepositorAddress2'),
toAddress('0xDepositorAddress3')
],
// Add more vaults on the same chain
[toAddress('0xVaultAddress2')]: [
toAddress('0xDepositorAddress4'),
toAddress('0xDepositorAddress5')
]
},
// Add vaults on other chains
8453: { // Base chain
[toAddress('0xBaseVaultAddress')]: [
toAddress('0xDepositorAddress6')
]
}
}
};The dashboard will automatically:
- Query balances and fees for all depositor addresses across all vaults and chains
- Aggregate total TVL and fees across all chains and vaults
- Display the combined metrics on the partner's dashboard
Create a logo component in components/icons/partners/ following the existing pattern:
// components/icons/partners/LogoYourPartner.tsx
import type {ReactElement} from 'react';
export default function LogoYourPartner({className, isColored}: {className?: string, isColored?: boolean}): ReactElement {
return (
<svg className={className} viewBox="0 0 100 100">
{/* Your SVG logo here */}
</svg>
);
}Then import it in utils/Partners.tsx:
import LogoYourPartner from 'components/icons/partners/LogoYourPartner';And add it to the LOGOS object (keyed by shortName):
const LOGOS: TPartnerLogo = {
yourpartner: <LogoYourPartner className={'text-900 h-3/4 w-3/4'} />
};// 1. Add to PARTNERS
const PARTNERS: TDict<TPartner> = {
acme: {
name: 'Acme Protocol',
shortName: 'acme',
treasury: [toAddress('0x1234567890123456789012345678901234567890')],
logo: <LogoAcme className={'text-900'} />
}
};
// 2. Add to PARTNER_VAULT_CONFIG
const PARTNER_VAULT_CONFIG: TPartnerVaultConfig = {
acme: {
1: { // Ethereum mainnet
[toAddress('0xBe53A109B494E5c9f97b9Cd39Fe969BE68BF6204')]: [ // USDC vault
toAddress('0xAcmeDepositor1'),
toAddress('0xAcmeDepositor2')
]
}
}
};After adding your partner, rebuild the app with pnpm build and the new dashboard will be available at:
/dashboard/0x1234567890123456789012345678901234567890(using treasury address)- Or via the login modal using the treasury address
- Yearn Vision-driven chart aggregation is currently disabled; the large historical chart fetch block in
components/dashboard/DashboardTabsWrapper.tsxis commented out. usePartnercurrently returns an emptyvaultsobject (legacy Yearn Vision data path disabled), so per-vault tabs and charts are not populated from that source.- The dashboard currently relies on the local
/api/partner-tvland/api/partner-feesroutes for totals; these endpoints are the supported path while the legacy flow is commented out.
