Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Launch a token with one WhatsApp message and keep the creator fees.
You text Fornum a name, a ticker and a picture. A person reads it, deploys the
token on pump.fun from a Fornum launch wallet, and replies with the mint
address. The creator fees that token earns are recorded against your number,
and you claim them here to any Solana address. You can also hand the fees of a
token to somebody else's number.
There is no bot, no form and no phone calls. The launch is a conversation, the
site is where the money is.
Production build is npm run build, serve it with npm start.README 전문 보기 ↗Launch a token with one WhatsApp message and keep the creator fees.
Live at fornum-exed.vercel.app
You text Fornum a name, a ticker and a picture. A person reads it, deploys the token on pump.fun from a Fornum launch wallet, and replies with the mint address. The creator fees that token earns are recorded against your number, and you claim them here to any Solana address. You can also hand the fees of a token to somebody else's number.
There is no bot, no form and no phone calls. The launch is a conversation, the site is where the money is.
| Layer | Choice |
|---|---|
| Framework | Next.js 16, App Router, RSC, Turbopack |
| Styling | Tailwind CSS v4, tokens declared in CSS |
| Motion | CSS keyframes only, no animation library |
| Fonts | Geist Sans and Geist Mono through next/font |
| Chain | Solana, program in progress |
npm install
npm run dev
Production build is npm run build, serve it with npm start.
/ the number, the thread it runs through, live counters
/launch how to launch, the number and the rules
/tokens everything launched here, fees and who they belong to
/token/[id] one token: fees, claim, hand over, claim history
/payouts claims, every one with a transaction
/signin sign in with a phone number by writing to it, link a wallet
/s/[token] one time sign in link from the chat
/docs how it works, including the money flow
/admin sign ins, launches, fees and the counters shown on the site
/legal/* terms and privacy
Only four are in the navigation: home, launch, tokens, claims. The rest are reached from the footer or from a card.
Every launch, confirmation and payout goes through one WhatsApp thread, so the
number is the largest element on the home page rather than a footnote. It is
+1 (631) 660-1838, and it lives in content/site-config.json under whatsapp.
display is what the site prints, e164 is what wa.me links are built from,
digits only and no plus. Change one and you have to change the other, or the
number on screen stops matching the thread it opens.
Schema is db/schema.sql, run it once against DATABASE_URL. Tables: tokens,
claims and launch requests. Amounts are lamports, stored as bigint.
Without DATABASE_URL the whole app falls back to an in memory store, so every
page renders before anything is provisioned. That store resets on restart,
which is the point: it is not a database. lib/db/store.ts is the only file
that knows which one is in use.
Creator fees accrue to the launch wallet that deployed the mint. pump.fun holds
them until the creator collects, so a claim first sweeps and collects them
into the launch wallet (one transaction built from pump.fun's published IDL,
lib/pump/collect.ts), then sends a plain SOL transfer to the address the
recipient gives us. Fees are never typed in: what a token earned is read off
the chain, pump.fun's creator vaults plus the wallet above its funding line
plus what was claimed (lib/tokens.ts).
POST /api/claim checks the session against the token's recipient hash, reads
the wallet balance on chain, sends the transfer, then writes the claim and moves
the claimed total in one transaction, so the same fees cannot go out twice. The
wallet keeps a small reserve so it can always pay for the next transaction.
POST /api/assign hands the fees of a token to another number. One way on
purpose: the new holder can pass them on again, the sender cannot pull them
back.
POST /api/admin/launch launches a coin from /admin: the picture and the
metadata are pinned to IPFS (PINATA_JWT), the coin is created on pump.fun
through PumpPortal from the first funded, unused launch wallet, and the mint is
recorded by itself. A JSON body with mint still records a coin deployed some
other way.
Every coin launched from /admin is created in one transaction with its fee
split locked by pump.fun's own fee sharing (lib/pump/shares.ts):
create_v2 with the launch wallet as creator, create_fee_sharing_config,
then update_fee_shares_v2 with the launch wallet at 8000 bps and the
treasury at 2000 bps, which also revokes the admin. If any of the three fails
none happens. Before signing, the policy is checked (two distinct valid
addresses, neither the funding wallet, 10 000 bps) and stored in
launch_fee_policies; the transaction is simulated and refused unless the
simulated accounts already show the split; after sending, the split is read
back from the finalized chain (programs, PDA, version 2, admin revoked, the
curve's and, once graduated, the pool's creator pointing at the config, the
two shareholders). Only then is the coin fee_sharing = 'native'; until then
its fees are not paid out.
The three instructions need an address lookup table, which the treasury
creates once from /admin (Fee split) and which is checked before every use:
authority, active, complete, final. npm run launch:dry-run -- <creator> <treasury> <table> simulates a launch against mainnet without sending it.
A native coin is claimed through pump.fun's distribution
(lib/pump/distribute.ts): 80% lands on its launch wallet and goes to the
owner whole, 20% lands on the treasury, and the site does not split it again.
Distributions are permissionless, so the worker reads every finalized one
from each coin's sharing config into the treasury ledger, once per signature,
and sends anything that is not a plain distribution to manual review. Coins
launched before this keep the old path: collected by the site and split 80/20
at each claim.
Fornum's 20% of a claim goes to the treasury (TREASURY_WALLET) in the claim
transaction. A pass of the buyback worker (lib/buyback/) then:
treasury_credits. Anything unusual (another amount, the
treasury paying the fee, a failed transaction) goes to manual review
instead of being guessed. The Fornum token's own fees are left out;BUYBACK_MIN_LAMPORTS, reserves up to
BUYBACK_MAX_LAMPORTS of them for one job, under an advisory lock, with at
most one open job;buy_v3 on the SOL curve, buy in the canonical PumpSwap SOL pool), and
BurnChecked of that same number. It checks the mint (token program, no
freeze authority, no Token-2022 extension beyond metadata) and the market
(SOL quote, no mayhem or cashback, matching creators), then simulates and
refuses unless the market leg fits the budget, the network cost and the
daily network budget fit their limits, the treasury keeps its reserve and
its token balance ends where it started;buyback_jobs before the first send, then
settles the job only on the finalized receipt. An unknown result is
resolved by its signature: sent again while the blockhash is valid, failed
once it has expired, never replaced by a new buy. What was not spent goes
back to the credits.Passes run after each claim, from the button on /admin
(POST /api/admin/buyback) and daily from Vercel Cron (/api/cron/buyback,
CRON_SECRET). BUYBACK_ENABLED=false, the default, stops new jobs and sends
but not reconciliation. npm test covers the rules, and
npm run buyback:dry-run -- <lamports> [mint] [address] builds and simulates
the transaction against mainnet without sending it.
/admin is behind a password. Only its scrypt hash is kept, in
ADMIN_PASSWORD_HASH, made with node scripts/admin-password.mts. The
operator routes take that session cookie, or ADMIN_TOKEN as a bearer token
for scripts.
Every number comes from the database. To show a different figure, pin it in
content/site-config.json or in FORNUM_OVERRIDES on the host. A key left as
null falls back to the computed value.
Token art is optional. When a launch has no image, TokenMark draws one from the
ticker: hue, gradient angle and pattern all come from the symbol, so the same
token looks identical everywhere and no slot is ever empty. Wallet marks are
inline SVG, nothing depends on a remote asset.
Tokens live in app/globals.css in two layers. The raw layer is a named palette
from ivory to jet. The semantic layer holds --background, --card,
--primary, --border, --brand and the rest as bare HSL triples, which is
what makes text-primary/70 and border-primary/[0.06] work.
Dark mode inverts --primary and --accent, so one button class reads white on
black and black on white.
Motion honours prefers-reduced-motion. Components that carry real data, such as
digit reels and progress bars, also write their end state inline, so turning
animation off never shows a wrong number.
Only a salted hash of a phone number goes on chain. The mapping lives off chain and is what the operator reads to answer the thread. Nothing is ever sent to a number that did not write first.
A phone number is the account, and nothing talks to WhatsApp or to an SMS provider to prove it. The number stays in the WhatsApp Business app on the operator's phone, exactly as it is for launches, and the operator is the bridge between the thread and the site. There are two ways in.
A link in the launch reply. When the operator records a launch in
/admin, the site writes the reply for the thread: the mint and a one time
link for the launcher's number. The operator only ever replies to the number
that wrote, so the thread itself proves who will open it. The link lands on
/s/[token], which waits for a button press because WhatsApp fetches every
link to draw a preview. A link works once and for a week. Somebody who writes
asking to sign in gets a fresh one from the same panel.
A code sent from the number. On /signin the visitor types their number
and gets a short code with a wa.me link to the Fornum number. They send it,
it shows up in the chat and in the sign in queue on /admin, and the operator
types the number it came from next to it. The site confirms only if that
number hashes to the one typed on the site, and only the browser that asked
holds the secret, an httpOnly cookie, that turns the confirmation into a
session. The page polls /api/auth/check and moves on by itself. A code
waits a day, and the page picks it up again if the visitor comes back. Five
codes an hour per number, no other limit.
After either, the visitor links a wallet, connected from Phantom, Solflare or
Backpack or pasted, and every claim goes there unless another address is typed
for that claim. Wallets live in accounts, keyed by the number's hash.
Run db/004-whatsapp-sign-in.sql and db/005-sign-in-links.sql once.
lib/auth/verify.ts holds the codes, lib/auth/sign-in-links.ts the links and
lib/replies.ts the text the operator pastes.
The interface is complete and runs on demo data from lib/data.ts. Next up: the
Anchor program with the token account and escrow, wallet signing, and a live
stream of the queue.