Skip to content
Merged
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
5 changes: 4 additions & 1 deletion app/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getLaunchFeed, getLaunchTotals } from "@/lib/launchpad/queries";
import { ethUsd } from "@/lib/launchpad/ethPrice";
import { SITE_URL, explorerAddress } from "@/lib/chainPublic";
import { launchpad } from "@/lib/launchpad/config";
import { BRAND, BRAND_DOMAIN, BRAND_TLD, BRAND_X, SITE_DESCRIPTION, SITE_TITLE, SOCIAL_DESCRIPTION } from "@/lib/brand";
import { BRAND, BRAND_DOMAIN, BRAND_GITHUB, BRAND_TLD, BRAND_X, SITE_DESCRIPTION, SITE_TITLE, SOCIAL_DESCRIPTION } from "@/lib/brand";
import Mark from "@/components/launchpad/Mark";
import RouteProgress from "@/components/RouteProgress";
import { Suspense } from "react";
Expand Down Expand Up @@ -59,6 +59,9 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<a href="/rules" className="hover:text-ink">how it works</a>
<a href="/agents" className="hover:text-ink">agents</a>
<a href="/llms.txt" className="hover:text-ink">llms.txt</a>
<a href={BRAND_GITHUB} target="_blank" rel="noreferrer" className="hover:text-ink">
source · GitHub ↗
</a>
{b.factory ? (
<a href={explorerAddress("base", b.factory)} target="_blank" rel="noreferrer" className="hover:text-ink">
factory · Base ↗
Expand Down
23 changes: 22 additions & 1 deletion app/src/app/llms.txt/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,35 @@ import { BRAND_DOMAIN } from "@/lib/brand";

export const dynamic = "force-dynamic";

/** One "- <chain>: …" line per chain; links only for deployed contracts (factory / locker are nullable until configured). */
function verificationLine(label: string, c: { factory: string | null; locker: string | null }, verifiers: [string, (a: string) => string][]): string {
if (!c.factory && !c.locker) return `- ${label}: (not deployed yet)`;
const parts = verifiers.map(([name, url]) => {
const links = [c.factory ? `${url(c.factory)} (factory)` : null, c.locker ? `${url(c.locker)} (locker)` : null].filter(Boolean).join(", ");
return `${name} ${links}`;
});
return `- ${label}: ${parts.join("; ")}`;
}

export function GET() {
const b = launchpad("base");
const r = launchpad("robinhood");
const body = `# ${BRAND_DOMAIN}

> Open-source (contracts verified on Sourcify; code release pending), zero-fee token launchpad on Base (8453) and Robinhood Chain (4663). One transaction deploys a token and locks 100% of its supply as
> Open-source (MIT — https://github.com/Gitlawb/openlaunch), zero-fee token launchpad on Base (8453) and Robinhood Chain (4663). One transaction deploys a token and locks 100% of its supply as
> Uniswap v4 liquidity, forever. No platform fee: the factory and locker have no fee address at all.

## Source verification
${verificationLine("Base (8453)", b, [
["Basescan", (a) => `https://basescan.org/address/${a}#code`],
["Blockscout", (a) => `https://base.blockscout.com/address/${a}?tab=contract`],
["Sourcify", (a) => `https://repo.sourcify.dev/8453/${a}`],
])}
${verificationLine("Robinhood Chain (4663)", r, [
["Blockscout", (a) => `https://robinhoodchain.blockscout.com/address/${a}?tab=contract`],
["Sourcify", (a) => `https://repo.sourcify.dev/4663/${a}`],
])}

## What a launch does
1. deploys a fixed-supply ERC-20 (1,000,000,000; no mint/pause/blacklist/tax/owner)
2. initializes a Uniswap v4 pool quote/token (quote = ETH, or USDG on Robinhood Chain; tick spacing 200, no hook) at the chosen start tick
Expand Down
30 changes: 29 additions & 1 deletion app/src/app/rules/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Link from "next/link";
import { btn, cardPad } from "@/components/ui";
import { launchpad } from "@/lib/launchpad/config";
import { CHAIN_KEYS, CHAIN_LABELS, explorerAddress } from "@/lib/chainPublic";
import { BRAND_GITHUB } from "@/lib/brand";

export const metadata: Metadata = { title: "How it works", description: "What a launch does on-chain, what it costs (gas), and what can never happen to your liquidity." };

Expand All @@ -20,6 +21,19 @@ const NEVER = [
["No admin", "No owner, no pause, no upgrade, no allowlist. The contracts are the same for everyone, forever."],
] as const;

/** Where each chain's contract source is verified (links go to the explorer's contract record). */
const VERIFIERS: Record<(typeof CHAIN_KEYS)[number], { name: string; url: (addr: string) => string }[]> = {
base: [
{ name: "Basescan", url: (a) => `https://basescan.org/address/${a}#code` },
{ name: "Blockscout", url: (a) => `https://base.blockscout.com/address/${a}?tab=contract` },
{ name: "Sourcify", url: (a) => `https://repo.sourcify.dev/8453/${a}` },
],
robinhood: [
{ name: "Blockscout", url: (a) => `https://robinhoodchain.blockscout.com/address/${a}?tab=contract` },
{ name: "Sourcify", url: (a) => `https://repo.sourcify.dev/4663/${a}` },
],
};

export default function RulesPage() {
return (
<main className="mx-auto max-w-3xl px-4 py-10 space-y-10">
Expand Down Expand Up @@ -108,10 +122,24 @@ export default function RulesPage() {
<span className="font-mono">not deployed yet</span>
)}
</p>
{c.factory && c.locker ? (
<p className="text-xs text-muted">
Source verified:{" "}
{VERIFIERS[k].map((v, i) => (
<span key={v.name}>
{i > 0 ? " · " : ""}
{v.name} (<a href={v.url(c.factory!)} target="_blank" rel="noreferrer" className="underline underline-offset-2">factory</a>,{" "}
<a href={v.url(c.locker!)} target="_blank" rel="noreferrer" className="underline underline-offset-2">locker</a>)
</span>
))}
</p>
) : null}
</div>
);
})}
<p>Identical bytecode on both chains. Uniswap v4&apos;s PoolManager, PositionManager, Permit2 and Universal Router are Uniswap&apos;s canonical deployments. MIT-licensed source, verified on Sourcify.</p>
<p>Identical bytecode on both chains. Uniswap v4&apos;s PoolManager, PositionManager, Permit2 and Universal Router are Uniswap&apos;s canonical deployments. MIT-licensed source on{" "}
<a href={BRAND_GITHUB} target="_blank" rel="noreferrer" className="text-ink underline underline-offset-2">GitHub ↗</a>; the verification records for each chain are linked above.
</p>
</div>
</section>

Expand Down
6 changes: 5 additions & 1 deletion app/src/components/launchpad/LaunchHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { btn, pill } from "@/components/ui";
import LiveTotals from "./LiveTotals";
import { launchpad } from "@/lib/launchpad/config";
import { explorerAddress } from "@/lib/chainPublic";
import { BRAND_GITHUB } from "@/lib/brand";

export default function LaunchHero({ configured }: { ethUsd?: number | null; configured: boolean }) {
const b = launchpad("base");
Expand All @@ -11,8 +12,11 @@ export default function LaunchHero({ configured }: { ethUsd?: number | null; con
<section className="relative pt-8 sm:pt-12 pb-2">
<div className="flex flex-wrap items-center gap-2">
<span className={`${pill} text-up border-up/20 bg-up-soft`}>0% platform fee</span>
<a href={BRAND_GITHUB} target="_blank" rel="noreferrer" className={`${pill} hover:text-ink hover:border-line-strong`}>
open source · GitHub ↗
</a>
<a href="/rules#contracts" className={`${pill} hover:text-ink hover:border-line-strong`}>
open source · verified contracts
verified contracts
</a>
<span className={pill}>Base + Robinhood Chain · Uniswap v4</span>
<span className={pill}>liquidity locked forever</span>
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/brand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const BRAND_TLD = ".lol";
export const BRAND_DOMAIN = `${BRAND}${BRAND_TLD}`; // openlaunch.lol
/** @openlaunchlol and the openlaunchlol GitHub org were squatted after the rename — never link them. */
export const BRAND_X = "gitlawb";
export const BRAND_GITHUB = "https://github.com/Gitlawb";
export const BRAND_GITHUB = "https://github.com/Gitlawb/openlaunch"; // MIT, contracts + site
export const TAGLINE = "launch a token. Free. Open source. On Base or Robinhood Chain.";
/**
* Per-surface copy (each surface truncates at a different point):
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/launchpad/creator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ test("share card shaping", () => {
const now = Date.parse("2026-09-06T12:00:00Z");
const c = shapeCard({ name: "Dollar Dog", symbol: "DDOG", chain: "robinhood", fdv_usd: 12345, fdv_quote: 12345, quote_symbol: "USDG", change_from_launch: 0.234, lp_fee: 10000, recipients: [{ payout: DEAD, bps: 10000 }], block_time: "2026-09-06T09:30:00Z" }, now);
assert.deepEqual(c, { title: "Dollar Dog", symbol: "DDOG", chainLabel: "Robinhood Chain", mcap: "$12.3K", change: "+23%", up: true, fee: "1% fee, burned", age: "2h old", quote: null });
assert.deepEqual(shapeCard({ name: "Base Stock Test", symbol: "BSTK", chain: "base", fdv_usd: 25206, fdv_quote: 109.6, quote_symbol: "NVDAc", change_from_launch: 0, lp_fee: 10000, recipients: [{ payout: "0x63f300b7b21fba52a8d874d90f7e1b301ae858c4", bps: 10000 }], block_time: "2026-09-06T09:30:00Z" }, now).quote, { symbol: "NVDAc", ticker: "NVDA" }, "stock quotes get a ticker tile on the card");
assert.deepEqual(shapeCard({ name: "Base Stock Test", symbol: "BSTK", chain: "base", fdv_usd: 25206, fdv_quote: 109.6, quote_symbol: "NVDAc", change_from_launch: 0, lp_fee: 10000, recipients: [{ payout: "0x00000000000000000000000000000000000c0ffe", bps: 10000 }], block_time: "2026-09-06T09:30:00Z" }, now).quote, { symbol: "NVDAc", ticker: "NVDA" }, "stock quotes get a ticker tile on the card");
assert.equal(feeLabel(0, []), "0% fee");
assert.equal(feeLabel(30000, [{ payout: "0x1", bps: 10000 }]), "3% fee → beneficiary");
assert.equal(ageLabel("2026-09-06T11:59:30Z", now), "1m old");
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/launchpad/holders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DEAD_ADDR, ZERO_ADDR, applyTransfer, creatorActivity, fmtShare, holderT

const PM = "0x498581fF718922c3f8e6A244956aF099B2652b2b";
const LOCKER = "0xcd1680D26922fcd9CabFbb8a56bA40C333fD842a";
const DEV = "0x63f300b7b21fba52a8d874d90f7e1b301ae858c4";
const DEV = "0x00000000000000000000000000000000000c0ffe";
const A = "0x" + "a".repeat(40);
const B = "0x" + "b".repeat(40);
const SUPPLY = 10n ** 27n;
Expand Down
4 changes: 2 additions & 2 deletions app/src/lib/launchpad/metaShared.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { test } from "node:test";
import assert from "node:assert/strict";
import { metaUriFor, metaWriteDecision, validateMeta } from "./metaShared.ts";

const L = "0x63F300b7b21FbA52A8D874D90F7E1B301AE858c4";
const L = "0x00000000000000000000000000000000000c0ffe";
const SALT = "0x" + "a".repeat(64);
const KEY = "0x" + "B".repeat(64);
const base = { chain: "base" as const, launcher: L, salt: SALT, name: "Clear Sky", symbol: "sky" };
Expand All @@ -22,7 +22,7 @@ test("validateMeta: meta_key is optional (defaults to the salt) and normalized t

test("metaUriFor is keyed by (launcher, meta_key) and is stable while the salt changes", () => {
const u1 = metaUriFor(L, KEY);
assert.match(u1, /\/api\/launch\/meta\/0x63f300b7b21fba52a8d874d90f7e1b301ae858c4\/0xbbbb/);
assert.match(u1, /\/api\/launch\/meta\/0x00000000000000000000000000000000000c0ffe\/0xbbbb/);
assert.equal(metaUriFor(L.toLowerCase(), KEY.toLowerCase()), u1, "case-insensitive");
assert.notEqual(metaUriFor(L, SALT), u1, "a different key → different URI");
});
Expand Down
Loading