Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 33 additions & 15 deletions app/src/app/(home)/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Sk, SkPost, SkRow } from "@/components/Skeleton";
import { LaunchListHeader } from "@/components/launchpad/LaunchRow";

/** Home skeleton: hero + totals, list header, rows, side column. Same grid as page.tsx so nothing shifts. */
/** The readable hero, open market toolbar and support rail follow page.tsx. */
export default function Loading() {
return (
<main className="relative mx-auto max-w-6xl px-4 pb-16 space-y-8" aria-busy="true" aria-label="loading">
<section className="pt-10 sm:pt-14 pb-2 grid lg:grid-cols-[minmax(0,1.1fr)_minmax(0,1fr)] gap-x-8 gap-y-8 xl:gap-x-12 lg:gap-y-0 lg:grid-rows-[min-content_1fr]">
<main className="relative pb-16 space-y-8" aria-busy="true" aria-label="loading">
<section className="mx-auto max-w-6xl px-4 pt-10 sm:pt-14 pb-2 grid lg:grid-cols-[minmax(0,1.1fr)_minmax(0,1fr)] gap-x-8 gap-y-8 xl:gap-x-12 lg:gap-y-0 lg:grid-rows-[min-content_1fr]">
<div className="min-w-0 lg:col-start-1 lg:row-start-1">
<div className="space-y-2">
{[0, 1, 2].map((i) => <Sk key={i} className="h-11 sm:h-14 lg:h-12 xl:h-14 w-11/12" />)}
Expand All @@ -28,27 +29,35 @@ export default function Loading() {
<Sk className="mt-5 h-3 w-44" />
</div>
</section>
<div className="space-y-3"><Sk className="h-4 w-40" /><Sk className="h-16 w-full rounded-xl" /></div>
<div className="workspace-shell space-y-6">
<div className="space-y-2">
<Sk className="h-4 w-40" />
<div className="grid grid-flow-col auto-cols-[minmax(15rem,1fr)] divide-x divide-line overflow-hidden border-y border-line lg:auto-cols-fr">
{[0, 1, 2].map((i) => <div key={i} className="space-y-3 px-4 py-3"><div className="flex items-center gap-2"><Sk className="size-7 shrink-0 rounded-lg" /><Sk className="h-3 w-28" /></div><div className="flex justify-between gap-4"><Sk className="h-4 w-20" /><Sk className="h-3 w-12" /></div><Sk className="h-2.5 w-full" /></div>)}
</div>
</div>
<div className="grid xl:grid-cols-[minmax(0,1fr)_17rem] gap-6 items-start">
<section className="overflow-hidden rounded-2xl border border-line bg-paper">
<div className="flex flex-wrap items-center justify-between gap-3 px-4 pt-5">
<Sk className="h-7 w-32" />
<Sk className="h-11 w-full sm:w-64 rounded-xl" />
<section className="min-w-0">
<div className="flex flex-col items-start justify-between gap-4 border-t border-line pb-5 pt-6 sm:flex-row sm:items-end">
<div className="space-y-2"><Sk className="h-2.5 w-20" /><Sk className="h-7 w-64 max-w-full" /><Sk className="h-3 w-72 max-w-full" /></div>
<Sk className="h-12 w-52 max-w-full rounded-xl" />
</div>
<div className="market-toolbar grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 pb-3 sm:grid-cols-[minmax(0,1fr)_auto_auto]">
<Sk className="col-span-2 h-11 w-full min-w-0 rounded-xl sm:col-span-1" /><Sk className="h-11 w-28 shrink-0 rounded-xl" /><Sk className="h-11 w-24 shrink-0 rounded-xl" />
</div>
<div className="space-y-4 px-4 py-4">
<Sk className="h-10 w-full max-w-md" />
<Sk className="h-11 w-64 max-w-full rounded-xl" />
<Sk className="h-10 w-64 max-w-full" />
<div className="flex min-h-11 flex-wrap items-center justify-between gap-3 pb-3">
<div className="flex gap-2 overflow-hidden">{[0, 1, 2, 3, 4, 5].map((i) => <Sk key={i} className="h-9 w-16 shrink-0 rounded-lg" />)}</div>
<Sk className="h-3 w-36" />
</div>
<LaunchListHeader window="all" />
<ul>
{Array.from({ length: 8 }, (_, i) => (
<SkRow key={i} i={i} ledger />
))}
</ul>
</section>
<aside className="space-y-4">
<div className="rounded-2xl bg-card border border-line shadow-card overflow-hidden">
<aside className="grid min-w-0 gap-6 border-t border-line pt-4 md:grid-cols-2 xl:grid-cols-1 xl:border-t-0 xl:border-l xl:pt-0">
<div className="min-w-0">
<div className="flex min-h-14 items-center justify-between border-b border-line px-4">
<Sk className="h-4 w-14" />
<Sk className="h-3 w-16" />
Expand All @@ -59,7 +68,8 @@ export default function Loading() {
))}
</ul>
</div>
<div className="rounded-2xl bg-card border border-line shadow-card overflow-hidden">
<div className="min-w-0 space-y-6">
<div>
<div className="flex min-h-14 items-center justify-between gap-2 border-b border-line px-4">
<Sk className="h-4 w-20" />
<div className="flex items-center gap-2"><Sk className="h-3 w-14" /><Sk className="h-10 w-10 rounded-lg" /></div>
Expand All @@ -70,8 +80,16 @@ export default function Loading() {
))}
</ul>
</div>
<div className="space-y-4 border-t border-line px-4 pt-6">
<Sk className="h-4 w-24" />
<div className="space-y-2"><Sk className="h-3 w-full" /><Sk className="h-3 w-4/5" /></div>
<div className="space-y-3">{[0, 1].map((i) => <div key={i} className="flex justify-between gap-4"><Sk className="h-3 w-20" /><Sk className="h-3 w-12" /></div>)}</div>
<Sk className="h-3 w-4/5" />
</div>
</div>
</aside>
</div>
</div>
</main>
);
}
19 changes: 11 additions & 8 deletions app/src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Metadata } from "next";
import Link from "next/link";
import LaunchHero from "@/components/launchpad/LaunchHero";
import LaunchList from "@/components/launchpad/LaunchList";
import LaunchBrowser from "@/components/launchpad/LaunchBrowser";
import LaunchTape from "@/components/launchpad/LaunchTape";
import { PostsFeed } from "@/components/launchpad/Posts";
import { listFeed } from "@/lib/launchpad/postsServer";
Expand Down Expand Up @@ -30,29 +31,31 @@ export default async function Home({ searchParams }: { searchParams: Promise<{ s

return (
<>
<main className="relative mx-auto max-w-6xl px-4 pb-16 space-y-8">
<LaunchHero configured={LAUNCHPAD_CONFIGURED} />
<main className="relative pb-16 space-y-8">
<div className="mx-auto max-w-6xl px-4"><LaunchHero configured={LAUNCHPAD_CONFIGURED} /></div>
<div className="workspace-shell space-y-6">
<TrendingStrip initial={trending} />
<div className="grid xl:grid-cols-[minmax(0,1fr)_17rem] gap-6 items-start">
<LaunchList initial={page.items} initialHasMore={page.hasMore} initialSort={sort} initialWindow={window} initialChain={chain} initialFilter={filter} hasDb={dbConfigured()} />
<aside aria-label="Launchpad activity and information" className="grid min-w-0 gap-4 md:grid-cols-2 xl:sticky xl:top-24 xl:grid-cols-1">
<LaunchBrowser><LaunchList initial={page.items} initialHasMore={page.hasMore} initialSort={sort} initialWindow={window} initialChain={chain} initialFilter={filter} hasDb={dbConfigured()} /></LaunchBrowser>
<aside aria-label="Launchpad activity and information" className="grid min-w-0 gap-6 border-t border-line pt-4 md:grid-cols-2 xl:sticky xl:top-24 xl:grid-cols-1 xl:border-t-0 xl:border-l xl:pt-0">
<LaunchTape initial={feed} />
<div className="min-w-0 space-y-4">
<div className="min-w-0 space-y-6">
<PostsFeed initial={posts} compact />
<section aria-labelledby="free-heading" className="rounded-2xl border border-line bg-paper p-4">
<section aria-labelledby="free-heading" className="border-t border-line px-4 pt-6">
<h2 id="free-heading" className="text-sm font-semibold text-ink">Why it&apos;s free</h2>
<p className="mt-2 text-pretty text-xs leading-relaxed text-muted">No fee address in the factory. No platform cut in the locker. On every chain.</p>
<dl className="mt-4 divide-y divide-line border-y border-line text-xs">
<dl className="mt-3 divide-y divide-line text-xs">
<div className="flex items-center justify-between gap-3 py-2.5"><dt className="text-muted">Platform fee</dt><dd className="font-mono font-bold text-up tnum">$0</dd></div>
<div className="flex items-center justify-between gap-3 py-2.5"><dt className="text-muted">Trading fee</dt><dd className="font-mono text-ink tnum">0 / 1 / 3%</dd></div>
</dl>
<p className="mt-3 text-pretty text-[11px] leading-relaxed text-muted">Creators choose the trading fee. It goes in full to their beneficiaries, or is burned.</p>
<a href="https://github.com/Gitlawb/openlaunch/tree/main/contracts/src" target="_blank" rel="noopener noreferrer" className="mt-3 inline-flex min-h-8 items-center text-xs font-medium text-body underline decoration-line-strong underline-offset-4 hover:text-ink">Read the contracts ↗</a>
<div className="mt-3 border-t border-line pt-3"><Link href="/agents" className="inline-flex min-h-8 items-center text-xs font-medium text-brand hover:underline underline-offset-4">Agents can launch too →</Link></div>
<div className="mt-2"><Link href="/agents" className="inline-flex min-h-8 items-center text-xs font-medium text-brand hover:underline underline-offset-4">Agents can launch too →</Link></div>
</section>
</div>
</aside>
</div>
</div>
</main>
</>
);
Expand Down
34 changes: 13 additions & 21 deletions app/src/app/agents/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { Metadata } from "next";
import { pageMetadata } from "@/lib/seo";
import { ArrowDown, ArrowRight, ArrowUpRight, Braces, FileCode2, Terminal } from "lucide-react";
import { ArrowDown, ArrowUpRight, Braces, FileCode2, Terminal } from "lucide-react";
import SectionIntro from "@/components/sections/SectionIntro";
import DocumentationContents from "@/components/sections/DocumentationContents";
import AgentsCodeBlock from "@/components/sections/AgentsCodeBlock";
import { agentExamples } from "@/components/sections/agent-examples";
import shell from "@/components/sections/SectionShell.module.css";
import styles from "@/components/sections/Agents.module.css";
import { launchpad } from "@/lib/launchpad/config";
Expand All @@ -25,16 +27,9 @@ const endpoints = [
] as const;

export default function AgentsPage() {
const factory = launchpad("base").factory ?? "<factory>";
const locker = launchpad("base").locker ?? "<locker>";
const launchExample = `cast send ${factory} \\
"launch((string,string,string,address,uint256,int24,uint24,bytes32,(address,uint16)[]))" \\
"(My Token,MYT,,0x0000000000000000000000000000000000000000,0,184200,10000,0x$(openssl rand -hex 32),[(0xYourWallet,10000)])" \\
--rpc-url https://mainnet.base.org --private-key $PK`;

return (
<main className={`${shell.page} ${styles.page}`}>
<SectionIntro eyebrow="Developer reference" title="Agents" description={<>No API key, no signup, no platform fee. A launch is one contract call from any wallet with a little ETH for gas. Everything the site shows is also JSON.</>}>
<SectionIntro eyebrow="Developer reference" title="Agents" description={<>No API key, no signup, no platform fee. A launch is one contract call from your wallet. Keep ETH for gas on Base and Robinhood Chain, or USDC on Arc. Everything the site shows is also JSON.</>}>
<a href="/llms.txt" className={shell.action}><FileCode2 size={16} aria-hidden="true" />Read llms.txt<ArrowUpRight size={14} aria-hidden="true" /></a>
<a href={BRAND_GITHUB} target="_blank" rel="noreferrer" className={shell.textLink}>Explore the source<ArrowUpRight size={14} aria-hidden="true" /></a>
</SectionIntro>
Expand All @@ -46,10 +41,7 @@ export default function AgentsPage() {

<div className={styles.layout}>
<aside className={styles.sidebar}>
<nav aria-label="Agent documentation sections">
<p className={styles.indexLabel}>On this page</p>
{sections.map(({ id, number, label }) => <a key={id} href={`#${id}`}><span>{number}</span>{label}<ArrowRight size={13} aria-hidden="true" /></a>)}
</nav>
<DocumentationContents sections={sections} aria-label="Agent documentation sections" />
<p className={styles.sidebarNote}>Use the JSON API to read.<br />Use your wallet to write on-chain.</p>
</aside>

Expand All @@ -68,15 +60,15 @@ export default function AgentsPage() {
</div>;
})}
</div>
<p className={styles.prose}>Call <code>launch(params)</code> on that chain&apos;s factory. The example below launches on Base with an ETH quote.</p>
<AgentsCodeBlock title="Launch on Base" language="Shell · cast" code={launchExample} />
<p className={styles.exampleNote}>Example only. Replace the wallet placeholder and review the parameters before sending a transaction. Never share your private key.</p>
<p className={styles.prose}>Call <code>launch(params)</code> on that chain&apos;s factory. Choose a network below to see its address and chain ID. Base and Robinhood examples use ETH; Arc uses ERC-20 USDC with 6 decimals and an opening market cap of approximately 10,000 USDC.</p>
<AgentsCodeBlock title="Launch parameters" language="JSON · parameter reference" examples={agentExamples("launch")} />
<p className={styles.exampleNote}>Example only, not an executable transaction. Replace the placeholders, create a unique salt and simulate the call with your own wallet tooling before signing. Copying does not connect a wallet or send anything. Never share your private key.</p>
<div className={styles.reference}>
<div className={styles.referenceHeading}><Braces size={16} aria-hidden="true" /><h3>Parameters, without the guesswork</h3></div>
<dl className={styles.parameters}>
<div><dt><code>quote</code></dt><dd>ETH uses address zero. For GITLAWB use <code>0x5F980Dcfc4c0fa3911554cf5ab288ed0eb13DBa3</code> on Base or <code>0xd1b0d44E4f6ed940fcC7A9F59Bf30Daf62cCFe3D</code> on Robinhood Chain; for USDG on Robinhood Chain, <code>0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168</code>. For any ERC-20 quote call <code>findSalt(...)</code> first so the token address sorts above the quote.</dd></div>
<div><dt><code>quote</code></dt><dd>ETH uses address zero on Base and Robinhood Chain. Arc requires the ERC-20 USDC address, not address zero; native USDC accounting uses 18 decimals while the ERC-20 quote uses 6. {CHAIN_KEYS.map((chain) => <span key={chain}>{CHAIN_LABELS[chain]} quote addresses: {launchpad(chain).quotes.filter((quote) => quote.key !== "eth").map((quote, index) => <span key={quote.key}>{index > 0 ? "; " : ""}{quote.symbol} <code>{quote.address}</code></span>)}. </span>)}For any ERC-20 quote call <code>findSalt(...)</code> first so the token address sorts above the quote.</dd></div>
<div><dt><code>supply</code></dt><dd><code>0</code> means the default <code>1B</code> supply.</dd></div>
<div><dt><code>startTick</code></dt><dd>Sets the opening market cap. A multiple of <code>200</code>; <code>184200 ≈ 10 ETH</code> FDV for <code>1B</code> supply.</dd></div>
<div><dt><code>startTick</code></dt><dd>Sets the opening market cap. A multiple of <code>200</code>; <code>184200 ≈ 10 ETH</code> FDV for <code>1B</code> supply. The examples derive this value using the chosen quote&apos;s decimals. Do not reuse an ETH tick for Arc&apos;s 6-decimal USDC quote.</dd></div>
<div><dt><code>lpFee</code></dt><dd>In pips: <code>0</code>, <code>10000 = 1%</code>, or <code>30000 = 3%</code>.</dd></div>
<div><dt><code>recipients</code></dt><dd>Empty means fees are burned. Otherwise, shares are in bps and sum to <code>10000</code>.</dd></div>
</dl>
Expand All @@ -98,7 +90,7 @@ export default function AgentsPage() {
<div><code className={styles.endpointPath}>{endpoint.path}</code><p>{endpoint.description}</p>{"query" in endpoint && <code className={styles.query}>{endpoint.query}</code>}</div>
</div>)}
</div>
<AgentsCodeBlock title="Read endpoints" language="HTTP reference" code={`GET ${SITE_URL}/api/launch/list?chain=base|robinhood|arc&sort=live|new|mcap|volume|gainers|holders&window=1h|24h|all&limit=50\nGET ${SITE_URL}/api/launch/feed # latest launches + trades\nGET ${SITE_URL}/api/launch/meta/<token> # image / description / links\nGET ${SITE_URL}/llms.txt`} />
<AgentsCodeBlock title="Read endpoints" language="HTTP reference" examples={agentExamples("read")} />
<div className={styles.dataNote}>
<p>Raw token and quote amounts are decimal integer strings. Use <code>quote_decimals</code> for quote amounts, not a blanket <code>18</code> decimals. <code>price_quote</code> and <code>fdv_quote</code> are numbers in the token&apos;s quote asset; explicit <code>price_usd</code>, <code>fdv_usd</code> and <code>volume_usd</code> fields are USD values and may be <code>null</code> when pricing is unavailable.</p>
<p>Poll modestly and back off on errors. Indexing and server-side caching mean responses are not a guarantee of the latest chain state, even when an HTTP response uses <code>no-store</code>.</p>
Expand All @@ -109,13 +101,13 @@ export default function AgentsPage() {
<div className={styles.sectionHeading}><span className={styles.sectionNumber}>03</span><div><h2 id="agents-trade-title">Trade & collect</h2><p>Standard pools. Direct contract calls.</p></div></div>
<div className={styles.tradeReference}>
<div><span className={styles.tradeLabel}>Swap</span><h3>Speak Uniswap v4</h3><p className={styles.prose}>Pools are plain Uniswap v4, with tick spacing <code>200</code> and no hook. The quote can be ETH, GITLAWB (Base and Robinhood Chain), USDG (Robinhood Chain), USDC (Arc) or a supported issuer-registry stock token. Get the actual pool key with <code>poolKeyOf(token)</code> on the factory. Swap through the Universal Router with a <code>V4_SWAP</code> command, or any router that speaks v4.</p></div>
<div><span className={styles.tradeLabel}>Collect</span><h3>Pay out accrued fees</h3><p className={styles.prose}>Anyone may call <code>collect(tokenId)</code> on that chain&apos;s locker to pay out accrued fees. Base locker: <code>{locker}</code>. Use the matching chain address above.</p></div>
<div><span className={styles.tradeLabel}>Collect</span><h3>Pay out accrued fees</h3><p className={styles.prose}>Anyone may call <code>collect(tokenId)</code> on that chain&apos;s locker to pay out accrued fees. Use the matching chain address above. Simulate the call first; collecting still needs a signed transaction and network gas.</p></div>
</div>
<p className={styles.exampleNote}>Tokenized stocks are third-party securities offered under Regulation S, not to US persons. The site recognizes them from issuer registries, not on-chain names.</p>
<div className={styles.metadata}>
<div className={styles.subheading}><span className={styles.method}>POST</span><h3>Sync your transaction</h3></div>
<p className={styles.prose}>After a transaction you sent, request immediate indexing with this endpoint. Background polling normally runs about every <code>15s</code>; receipt availability and RPC errors can delay indexing.</p>
<AgentsCodeBlock title="Transaction sync endpoint" language="HTTP reference" code={`POST ${SITE_URL}/api/launch/sync?chain=base|robinhood|arc&tx=0x…`} />
<AgentsCodeBlock title="Transaction sync endpoint" language="HTTP reference" examples={agentExamples("sync")} />
</div>
</section>
</div>
Expand Down
Loading
Loading