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
4 changes: 2 additions & 2 deletions app/src/app/rules/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ export default function RulesPage() {
<div className={styles.sectionHeading}><div><p className={styles.eyebrow}><Trophy size={14} aria-hidden="true" />Season points</p><h2 id="points-heading">Points for real buyers.<br />Nothing for noise.</h2></div><Link href="/leaderboard" className={shell.textLink}>See the leaderboard <ArrowRight size={14} aria-hidden="true" /></Link></div>
<p className={styles.riskIntro}>Points measure reputation on openlaunch. They have no cash value, are not a token and not a promise of one, cannot be transferred or sold, and the rules can change between seasons. Wallets that game the system lose their points. Everything is computed from the chain every hour; the rules below are the whole of it.</p>
<div className={styles.questions}>
<details open><summary>What counts as a real buyer?<ChevronDown size={17} aria-hidden="true" /></summary><div><p>A wallet whose first buy of a token was ${RULES.minTradeUsd} or more, made after the launch block, the next {RULES.sniperBlocks} blocks and the first {RULES.sniperMs / 1000} seconds. The wallet must receive the tokens of that buy itself (a relayer or router that only passed them on is not a buyer). Never the launcher, a fee recipient, a wallet that got the token by transfer from either, or a wallet kept off points. A real holder is a real buyer with ${RULES.holderMinUsd} or more (${RULES.verifiedHolderMinUsd} for a qualifying profile, below) of that first buy still in the wallet.</p><p>Holding is judged per buy: whenever tokens leave a wallet (sold, or moved to any other wallet), the most recently received ones go first. So selling a later buy does not touch an earlier one, tokens sent in from another wallet never stand in for a buy, and moving a position out counts the same as selling it. Only tokens priced in a quote we can price count.</p></div></details>
<details open><summary>What counts as a real buyer?<ChevronDown size={17} aria-hidden="true" /></summary><div><p>A wallet whose first buy of a token was worth ${RULES.minTradeUsd} or more when it was made, after the launch block, the next {RULES.sniperBlocks} blocks and the first {RULES.sniperMs / 1000} seconds. The wallet must receive the tokens of that buy itself (a relayer or router that only passed them on is not a buyer). Never the launcher, a fee recipient, a wallet that got ${RULES.linkMinUsd} or more of the token from either before its first buy, or a wallet kept off points. A real holder is a real buyer with ${RULES.holderMinUsd} or more (${RULES.verifiedHolderMinUsd} for a qualifying profile, below) of that first buy still in the wallet, valued at the token&apos;s steady price (the middle of its last trade price now, 12 hours ago and 24 hours ago, so a last-minute pump or dump moves nothing).</p><p>Where a rule needs a number of holders, every holder with a qualifying profile counts, and holders without one count up to twice as many as those (at least {RULES.unverifiedFree}). The same limit applies to what a creator is paid for holders without a qualifying profile.</p><p>Holding is judged per buy: whenever tokens leave a wallet (sold, or moved to any other wallet), the most recently received ones go first. So selling a later buy does not touch an earlier one, tokens sent in from another wallet never stand in for a buy, and moving a position out counts the same as selling it. Only tokens priced in a quote we can price count.</p></div></details>
<details open><summary>How do creators earn?<ChevronDown size={17} aria-hidden="true" /></summary><div><p>On any token you launched, only what happens during the season counts. Each real holder who first bought this season and still holds a day later earns you {RULES.verifiedHolder} points if their profile qualifies (below), or {RULES.holder} if not; a week later, half again. Each holder counts once for you, on whichever of your tokens they are worth most.</p><p>Fees on buys by traders with a qualifying profile earn {RULES.creatorFeePointsPerUsd} points per $1 for each buy that is still at least half held (a buy sold straight back earns nothing), up to {RULES.creatorFeeCapPerTraderDay} from one trader a day. Of the tokens you launch on one day, only your best {RULES.bestTokensPerDay} count. A token scores nothing if you sold or moved tokens out during the season (to any wallet, including one of your own; burning them is fine) and less than half of your own buys of it is left.</p></div></details>
<details open><summary>How do traders earn?<ChevronDown size={17} aria-hidden="true" /></summary><div><p>Be one of the first {RULES.earlyFirstBuyers} real buyers of a token that now has {RULES.earlyHoldersTarget} real holders, with your first buy this season: {RULES.early} points, and {RULES.earlyStillHolding} more while you still hold half of that first buy.</p><p>Every token you first buy this season, with a real first buy, and still half-hold a day later (that buy itself, not a later one; a token you already held before the season does not count): {RULES.hold} points, up to {RULES.holdTokensPerDay} tokens a day. Fees you pay buying other people&apos;s tokens with {RULES.scoutFeeMinHolders}+ real holders ({RULES.scoutFeeMinEligibleHolders}+ of them qualifying), for each buy still at least half held: {RULES.scoutFeePointsPerUsd} points per $1, up to {RULES.scoutFeeCapPerDay} a day. Trades under ${RULES.minTradeUsd} earn nothing.</p></div></details>
<details open><summary>How do traders earn?<ChevronDown size={17} aria-hidden="true" /></summary><div><p>Be one of the first {RULES.earlyFirstBuyers} real buyers of a token that now has {RULES.earlyHoldersTarget} counted holders, with your first buy this season: {RULES.early} points, and {RULES.earlyStillHolding} more while you still hold half of that first buy.</p><p>Every token with {RULES.holdMinHolders}+ counted holders that you first buy this season, with a real first buy, and still half-hold a day later (that buy itself, not a later one; a token you already held before the season does not count): {RULES.hold} points, up to {RULES.holdTokensPerDay} tokens a day. Fees you pay buying other people&apos;s tokens with {RULES.scoutFeeMinHolders}+ counted holders ({RULES.scoutFeeMinEligibleHolders}+ of them qualifying), for each buy still at least half held: {RULES.scoutFeePointsPerUsd} points per $1, up to {RULES.scoutFeeCapPerDay} a day. Trades under ${RULES.minTradeUsd} earn nothing.</p></div></details>
<details open><summary>Who appears on the leaderboard?<ChevronDown size={17} aria-hidden="true" /></summary><div><p>Profiles verified with one post on X from an account at least {RULES.eligibleMinAgeDays} days old with {RULES.eligibleMinFollowers} or more followers. Everyone else can see the points waiting for them on their dashboard; while the season runs, they unlock for the whole season so far with the next points update after the profile qualifies (points update about every hour). The post itself earns nothing.</p></div></details>
</div>
</section>
Expand Down
3 changes: 2 additions & 1 deletion app/src/lib/launchpad/price-source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ test("hero totals: volume in a feed-less stock is left out without the undercoun

test("the points run waits for a missing price only when the quote has a price source", () => {
const points = read("../points/server.ts");
assert.match(points, /if \(q\.usd === null && q\.priced && finalRun && now < end \+ PRICE_WAIT_MS\) return \{ skipped: `no price for \$\{q\.key\} right now; the final standings wait for it` \};/);
// (usdQ: the quote's price in the season's last hour once it has ended, else its price now)
assert.match(points, /if \(usdQ === null && q\.priced && finalRun && now < end \+ PRICE_WAIT_MS\) return \{ skipped: `no price for \$\{q\.key\} right now; the final standings wait for it` \};/);
assert.doesNotMatch(points, /q\.key !== "other"/, "the key alone no longer decides: a feed-less stock has the key 'stock'");
// and that answer is the same one the hero totals use
const queries = read("./queries.ts");
Expand Down
Loading
Loading