One round, one buy, one price.
Updraft runs fair launches on Ascend, the launchpad on Elysium (Kinetiq’s Hyperliquid L2). Instead of a race for the bottom of the curve, a launch gathers a round first and buys once.
- Commit. Before launch, anyone puts USDC into the round, up to a cap per wallet (or one place per verified Hyperliquid account in Verified rounds). Commits can be withdrawn until the lock.
- Fire. At T0 one transaction, which anyone may send, turns the whole pot into Ascend’s fee-free launch buy. Everyone, the creator included, pays the same average price.
- Land. Tokens go to every wallet; the creator’s own share vests in public, with a cliff that lasts at least as long as everyone else’s schedule. Any oversubscription is refunded pro-rata.
After launch, Ascend’s creator role sits in a vault that splits creator fees by a published policy: Ascend’s buy-support bid, holders who stake the token in the vault, the team, and the platform. The split moves only inside bounds fixed at launch, after a timelock. Every launch writes an on-chain certificate: participants, concentration, the creator’s vesting and the policy hash.
Why: on Ascend testnet, 251 launches up to block 11,040,000, 49 opened with a dev-buy, and after the biggest ones the next token cost up to 12.8× the dev’s average price. The full analysis.
Addresses on Elysium testnet.
Chain id 99801. Updraft was deployed at block 11,174,917. Every address links to Elysium’s explorer.
| Contract | Address | What it does |
|---|---|---|
| UpdraftFactory | 0xA94cdA7c7184C060842569Da8dFC33Ca747Fb232 | Creates rounds and checks every config against the live launchpad. |
| UpdraftRound | 0xFf5d6E05Ed6737C630F48cC633715e537f4b55E8 | Implementation each round clones: escrow, fire, distribution, refunds. |
| CreatorVault | 0xA2BA1bEBFdc7dDa9fbf866aF4a8dAe1207B2F7ED | Implementation each launch’s vault clones: holds the creator role, splits fees. |
| LaunchCertificate | 0xA85F433603001AA2b85272929157f31F9785cDd1 | One on-chain record per launch. |
| UpdraftStaking | 0x90A39170D14C22711dC7dDbeF1367d58cbFA7E6f | $DRAFT staking and the platform basket, paid by epoch. |
| UpdraftLens | 0x133a4133937a5CE0120E281623fe56bADCFC2bEA | Curve previews, capacity and price after a buy. |
| Attestor | 0xEb596FD067a24a23df95D634EB926aA058237789 | Signer of Verified-round vouchers (a key, not a contract). |
| Distributor | 0x99BD3d593C73422CB75ab9A0091EDe8fAA9348f9 | Posts epoch roots (a key, not a contract). |
| Contract | Address | Role |
|---|---|---|
| Launchpad | 0x6d01f6644bbf1b5074472D3e85aa1465B4d2bF3d | Ascend’s curve launches; the factory only accepts this one. |
| Launchpad owner | 0x5Fa637713b819d6314e139291De2Bfa7b7cD70eB | Checked at every round creation. |
| Pool manager | 0x12E84206cB53aE0df055482ebc4658635096E1aA | Holds the pools tokens trade in after T0. |
| Vault | 0x2B738A9A69b7a45C9dA6B519f6bE6efBfb912aec | Ascend’s settlement vault. |
| USDC | 0x84Cc00D13173f7016Bbab22A736dBf75A154cFE2 | Mock testnet dollar, 6 decimals. |
| mNVDAx | 0xa7CDbE6342A2eF5f789BCdd3653c7f48c7F16A51 | Mock NVIDIA xStock, 18 decimals. |
Quickstart with @updraft/sdk.
A typed client over viem. It reads rounds, previews prices, and sends every write through a simulation first, so a call the contracts would refuse never reaches the wallet. It lives in packages/sdk of the Updraft repository.
pnpm install
pnpm --filter @updraft/sdk buildimport { createPublicClient, createWalletClient, custom, http, parseUnits } from "viem";
import { type Deployment, createUpdraftClient, elysiumTestnet, elysiumTestnetDeployment } from "@updraft/sdk";
const publicClient = createPublicClient({ chain: elysiumTestnet, transport: http() });
const [account] = await window.ethereum.request({ method: "eth_requestAccounts" });
const walletClient = createWalletClient({ account, chain: elysiumTestnet, transport: custom(window.ethereum) });
const updraft = createUpdraftClient({
publicClient,
walletClient,
deployment: elysiumTestnetDeployment as unknown as Deployment,
apiUrl: "https://updraft-api-494617981995.us-central1.run.app",
});import { ascendTestnet, predictToken } from "@updraft/sdk";
import { keccak256, toHex } from "viem";
const roundSalt = keccak256(toHex("starling, take one"));
const tokenSalt = keccak256(toHex("starling token"));
const round = await updraft.predictRound(roundSalt, account);
const token = predictToken({ launchpad: ascendTestnet.launchpad, round, tokenSalt, name: "Starling", symbol: "STRL" });
// cfg is a RoundConfig with the same tokenSalt; the factory re-checks every rule
await updraft.createRound(cfg, roundSalt);const amount = parseUnits("250", 6); // USDC has 6 decimals
// everyone's price if this were added now
const preview = await updraft.previewCommit(round, amount);
// one transaction: signs a permit when the allowance is short
await updraft.commit(round, amount);
// Verified rounds: ask the attestor for a voucher first
const voucher = await updraft.attest({ round, wallet: account });
if (voucher.ok) await updraft.commit(round, amount, voucher);const state = await updraft.getRound(round);
if (Date.now() / 1000 >= state.config.windows.closeAt) await updraft.fire(round);const { tokens, refund } = await updraft.claimable(round, account);
if (tokens > 0n || refund > 0n) await updraft.claim(round);
// anyone can push tokens to a range of participants
await updraft.distribute(round, 0n, 50n);The MCP server.
updraft-mcp exposes Updraft to any MCP client. Read tools query the chain and the API; build tools return unsigned transactions only. It never holds a key and never signs.
pnpm --filter @updraft/mcp build
updraft-mcp # stdio
updraft-mcp --http 8787 # HTTP at http://localhost:8787/mcp
# optional environment
# ELYSIUM_RPC=<rpc url>
# UPDRAFT_API=https://updraft-api-494617981995.us-central1.run.app{
"mcpServers": {
"updraft": {
"command": "updraft-mcp",
"env": { "UPDRAFT_API": "https://updraft-api-494617981995.us-central1.run.app" }
}
}
}| Tool | Kind | Returns |
|---|---|---|
| updraft_list_rounds | read-only | Every round the factory has created. |
| updraft_get_round | read-only | One round’s full state: config, status, totals, the fire preview and, once fired, its token, pool and vault. |
| updraft_preview_price | read-only | What everyone would pay if a given amount were committed now. |
| updraft_get_certificate | read-only | The on-chain launch certificate for a token. |
| updraft_bottom_of_curve | read-only | The analysis of every launch on Ascend’s testnet launchpads. |
| updraft_build_commit_tx | unsigned tx | Unsigned approve and commit transactions for an Open round. |
| updraft_build_create_round_tx | unsigned tx | An unsigned createRound transaction from a JSON round config. |
Every tool that takes a round checks first that the factory created it, so an impostor contract can’t steer an approval to itself.
Embed a round on any page.
One script tag. It is replaced by a frame showing the round live, and the frame grows to fit what it shows.
<script src="https://<app>/updraft-widget.js" data-round="0x…"></script>The frame loads /embed/round/<address> from the same origin as the script. To serve the script from somewhere else, add data-app="https://<app>". The script is under a kilobyte, and it only accepts height messages from its own frame.
Public endpoints.
Both services are open, read-mostly, and return JSON with amounts as decimal strings.
| GET | /rounds?status=live|fired|aborted | Every round, newest first. |
|---|---|---|
| GET | /rounds/:address | One round with its participants. |
| GET | /rounds/:address/commits | Commits, withdrawals, refunds and claims. |
| GET | /rounds/:address/swaps | Trades on the launched token’s pool. |
| GET | /certificates/:token | The launch certificate, decoded. |
| GET | /vaults/:address/flows | Fee routing, stakes, claims and policy changes. |
| GET | /wallets/:address | A wallet’s places across rounds. |
| GET | /stats | Rounds, fired rounds, quote launched, participants. |
| POST | /graphql | GraphQL over the same tables. |
| GET | /analysis | Who bought the bottom of the curve in every Ascend testnet launch. |
|---|---|---|
| GET | /rules/v1 | The rules Verified rounds apply, as JSON. |
| POST | /attest | { round, wallet, hlAccount?, linkSignature? } → a signed voucher, or a refusal with its evidence. |
| GET | /evidence/:hash | The inputs behind one attest decision. |
| POST | /drip | Test USDC and gas for a demo wallet. Rate-limited. |
| GET | /epochs | Every posted $DRAFT epoch: window, root, transaction. |
| GET | /epochs/:id | One epoch’s claims and its full Merkle tree. |
| GET | /epochs/claims/:account | Every allocation to an account, with proofs. |
Rules for Verified rounds.
In a Verified round, each place belongs to one Hyperliquid account. Before a wallet’s first commit, the attestor reads the account’s public history, applies these rules, and signs a voucher for that round and wallet only. The inputs to every decision are hashed and published at /evidence/:hash.
- The Hyperliquid account's first ledger activity or fill is at least 30 days old.
- It shows real activity: at least 5 fills, or at least 1 HYPE staked, or at least $1,000 lifetime volume.
- Its Elysium wallet was not first funded by a private wallet that also funded another wallet already admitted to the same round.
- Contracts and public hubs (5,000+ transactions, e.g. the faucet) never link wallets.
- One verified identity per round; every verified participant gets the same cap.
Fig. 15. Rules v1, live from updraft-api-494617981995.us-central1.run.app/rules/v1.
When a round doesn’t fire.
A round either fires cleanly or gives the money back. There is no half-launch, and no state where funds wait on anyone’s good will.
- Below minimumLess than the minimum raise is in at T0. Anyone can abort, and every commit is refunded.
- Deadline missedNobody fires before the fire-by time, at most 7 days after T0. The round aborts and refunds.
- Ascend changedThe launchpad’s curve for the quote changed since the round was created, Ascend stopped accepting the quote, or the factory revoked the launchpad. Fire aborts instead of buying on terms nobody signed up for.
- Launch failsIf Ascend’s launch call fails, fire reverts and the round stays live, so anyone can send it again. A failed launch never ends a round, so nobody can end one by making it fail; if it never succeeds, the fire-by time refunds everyone.
- Ascend pausedFire waits. It can be sent again once Ascend unpauses, until the fire-by time.
- Escrow shortIf the round holds less than it was given, new commits wait, withdrawals carry their pro-rata share of the loss, and refunds pay out pro-rata of what the round actually holds.
Honest limits.
- Testnet only. Everything here runs on Elysium testnet. There is no mainnet deployment.
- Testnet stables are mocks. Anyone can mint or burn Ascend’s testnet USDC and mNVDAx. The contracts account by the balances they actually hold, never by what they were told, so a burned balance is shared pro-rata instead of stranding someone.
- The attestor is a trusted signer. Verified rounds rely on it for one account, one place. Open rounds don’t use it at all.
- Epoch roots come from our distributor key (0x99BD3d59…). Anyone can recompute each root from the staking contract’s public events and check it against the published tree. Staked principal never depends on the root.
- Identity checks aren’t trustless yet. Elysium’s HyperCore precompile, which would let contracts read Hyperliquid history directly, arrives after mainnet.
- No third-party audit. A self-audit found 15 issues (1 critical, 2 high, 5 medium, 5 low, 2 informational). All 15 are fixed.
- Ascend doesn’t read the certificate. It is written on-chain for anyone to check; Ascend using it is on the roadmap, not live.