Updraft
Elysium testnet

Docs

Field notes for builders

Everything Updraft runs on, in one page: the contracts and their addresses, the SDK, the MCP server, the widget, the public API, and what the system does and doesn’t guarantee.

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.

  1. 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.
  2. 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.
  3. 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.

Fig. 1. Updraft
ContractAddressWhat it does
UpdraftFactory0xA94cdA7c7184C060842569Da8dFC33Ca747Fb232Creates rounds and checks every config against the live launchpad.
UpdraftRound0xFf5d6E05Ed6737C630F48cC633715e537f4b55E8Implementation each round clones: escrow, fire, distribution, refunds.
CreatorVault0xA2BA1bEBFdc7dDa9fbf866aF4a8dAe1207B2F7EDImplementation each launch’s vault clones: holds the creator role, splits fees.
LaunchCertificate0xA85F433603001AA2b85272929157f31F9785cDd1One on-chain record per launch.
UpdraftStaking0x90A39170D14C22711dC7dDbeF1367d58cbFA7E6f$DRAFT staking and the platform basket, paid by epoch.
UpdraftLens0x133a4133937a5CE0120E281623fe56bADCFC2bEACurve previews, capacity and price after a buy.
Attestor0xEb596FD067a24a23df95D634EB926aA058237789Signer of Verified-round vouchers (a key, not a contract).
Distributor0x99BD3d593C73422CB75ab9A0091EDe8fAA9348f9Posts epoch roots (a key, not a contract).
Fig. 2. Ascend, as Updraft uses it
ContractAddressRole
Launchpad0x6d01f6644bbf1b5074472D3e85aa1465B4d2bF3dAscend’s curve launches; the factory only accepts this one.
Launchpad owner0x5Fa637713b819d6314e139291De2Bfa7b7cD70eBChecked at every round creation.
Pool manager0x12E84206cB53aE0df055482ebc4658635096E1aAHolds the pools tokens trade in after T0.
Vault0x2B738A9A69b7a45C9dA6B519f6bE6efBfb912aecAscend’s settlement vault.
USDC0x84Cc00D13173f7016Bbab22A736dBf75A154cFE2Mock testnet dollar, 6 decimals.
mNVDAx0xa7CDbE6342A2eF5f789BCdd3653c7f48c7F16A51Mock 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 build
Fig. 3. Build the SDK.
import { 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",
});
Fig. 4. Create a client.
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);
Fig. 5. Know both addresses before anything is sent.
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);
Fig. 6. Commit.
const state = await updraft.getRound(round);
if (Date.now() / 1000 >= state.config.windows.closeAt) await updraft.fire(round);
Fig. 7. Fire, from T0 until the fire-by time. Anyone can send it.
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);
Fig. 8. Claim what has vested, plus any refund.

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
Fig. 9. Run it over stdio, or over Streamable HTTP.
{
  "mcpServers": {
    "updraft": {
      "command": "updraft-mcp",
      "env": { "UPDRAFT_API": "https://updraft-api-494617981995.us-central1.run.app" }
    }
  }
}
Fig. 10. A client entry for the stdio server.
Fig. 11. Tools
ToolKindReturns
updraft_list_roundsread-onlyEvery round the factory has created.
updraft_get_roundread-onlyOne round’s full state: config, status, totals, the fire preview and, once fired, its token, pool and vault.
updraft_preview_priceread-onlyWhat everyone would pay if a given amount were committed now.
updraft_get_certificateread-onlyThe on-chain launch certificate for a token.
updraft_bottom_of_curveread-onlyThe analysis of every launch on Ascend’s testnet launchpads.
updraft_build_commit_txunsigned txUnsigned approve and commit transactions for an Open round.
updraft_build_create_round_txunsigned txAn 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>
Fig. 12. The embed. data-round is the round’s address.

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.

Fig. 13. Indexer, updraft-indexer-494617981995.us-central1.run.app
GET/rounds?status=live|fired|abortedEvery round, newest first.
GET/rounds/:addressOne round with its participants.
GET/rounds/:address/commitsCommits, withdrawals, refunds and claims.
GET/rounds/:address/swapsTrades on the launched token’s pool.
GET/certificates/:tokenThe launch certificate, decoded.
GET/vaults/:address/flowsFee routing, stakes, claims and policy changes.
GET/wallets/:addressA wallet’s places across rounds.
GET/statsRounds, fired rounds, quote launched, participants.
POST/graphqlGraphQL over the same tables.
Fig. 14. API, updraft-api-494617981995.us-central1.run.app
GET/analysisWho bought the bottom of the curve in every Ascend testnet launch.
GET/rules/v1The rules Verified rounds apply, as JSON.
POST/attest{ round, wallet, hlAccount?, linkSignature? } → a signed voucher, or a refusal with its evidence.
GET/evidence/:hashThe inputs behind one attest decision.
POST/dripTest USDC and gas for a demo wallet. Rate-limited.
GET/epochsEvery posted $DRAFT epoch: window, root, transaction.
GET/epochs/:idOne epoch’s claims and its full Merkle tree.
GET/epochs/claims/:accountEvery 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.

  1. The Hyperliquid account's first ledger activity or fill is at least 30 days old.
  2. It shows real activity: at least 5 fills, or at least 1 HYPE staked, or at least $1,000 lifetime volume.
  3. Its Elysium wallet was not first funded by a private wallet that also funded another wallet already admitted to the same round.
  4. Contracts and public hubs (5,000+ transactions, e.g. the faucet) never link wallets.
  5. 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.