尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Daily parimutuel pools on where a US stock closes, staked and paid in the tokenized stock itself (xStocks, Backpack, Ondo).
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
SharePot — bet with your stock tokens, get paid in them
Daily parimutuel pools on US stocks where the stake and the payout are the tokenized stock itself — any issuer's
token on Solana: xStocks (SPCXx, TSLAx, NVDAx, SPYx), Backpack Securities (SPCX) and Ondo Global Markets (SPCXon,
TSLAon, NVDAon, SPYon). Holders put their shares to work without selling them:查看完整 README ↗Daily parimutuel pools on US stocks where the stake and the payout are the tokenized stock itself — any issuer's token on Solana: xStocks (SPCXx, TSLAx, NVDAx, SPYx), Backpack Securities (SPCX) and Ondo Global Markets (SPCXon, TSLAon, NVDAon, SPYon). Holders put their shares to work without selling them:
Built for the Solana Foundation Stocklana hackathon (September 2026).
Try it (devnet): https://devnet.sharepot.xyz — connect Phantom / Solflare / Backpack set to devnet, or use the built-in browser test wallet, then press "Get test tokens": every wallet gets mock tokens of every pool open today plus a little SOL for fees. A new stock pool opens for every token at each US opening bell; a pre-IPO or meme day's pool opens at 11:00 UTC the day before.
Updates: @sharepotxyz on X · contact: [email protected]
nyseYearByRule, tested against NYSE's published lists for 2022 and 2024–2027), so nothing is added by hand each year.The same stock often trades on Solana as several tokens: SpaceX as SPCXx (xStocks), SPCX (Backpack Securities) and SPCXon (Ondo Global Markets); Tesla as TSLAx and TSLAon. The tokens are not interchangeable (different issuers, decimals and dividend multipliers), so each token gets its own pool. All pools of a stock ask the same question and resolve on the same official close; each is staked and paid in its own token.
ScaledUiAmount multiplier that the issuer applies to every
balance, vaults included. The program books raw units, so every stake, pool and payout moves by the same ratio and
keeps its share of the pot; the site shows amounts with the multiplier applied, exactly as wallets do.seed_market exists for a deliberate promotion, switched on with
SEED_MARKETS=1). If nobody picked the winning
range, everyone is refunded; a voided market refunds everyone in full.forfeit_position; the program checks both the delay and the account), so a market can always be closed. The site
asks for stakes of about $1 or more for the same reason.SharePot is parimutuel, so there is no house on the other side of your bet — the players are each other's counterparty. Three consequences worth stating plainly, because "who pays me if I win?" is the first question anyone asks:
compute_payout in programs/sharepot/src/lib.rs). The worst case is a wasted
session, not a loss.Every settled market scores the wallets that were in it:
points = shares staked × the official close the market settled on
That is what the stake was worth, in dollars, at settlement. Every range you bet counts, won or lost: one share on
each of the four ranges of a $212 close is 848 points, and only one of them can pay. The close is the one in the
evidence file the result was derived from, so NVDAx and NVDAon score alike and no token quote is involved. It is
frozen into the settlement record at payout time (server/resolve.mjs); server/points.mjs only adds up what the
crank wrote. The board is at /leaderboard.html, backed by GET /api/leaderboard?window=7d|30d|all.
Anyone who has placed a bet gets a link (/?ref=CODE, code derived from the wallet address). A wallet that arrives
through it and places its first bet is bound to that code — the wallet signs the binding, so nobody can claim
someone else's wallet, and the file is keyed by address, so the binding holds on devnet and mainnet alike.
Fees are charged on winnings only, in the pool's token. When a bound wallet's winning bet settles, the referrer earns
20 % of that fee (25 % from 10 000 all-time points, 30 % from 100 000) and the invitee gets 10 % of it back, both in
the same token. deploy/referral-payout-remote.sh pays the balance out once a week straight from the treasury (rebates are a
share of collected fees, so it always holds enough), from the machine that keeps the treasury key, never the app host;
before a settlement row earns anyone a rebate the payer finds its transaction on-chain and requires this program's
PositionSettled event for the same market, owner and fee (server/settlement-proof.mjs), so the app host's files
cannot invent fees; one run never sends more than $2,000 without a human; a wallet that does not hold the token yet
gets its account opened once the rebate reaches $10.
data/referral-payouts.jsonl is the ledger, data/referrals.json the bindings, and everything else is recomputed from
settlements.jsonl so nothing is counted twice. Rules and maths: server/referrals.mjs (tests in
referrals.test.mjs).
PRICE_SOURCE=alpaca switches to Alpaca SIP daily bars — both agree to the cent), computes the close-to-close
move and proposes it together with the sha256 of the raw price response. The winning range is derived
on-chain from the market's thresholds.
Before it proposes, the number has to pass three checks, and a failed check holds the market for the next run
instead of posting a wrong result: the bar before the target must be the calendar's previous session (a dropped bar
would silently shift "previous close" back a day); the target bar must be final (the source's last regular trade
at or after the closing bell, so an intraday price is never mistaken for the close); and the close must match
Nasdaq's official close to the cent — an independent second source with no key. Closes that differ but leave
the day in the same range settle on the primary, with the difference written into the evidence; closes that put
the day in different ranges are never proposed, and if 24 h of retries do not reconcile them the market refunds
itself. If Nasdaq has nothing for the
day yet the resolver waits up to two hours after the bell, then proceeds on the primary alone and says so in the
published evidence. Fetches retry on network errors; whatever still fails is retried by cron every ten minutes.server/verify-proposals.mjs
runs every ten minutes on a different host that holds the admin key, fetches the closes itself (for on-chain closes:
from its own per-minute samples), and voids a proposal whose range it cannot reproduce — a full refund, never a
different winner. A proposal it still cannot check 45 minutes before the window closes (no price source
answered) is voided too: nothing settles on a value nobody re-derived (server/verify-policy.mjs). For an on-chain close, a disagreement within 0.5 % of a threshold only pages the operator (two samplers never see the same quotes). Disputes are recorded off-chain and
have no on-chain effect by themselves.void_stale_market; the
program checks the delay) and the crank refunds every stake. That is the only power the proposer has beyond
proposing a number: it can return money, never pick a winner.We do not settle on Pyth: since 2026-08-26 Hermes requires an API key for both latest and historical prices, and its equity feed reports the last trade before 16:00, not the official closing print these markets are defined on.
xStocks are Token-2022 mints with several extensions. The program and the tests take each of them into account:
transfer_checked through the token interface; classic SPL mints work
through the same path.place_bet and seed_market record the vault's balance change, not the amount sent,
so mints with a transfer fee (Tessera, PreStocks) run pools that never exceed their vault. Only an active transfer
hook is refused at create_market. xStocks, Ondo Global Markets and Backpack Securities tokens carry neither; the
program itself is issuer-agnostic.ScaledUiAmount multiplier change scales every pool,
stake and payout alike (tested mid-market).The same product runs on a second chain: Robinhood Chain, an Ethereum L2 (chain
id 4663; testnet 46630), staked in Robinhood's own Stock Tokens — on the testnet TSLA, AMZN, PLTR, NFLX and AMD, the
ones the issuer's faucet hands out. evm/src/SharePot.sol is a port of the program with the
same money model, instruction for instruction; the pages are one code base built twice (VITE_CHAIN=evm), and a
switch in the top bar links the two sites. Pools are separate per chain — a TSLA pool on Solana and one on Robinhood
Chain are two pots — but both settle on the same official close, read by the same resolver code
(server/evm/resolve.mjs imports the price module the Solana resolver uses), so one day's
TSLA never has two answers. Addresses live in server/evm/chains.json.
What the EVM changes, and what it does not:
held counter, never
read from the contract's balance, so two markets in the same token cannot see each other's funds and tokens sent
straight to the contract belong to nobody's pool. Bets and seeds are still booked at what actually arrived.forfeitPosition (30 days after resolution; the admin at once) first tries to pay the owner and only when
that transfer fails — the issuer has blocked the address — pays the treasury. A paused token fails both transfers,
so a pause never forfeits anyone.server/evm/index-events.mjs) that the crank and the "My bets" page read.The contract has the program's functions under the same names (createMarket, seedMarket, placeBet,
proposeResolution, finalizeResolution, voidMarket, voidStaleMarket, settlePosition, forfeitPosition,
sweepMarket, updateConfig) and the same hard limits (fee ≤ 10 %, 2–8 ranges, 24 h stale void, 30-day forfeit
grace). Seventeen Foundry tests cover the same scenarios as the Solana suite plus the shared vault, blocked owners and
a token that returns nothing (cd evm && forge test).
Two more token classes run on the same program. There is no exchange for them, so a day's close is read on-chain:
server/select-chain.mjs runs at 11:00 UTC and picks the ten Solana tokens with the most 24-hour traded
volume (Jupiter's top-traded list) for the next day, subject to filters: mint and freeze authority given up, liquidity
≥ $500k, first pool ≥ 3 days old, no wrapped/bridged assets, no tokenized stocks, DeFi or "strict"-list tokens.
They are recorded in data/chain-tokens.json; on devnet the opener mints a mock per token and stocks the faucet.server/sample-prices.mjs into data/ticks/<date>.jsonl. Metric tag <SYMBOL>.day:<date>; the move is that day's
close against the previous day's, both read from the samples at resolution and published together as evidence.
Fewer than 40 usable quotes on either day voids the market (full refund). Jupiter is the one settlement source —
the same feed the site shows as "now" and "prev close". Every sample also records a second quote (DexScreener),
published with the evidence for comparison only: two venues trade at different prices, so it never decides or
holds a market.place_bet and seed_market
book what the vault actually received (balance before/after the transfer), so the pools never exceed the vault and a
payout simply lands net of the issuer's fee. Before a fee-mint vault is closed the crank harvests the withheld fees to
the mint (HarvestWithheldTokensToMint, permissionless); Token-2022 refuses to close an account holding any.programs/sharepot Anchor program (Rust): per-stock parimutuel pools, Token-2022, on-chain range derivation
tests/ 15 tests against a local validator with mock xStocks carrying the real TSLAx extension set
server/ market opener (NYSE calendar), resolver + settlement crank, API + devnet faucet + static site
web/ market pages, Wallet Standard betting (Phantom, Solflare, Backpack), "My bets"
scripts/ devnet bootstrap (mock xStocks, faucet, config), replay markets for demos, admin tools
idl/ program IDL + TypeScript types
examples/ automate.mjs: list open pools, bet, read results from a script
The site speaks English, 繁體中文, 简体中文, 日本語, 한국어 and Español. The server picks one per request — a ?lang=
link, then the picker's cookie, then the browser's Accept-Language — and sends the page already in that language
(static text, the pre-rendered market cards, dates in the viewer's locale), so nothing flashes in English first. The
page's scripts get the same dictionary from a cacheable /i18n/<lang>.js. Dictionaries are plain JSON in
web/src/i18n/; server/i18n.test.mjs fails if a language misses a key, a {slot} or a tag, or if a page's English
drifts from en.json. Adding a language is two JSON files and one row in LANGS.
| Instruction | Who | What |
|---|---|---|
initialize / update_config | admin | proposer, treasury owner, fee (≤ 10 % hard cap), early-bird, dispute window, min bet, pause |
create_market | admin or proposer | stock mint, metric tag, question hash, thresholds + range count, open/close/resolve times; creates the vault |
seed_market | anyone | add a fee-free prize in the market's stock |
place_bet | anyone | range index + amount of the stock; fee rate locked into the position |
propose_resolution | proposer or admin | observed move + evidence hash; range derived on-chain; starts the dispute window |
finalize_resolution | anyone after the window, admin any time | locks the outcome |
void_market | admin | refund everyone |
void_stale_market | proposer or admin | refund everyone in a market still unproposed 24 h after its resolve time |
settle_position | anyone | pay one position in the stock, close it, refund its rent to the payer |
forfeit_position | anyone after 30 days, admin any time | only if the owner's token account is gone, frozen or set to require memos: the payout goes to the treasury, the position closes |
sweep_market | anyone | after all positions are settled: fees + dust to the treasury's account for that stock, close the vault and the market account; their rent goes back to the proposer that paid it |
Program id: 8TzdVXpqa52o3fBvYynSxHTWP4zuWfZmTvSkpdLT9rWW. The EVM contract (evm/src/SharePot.sol)
has the same functions under the same names; its addresses are in server/evm/chains.json.
A bot needs three things: which pools are open, a way to bet, and the results. The first and the third are the public read API (no key, open CORS); the second is the program, signed by the bot's own wallet. There is no server-side bet endpoint, so nobody can bet with your tokens but you.
| Endpoint | What |
|---|---|
GET /api/markets, GET /api/markets/<id> | every market / one market. status: 0 open, 1 proposed, 2 resolved, 3 voided, 4 settled and swept. A bet is accepted while status is 0 and now is between openTs and closeTs (unix seconds) |
GET /api/config | fee, early-bird discount, dispute window, minimum bet (base units) |
GET /api/stocks, GET /api/prices | the tokens with mints and decimals; the live prices the site shows |
GET /api/evidence/<id>, …/raw | the settlement evidence; /raw is the exact bytes whose sha256 is on-chain |
GET /api/positions/<wallet> | every payout the crank pushed to a wallet, with its signature |
GET /api/leaderboard?window=7d|30d|all | the points board |
POST /api/faucet {"address"} | devnet only: mock shares of every open pool plus a little SOL, once a day per wallet |
Units: thresholds and the observed move proposedValue are in ppm (1 % = 10 000); range 0 is below the first
threshold, the last range at or above the last one, outcome is the winning range. pools and bet amounts are in base
units (shares × 10^decimals). Betting is the program's place_bet(range, amount) instruction (IDL in idl/);
payouts are pushed to the wallet after the dispute window, nothing to claim. Market data is cached for 15 s; the
faucet, disputes and feedback are limited per address and per day.
examples/automate.mjs does all of it in 80 lines (Node 22, cd server && npm ci once):
node examples/automate.mjs markets # open pools: id, ranges, closes in, pool sizes
node examples/automate.mjs bet 153 1 0.5 # 0.5 shares on range 1 of market #153, signed by KEYPAIR
node examples/automate.mjs results <wallet> # settled markets, and what that wallet was paid
anchor build
./scripts/test-local.sh # fresh validator + the 15 tests
# a local cluster with mock xStocks, a faucet and today's markets
solana-test-validator --reset --bpf-program 8TzdVXpqa52o3fBvYynSxHTWP4zuWfZmTvSkpdLT9rWW target/deploy/sharepot.so &
export ANCHOR_PROVIDER_URL=http://127.0.0.1:8899 ANCHOR_WALLET=~/.config/solana/id.json
SHAREPOT_SECRETS=./.local npx ts-node scripts/devnet-setup.ts
CLUSTER=localnet STATE=./.local/state.json node server/open-markets.mjs
(cd server && npm i) && (cd web && npm i && VITE_CLUSTER=localnet npm run build)
CLUSTER=localnet SHAREPOT_SECRETS=./.local CLUSTER_RPC=http://127.0.0.1:8899 node server/api.mjs # site + API on :5041
# watch a full cycle in minutes: a market on a past session, resolved from its real official close
SYMBOL=TSLA SESSION=2026-09-11 BET_SECS=120 CLUSTER=localnet STATE=./.local/state.json node scripts/quick-market.mjs
CLUSTER=localnet SHAREPOT_SECRETS=./.local ADMIN_FINALIZE=1 ADMIN_KEYPAIR=$ANCHOR_WALLET node server/resolve.mjs
The EVM side, on a local chain (Foundry: forge, anvil, cast):
cd evm && forge test # the 17 contract tests
anvil & # a local chain; account 0 = admin
PROPOSER=<addr> TREASURY=<addr> MOCK_STOCKS="TSLA AMZN" forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --private-key <key> --broadcast
# put the printed addresses into a chains.json entry ("local": rpc, pot, deployBlock 0, stocks with thresholdsBps), then
cd ../server && EVM_CHAIN=local EVM_CHAINS=./chains.local.json EVM_PROPOSER_KEY_FILE=<file> node evm/open-markets.mjs
EVM_CHAIN=local EVM_CHAINS=./chains.local.json EVM_PROPOSER_KEY_FILE=<file> node evm/resolve.mjs
(cd ../web && VITE_CHAIN=evm VITE_OUT_DIR=dist-evm-local VITE_EVM_POT=<pot> VITE_EVM_RPC=http://127.0.0.1:8545 VITE_EVM_CHAIN_ID=31337 npx vite build)
EVM_CHAIN=local EVM_CHAINS=./chains.local.json STATIC_DIR=../web/dist-evm-local PORT=5042 node evm/api.mjs # site + API on :5042
8TzdVXpqa52o3fBvYynSxHTWP4zuWfZmTvSkpdLT9rWW, config
3tS4yRS8HrrSnNi4or5UGbfAyFpFrXTJAF3BNMivF5Uh; nine mock stock tokens copying each issuer's mainnet extension set
and decimals; markets open and settle on a schedule (deploy/crontab.txt), payouts are pushed automatically.server/evm/chains.json has the contract
address; deploy/crontab-evm.txt the schedule), reachable from the chain switch in the top bar.MIT