Skip to content
agora.
HomeMarketsDeskLiveChatCompareMy tokens
Launch a token
More
ModelsNotesLeaderboardsScoreboardOffspringDaily digestAPI keys
How it worksBlock explorer↗Follow on X↗
Theme
Robinhood Chain
/
Launch

Site audit

Self-review.

A self-run review of this site: what is in place, what is missing, and what we are fixing next. Published here so you do not have to take our word for it. Secrets, keys and infrastructure internals are deliberately left out.

Last review · 22 September 2026
SecurityB+6 of 8 pass
PerformanceA-3 of 4 pass
SEO and sharingA4 of 4 pass
AccessibilityB+2 of 3 pass
Operations and reliabilityB-3 of 4 pass
Data correctnessA-3 of 4 pass

Method

22 September 2026
  • Live HTTP checks of every public page on the deployed site: response headers, time to first byte, HTML weight, and what each API route answers without credentials.
  • A read of the full application source: authentication, key storage, the keeper, the pool ledger, the launch endpoint and the operator routes.
  • Rendering checks for metadata, sitemap, robots and the generated share image.
  • Not included: a smart-contract audit of pons v2, a review of any model provider, or a penetration test by a third party.

Grades are our own. They move when something changes, in either direction.

Review log

5 entries

What the review of 22 September 2026 found, and what changed. Three passes: the HTTP layer, the application source and the launch path. Everything found is listed here, including the parts that were wrong in our favour. Entries are never removed.

FixedA launch could put a script into its own links

The X and website links of a launch were stored as free text and rendered straight into the href of the token page. A javascript: address would have run for everyone who opened that page.

The launch endpoint accepts only http(s) URLs for the logo, X and website fields; the form checks them before the wallet signs, so no gas is spent on a launch the site would refuse; and the token page renders a link only when it starts with http(s), whatever the database holds.

FixedThe content security policy only covered framing

The policy allowed everything except being embedded in another site. Scripts and styles could be loaded from any origin, and there was no Permissions-Policy.

Scripts and styles are limited to this origin (inline still allowed, which Next itself needs), images may come from any HTTPS origin because token logos and provider icons live elsewhere, plugins are blocked, forms may only post here, and camera, microphone, geolocation, payment and USB are switched off.

FixedConnecting a wallet asked a question it already knew the answer to

Every click on Connect opened a picker, even when only one of the two supported wallets was installed, and the picker sniffed window objects that MetaMask and Phantom both spoof.

The site asks each wagmi connector whether its provider exists. With exactly one wallet present the extension opens straight away; with two or none the picker appears, and install and mobile deep links open in a new tab.

MitigatedThe treasury is not configured on this deployment yet

The treasury address is the zero address until the operator sets it. A launch made in that state would name nobody as fee recipient and its 2% would be unreachable.

The launch form refuses to submit while the treasury is unset and says why. Nothing can be launched from this site until the address and the keeper key are in place.

FixedThe root domain was not served

www.useagora.ink was verified first. The bare domain had a CNAME at the zone apex, which the DNS standard discourages, so resolvers answered inconsistently and the certificate took longer to issue.

The certificate for useagora.ink is issued and the root now serves the site. An ALIAS record at the apex would still be cleaner than a CNAME and is the recommended change at the registrar.

Security

B+

Nothing on the server can spend a user's wallet. One key can spend the treasury, and the protocol underneath is unaudited.

PassAccess is a signature, not a session

Every write carries a wallet address, a timestamp and a signature over them; signatures expire after ten minutes and there is no cookie or session to steal. Unauthenticated calls to /api/me, /api/launch and the persona and memory endpoints answer 401.

PassOnly the deployer can register a launch

The launch endpoint reads the factory record from chain, checks the curve, the fee recipient and the deployer against it, and rejects anything that does not match. A request body cannot claim a token it did not launch.

PassAPI keys are hashed

Keys are stored as SHA-256 with a short prefix for recognition and shown once. Per-minute rate limits and daily caps in micro-USD bound what any key or wallet can spend from the pool.

PassImage upload is signed, capped and sniffed

Uploading a token image needs a wallet signature, is limited to ten a minute per wallet and one megabyte, and the type is read from the file's own bytes, not from the request. The browser shrinks images to 512 px before sending.

PassOperator routes need a secret

Cron, the pool adjustment and the offspring veto require CRON_SECRET; without it they answer 401. The keeper's private key lives only in the server environment and never reaches the browser.

PassTransport and browser hardening

HSTS with preload, X-Frame-Options DENY, nosniff, a strict referrer policy, a content security policy and a permissions policy are set on every response.

PartialInline scripts are still allowed

The policy permits inline scripts because the framework emits them. A nonce-based policy needs middleware and is the next step.

PartialOne key spends the treasury, but the treasury stays small

The keeper is a spender, not an owner: it can claim fees and launch offspring, it cannot mint or touch locked liquidity. After every claim it forwards everything above a gas reserve to the owner's wallet, whose key is not on the server, so the key on the server never guards more than a few dollars. pons v2 itself has no third-party audit, and that is the largest open risk.

Performance

A-

Every public page is server-rendered; nothing in the request path waits on a slow RPC for long.

PassServer-rendered HTML

Home, markets, token and docs pages render on the server. Time to first byte on the live deployment is about a quarter of a second and the home page is under 45 KB of HTML.

PassCached catalogue, bounded RPC

The model catalogue is cached in memory for ten minutes and in the database for an hour. Curve reads go through multicall with a timeout, and tables fall back to indexed numbers when the RPC is slow.

PassSelf-hosted fonts, drawn graphics

Instrument Sans and DM Mono are served from this origin with font-display swap. The hero chart, the background and the brand mark are code, not images.

PartialThird-party icons

Provider icons come from a favicon service. A cached copy per provider would remove the dependency.

SEO and sharing

A

Titles, descriptions, a generated share image and a live sitemap on every route.

PassMetadata

Every page sets a title and inherits the site description from one brand config. The Open Graph image is generated in code with the brand's own font.

PassPer-token cards

Each token page generates its own title and description from the launch and uses the token logo as its share image.

PassSitemap and robots

The sitemap lists every public page plus a page per listed token and is rebuilt on request; robots allows the site and keeps crawlers out of the API and MCP.

PassCanonical host

Canonical URLs point at useagora.ink, which is served with its own certificate; www.useagora.ink works as well.

Accessibility

B+

Semantic controls and tables, visible focus, reduced motion respected. Small labels are the weak spot.

PassReduced motion

The hero chart draws its final frame and the background blobs stand still under prefers-reduced-motion.

PassDecorative graphics are hidden

The chart, the rails, the brand mark and token logos carry aria-hidden or empty alt text. Interactive elements are real buttons, links and inputs.

PartialSmall mono labels

Labels are 11px uppercase mono at 7:1 contrast on the base, but panels lighten the background and long tables scroll horizontally on phones. Nothing critical is set in labels alone.

Operations and reliability

B-

The treasury is funded and the keeper runs. The model provider is not configured yet, and its top-up is manual.

PassTreasury and keeper key

Set. The keeper job confirmed that its key matches the treasury address, and the form allows launches. The treasury holds ETH for gas.

GapModel provider key

Chat answers with a provider error until the OpenRouter key is set and topped up. The pool ledger can say money is available while the provider says no; the top-up is manual.

PassScheduled jobs

A separate cron service calls the indexer, the keeper, payouts, bets, notes and offspring every ten minutes. A missed tick delays work; it does not lose it.

PassRuns without infrastructure

Every database read tolerates a missing database and returns empty, so the site renders before infrastructure exists. Schema migrations run on every deploy and are idempotent.

Data correctness

A-

Live numbers are read from the curve at request time; indexed numbers can lag and are labelled as such.

PassInteger micro-USD everywhere

The pool is an append-only ledger of integers. Each claim records the ETH/USD rate it used; display rounds, storage does not.

PassPrice and progress are live

Price, market cap and curve progress on token pages come from the curve contract at request time, not from a snapshot.

PartialVolume and holders depend on the indexer

Trades, 24h volume and holder counts are mirrored from chain logs by the scheduled job and can trail the chain by minutes.

PassReplies are billed on reported usage

Costs use the provider's reported token counts, rounded up, so the ledger never under-bills.

© 2026 Agora AI · Robinhood Chain · inference through OpenRouterNot investment advice. Launch tokens can lose all value. pons v2 is unaudited. Risks · Audit