ARCWARDocsOpen app
Documentation

Tokens fight for one pool.How that works, and how to build on it.

Chain
Arc testnet · 5042002
To enter
1 USDC
Target, per battle
5,000 USDC
Window
27,923 blocks · 4 h
Pool fee
1% · 20% to the creator, the rest to the treasury
Parameters read from the chain 24 Oct 2026 00:32 UTC

What this is

ARCWAR is a launchpad where tokens compete for liquidity instead of each receiving their own. Up to six tokens enter a four-hour auction together — a battle opens with as few as two. The one that raises the most opens a Uniswap v4 pool. The money raised behind the others is not refunded and not burned — it is spent buying the winner in that pool, and the winner’s token is what their backers claim.

That single rule is what the rest of this document explains. It is also the only thing about ARCWAR that is unusual; everything else is an ordinary auction and an ordinary Uniswap pool.

How a battle runs

Queue1 USDC · supply heldOpenone window, all entrantsBidone clearing priceResolvebiggest raise winsFinalisepool opens · losers buy inClaimwinner's token to all
Six moves, all of them permissionless after the first. The tank is the raise; the pad is the queue; the launch is the pool.
  1. 01

    Enter the queue

    A creator pays 1 USDC and their token joins the queue. The whole supply is held by the orchestrator until a battle claims it. There is no way back out: an entry is a commitment to the next battle, so nobody can hold the queue's clock by registering and leaving.

  2. 02

    The queue fills, then holds

    Once enough tokens are waiting, a thirty-minute countdown starts — and every new entrant pushes it out again. Nobody can open a battle out from under a creator who is still telling people about it. A full cohort of six skips the wait and opens at once.

  3. 03

    Open

    Every entrant’s auction is deployed in the same transaction, so they share one window and no entrant gets a head start. The window is 27,923 blocks — four hours at Arc’s block rate.

  4. 04

    Bid

    The auction releases its supply over the window and fills bids block by block at that block’s clearing price, which only ever rises. Money that arrives early buys cheaper; thirty percent of the supply clears in the final block, so the closing price stays close to what the money paid rather than a multiple of it. A bid the clearing price passes is refunded rather than filled at a price its owner did not agree to.

  5. 05

    Resolve

    After the window closes anyone can settle it — the keeper is expected to, but the function is permissionless so a battle cannot be stranded by one wallet going quiet. The biggest raise wins.

  6. 06

    Finalise and claim

    A second transaction opens the winner’s pool and spends the losing side’s raise buying into it. Backers then claim: the winner’s own backers claim the token they bid on, everyone else claims their share of what their money bought.

Launching a token

A launch needs a name, a ticker, a picture and one dollar. There is no allocation to negotiate and no vesting schedule to sign: the supply is fixed at a billion, half of it is auctioned, and the half that does not sell becomes the pool’s liquidity if the token wins.

Entry fee
1 USDC, non-refundable
Total supply
1,000,000,000, fixed at mint
Auctioned
500,000,000 — half
Target to graduate
5,000 USDC raised by the battle, not by each token
Window
Four hours, shared with every other entrant
Picture
Up to 12,000 bytes, stored on chain
Description
Up to 500 bytes
The entry fee does not come back

Not even when the battle falls short. A fee you get back is not a deterrent, and the queue is the one place spam costs other creators something.

A creator may also skip the auction entirely and launch instantly, which is a different thing in almost every respect and has its own section below.

Launching instantly

The queue exists so six tokens can be drawn against each other. A creator who does not want the contest can leave it: launchInstant opens the pool in the same transaction, and the token never enters a battle. About a third of the tokens on this chain arrived this way.

What goes into the pool is the whole supply, not half. A battle sells 500,000,000 through its auction and puts the unsold half into the winner’s pool; an instant launch has nothing to sell, so all 1,000,000,000 become liquidity at once.

Cost
The same $1 queue fee, and nothing else
Into the pool
1,000,000,000
Opening price
$0.000001
Opening valuation
$1,000
Currency in the pool at open
$0
The first buyer is the first person to put money in

The pool opens holding token and no currency at all, which is possible because the liquidity sits in a range strictly below the opening price — a range below the price holds only the token side. Nobody has bought anything yet, so there is nothing for the pool to hold but what the creator supplied. Every dollar in it afterwards arrives through a trade.

Nothing here can be refunded, because nothing was staked

A battle can end with money going back: bids the clearing price passed, and every bid in a battle whose entrants fell short between them. An instant launch takes no bids. There is no raise to return and no target to miss — the only money that changed hands is the dollar to enter the queue, and that is spent whichever route the creator takes.

The pool is the same pool a battle winner gets, on the same terms: liquidity nobody can withdraw, a 1% fee on every trade, and that fee swept each hour into AW for the accounts whose trading produced it. What an instant launch does not get is the evidence. A token that won a battle has shown that people put real money behind it against five alternatives; a token that launched instantly has shown that somebody paid a dollar. Both open with permanent liquidity, and only one of them has been argued for.

Backing a token

A bid names an amount and a ceiling: the most it is willing to pay per token. It fills at the clearing price, not at the ceiling, so bidding above the market costs nothing extra — the ceiling only decides at what point the bid stops buying.

The auction is continuous: supply is issued over the window on a schedule that starts slow and rises, with thirty percent held for the final block, and every block clears at one price for everyone bidding in it. The price only rises, so earlier money fills cheaper and the last block — the largest — settles close to the average. The pool opens at that closing price.

A bid the price passes is refunded, not filled

If the clearing price rises above your ceiling, your bid stops buying and the unspent remainder comes back. You are never filled at a price you did not agree to.

When a token loses

This is the part that differs from every other launchpad, so it is worth being precise about.

A token that was funded but lost does not refund its backers. Its raise is spent buying the winner’s token in the pool that has just opened, and that token is what its backers claim. They came for one launch and leave holding the one that worked. The ratio is fixed at settlement; what moves afterwards is the price when they sell.

A token that raised almost nothing is not a separate case, and this is the part that changed. The target belongs to the battle: what the entrants raise between them is what is measured, and the ruling that comes back is the same for all of them. So a token that pulled in forty dollars inside a battle that cleared five thousand is funded, and its backers hold tokens rather than a refund — carried by the rest of the field.

Refunds happen when the battle falls short, not when a token does. Then nobody graduates, including whichever token raised the most.

What a losing side's money buyswinnerTokens = swap(loserRaise) into the winner's pool

When nothing clears

If no token in a battle reaches the target, there is no winner and no pool. The battle is recorded as abandoned, every entrant’s supply goes back to its creator, and every bid is refunded in full by the auction itself.

Nothing is paid out until the battle has ruled

An auction in a battle cannot answer for itself, because the figure it would have to check is not one it can see. So it is told at the moment it opens to wait, and from then until resolveBattle runs it refuses every exit and every claim. Bids and reserve supply sit where they are.

There is no deadline that releases them, deliberately: a fallback would be a second rule for settling a battle, and the point of the first one is that it is the only one. resolveBattle takes no permission and no key — anyone at all can call it once the window closes, and that is what ends the wait.

Why the pool stays

The winner’s pool position is owned by PoolVault, and that contract has no function that reduces liquidity. Not a locked one, not a time-delayed one — the code to withdraw does not exist. The only modifyLiquidity call in it passes a delta of zero, which is how Uniswap v4 says “settle my fees and change nothing”.

It is also the one contract in the system that is not upgradeable. The orchestrator and the migrator sit behind proxies so their settlement logic can be fixed; the positions were moved somewhere a change of code cannot reach, or “the liquidity is permanent” would have quietly meant “until whoever holds the upgrade key decides otherwise”.

AW and epochs

Trading fees collected from every pool on the platform fund an epoch. Your share of that epoch is your share of the volume you drove during it.

An epoch pays accounts that traded at least $50 in it

Below that, the hour pays nothing, and the volume is not carried: each epoch judges itself from nothing, so five dollars an hour for ten hours is paid in none of them. Fifty dollars in the hour, or nothing. The floor exists because an allocation worth a fraction of a cent costs more gas to claim than it is worth, and every one of them is a leaf in the tree the page has to serve.

There is no premine, no allocation and no reserve. The entire supply was minted to the treasury and put into a pool; the only way AW reaches anyone is the treasury buying it back out with fees that were actually collected. It is the protocol’s own token and it does not compete for a pool with anyone.

Not everything a buy-back returns is handed out. 9% of it is burned in the same transaction as the buy, sent to the dead address before any root could name it; the rest is what the epoch divides. The burn is why a crowd that claims and sells everything it is given still leaves the price somewhere above where it found it: what they sell back is less than what the treasury took out. It is a setting on the treasury, capped at half, and the figure here is what it holds now.

Fees

To enter the queue
1 USDC, once, non-refundable
Taken from the raise
1% of what a battle raised, once, at settlement
Trading fees
1% of every trade, swept hourly
To claim
Gas only

The battle cut is charged on the whole raise — the winner’s and the losing side’s together — and goes to the treasury in USDC. It is a real cost to the losing bidders: the buy-back that funds their claim is 1% smaller than their raise. A battle that falls short is refunded in full; the cut is only ever taken from money that graduated.

The raisewinner’s and losers’, at settlementEvery trade1% pool fee, swept hourly99%Winner’s poolliquidity nobody can withdraw1% cutTreasuryUSDC, before any buy80% buybackAW · 9% burned, the rest to traders18% social contributorsUSDC, into its vault2% Ctrl88 LabUSDC, into its vault
A creator who switched the creator fee on takes 20% of whatever the protocol took for their token, before the split.
Buyback
80%
Social contributors
18%
Ctrl88 Lab
2%
Of each buy, burned
9%

Everything the treasury collects — the battle cuts and the hourly sweeps — is divided the same way. The buyback is the share that reaches traders: it is spent buying the protocol’s token, 9% of what comes back is burned, and the rest is handed to the accounts whose trading produced the fees. The other two are paid in USDC rather than in the token, which is deliberate: a recipient paid in the asset whose supply it helps decide has an interest nobody can audit away. Each is paid into a vault of its own — a contract that holds it and whose admin may move it — so what has been paid is a balance anyone can read. The split is a setting on the treasury, capped at 25% for the two paid shares together, and the figures above are what it holds now.

A creator who switched the creator fee on at launch is owed 20% of every sum the protocol takes for their token: of the battle cut, in USDC, and of each sweep of their pool — in USDC and in the token, in whatever mix the trades paid. Of the 1% a trade pays, that is 0.2% to the creator and 0.8% to the treasury; a creator who left the fee off sends the whole 1% to the treasury. The share is not sent: it is set aside in the migrator, and the creator collects it from their portfolio whenever they choose — claimCreatorFees sweeps the pool on the way, so one transaction pays everything owed, the hour’s takings included. The treasury’s share leaves on every sweep as before.

The whitelist

Before Arc mainnet opens, a spot on the ARCWAR whitelist is claimed at quest.arcwar.gg: four tasks on X — follow, like, repost, reply — and one wallet to receive it. Spots are recorded in the order they arrive, and the list closes the moment mainnet opens, on 16 September.

Every spot comes with a sealed pack of five traits — background, TV, face, outfit and an effect — drawn by the server the moment the spot is taken. The pack rolls its rarity first (Common 69%, Rare 25%, Epic 5%, Legendary 1%), one of the four ranked traits carries it, and the other three roll at or under it (the backgrounds have no Epic tier, so an Epic never lands there); the effect is a flourish and carries none. The pack opens on the page; the NFT it shows is minted to that wallet once mainnet is live, with exactly the traits shown.

Protocol

What is deployed, and how to read it.

Addresses, the auction we forked, and the calls an integrator needs.

Network

Chain
Arc testnet
Chain ID
5042002
Native currency
USDC — gas is paid in it
Block time
~0.516s
RPC
https://rpc.testnet.arc.io
First indexed block
59976263
The public RPC allows two concurrent eth_getLogs

Enough to read state, not enough to index. Circle hosts keyless vendor endpoints on the same domain that do not have that limit — rpc.blockdaemon.testnet.arc.io and rpc.drpc.testnet.arc.io. Blockdaemon’s is pruned roughly 400,000 blocks behind head, so a deep backfill still needs Circle’s.

None of them answer a browser. Every public Arc endpoint sits behind bot protection that returns 503 to a page’s own fetch, though curl and scripts pass. A web front-end has to proxy its RPC calls through its own origin, which is what this app does.

Contracts

BattleOrchestratorproxythe queue, battles and settlement0x41ee78fDdb32EEe0Eb3ad91101Fc7046f9B5E1C2
BattleMigratorproxyopens pools, spends the losing raise0xAf32a500500f360E2e9c4C79Eb06FB6fB709e6a2
PoolVaultnot upgradeableholds every position · no exit0xeEe6A960C77Ab4E541F3Ac94Add3Fc146EcfCE41
PoolGatehook · proxyonly the migrator opens a pool · announces every swap0x47d99d5955CF40CDe89A9085Dc98f5a416fCBff0
ArcSwapRouterbuy and sell against a pool0xE9B344F4F06f4Df660AD21d399E12dD6E9bE4376
PoolLensread-onlypool state over eth_call0xea73e9e0cE0e509154c778aB298247c591817AcD
BattleTokenimplementationevery launch is a clone0x991bc392F65745f9deb75A8B32D6D126772F6868
BidPolicyproxycurrently off0xD616c83E70637a9333607974f6a4F9bB494ed045
RaidToken (AW)tokenthe protocol's own; a billion, all in the treasury's 1% pool0x3a1e5C9c5ACBFaAAA56b09dE1c0b93DDD1D1A46B
RaidTreasuryproxysweeps fees, buys the token, burns 9%, publishes the epoch0xC87d6b25E6a67Ac50e0f9A7D3DBA928b3665505d
ShareVault · socialproxyholds the 18%0x6Fb7cA9762e8531471e94d053a0a7BdEcDc2Ac7f
ShareVault · Ctrl88 Labproxyholds the 2%0xa45dB27a7429b1132db04929E15e8F60bDC42770
Continuous Clearing Auction factoryforkour fork of Uniswap's CCA0x12d2eFc32F13389c23E952cB26C75413a19Ca3f7
Uniswap v4 PoolManagerUniswap’s0x5e4b627b99BC77a29c874ba1ccAe65af5d8D1B19

The auction

The auction layer is Uniswap’s Continuous Clearing Auction, vendored and forked. We neither fork nor deploy a DEX — the pool is Uniswap’s v4, at the address above, passed to the migrator as a constructor argument.

The fork adds one thing: exitPartiallyFilledAndClaimBatch, which settles every bid a caller holds in one auction and pays out in a single transfer. Without it a position of three bids was six transactions. You can check which factory you are talking to without opening a battle:

Confirming the deployed factory is the fork
cast code 0x12d2eFc32F13389c23E952cB26C75413a19Ca3f7 \
  --rpc-url https://rpc.testnet.arc.io | grep -c ffe12763
# 1 — exitPartiallyFilledAndClaimBatch is present

cast code 0xe0648174b6c0860C5e8CFB263C3A0B54D28Fe9FD \
  --rpc-url https://rpc.testnet.arc.io | grep -c ffe12763
# 0 — Uniswap's own factory has no such function

Valuation

A token’s valuation is not a model — it falls out of the auction’s own arithmetic. Half the supply is auctioned; the pool opens at the closing clearing price, and because thirty percent of the supply clears in the final block that price stays close to the average paid — measured on Arc, about one and a half times it, where a flat schedule had produced ten — so a fully subscribed auction has roughly raised ≈ price × 500e6 and the pool is priced at that closing price across the whole billion. The other half of the supply pairs with the raise as full-range liquidity. Whatever the auction did not sell, and whatever the opening price could not pair, is burned — nothing is held back.

Fully diluted value at open, above the floorfdv ≈ raised × 2
Below full subscription at the floorfdv = 1,000 USDC
Floor price
0.000001 USDC per token
Floor FDV
1,000 USDC
Full subscription at the floor
500 USDC raised
A token that raises 5,000 alone
10,000 USDC FDV at open
Ceiling price
the auction's own maximum; the app bids at it, so a bid fills at whatever the clearing price becomes
Supply schedule
twelve rising steps over the window, then 30% of the auctioned supply in the final block
Unsold supply
burned at finalisation, together with the losers' supply

After the pool opens, the losing side’s raise buys into it, which moves the price up before anyone has traded. The figures above are the opening valuation, not the settled one.

Reading state

Pool state is not readable through ordinary getters. StateLibrary computes storage slots and reads them through extsload, so there is no getSlot0 to call over JSON-RPC. The chain is still the door: the slot arithmetic is short, and PoolLens — a stateless contract that runs the same arithmetic the pool manager does — reports what a position is owed, the read a keeper needs before deciding what is worth sweeping.

A pool's price, straight from the PoolManager's storage
import { createPublicClient, http, encodeAbiParameters, keccak256, hexToBigInt } from "viem";

const pm = "0x5e4b627b99BC77a29c874ba1ccAe65af5d8D1B19"; // Uniswap v4 PoolManager
const client = createPublicClient({ transport: http("https://rpc.testnet.arc.io") });

// The key the migrator opened the pool with — ask it rather than assume.
const key = await client.readContract({ address: MIGRATOR, abi: migratorAbi, functionName: "poolKeyFor", args: [token] });
const poolId = keccak256(encodeAbiParameters(
  [{ type: "address" }, { type: "address" }, { type: "uint24" }, { type: "int24" }, { type: "address" }],
  [key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks]));

// StateLibrary: pools live in slot 6; slot0 is the first word of the pool's struct.
const slot = keccak256(encodeAbiParameters([{ type: "bytes32" }, { type: "uint256" }], [poolId, 6n]));
const word = await client.readContract({ address: pm, abi: [{ name: "extsload", type: "function", stateMutability: "view", inputs: [{ type: "bytes32" }], outputs: [{ type: "bytes32" }] }], functionName: "extsload", args: [slot] });
const sqrtPriceX96 = hexToBigInt(word) & ((1n << 160n) - 1n);

// sqrtPriceX96 is tokens per unit of currency, so it runs backwards to value.
const r = Number(sqrtPriceX96) / 2 ** 96;
const price = 1 / (r * r);          // USDC per token
const fdv = price * 1_000_000_000;  // supply is fixed at a billion
sqrtPriceX96 is inverted here

It encodes tokens per unit of currency, so squaring it gives you the reciprocal of the price. Sorting tokens on the raw value ranks them backwards — cheapest first — and the mistake looks plausible enough to survive review.

There is no public API

The site is served by an indexer that derives every figure from logs, and that indexer answers the site alone: it is sized for one application, not for whoever finds the URL, and every read of it from outside would be a read the app could not make. What the app shows is the reading; what the chain holds is the record, and the two examples above are how to take it yourself.

Events to index

TokenRegistered
A creator entered the queue. Carries name, symbol, image.
BattleOpened
Auctions deployed. Carries the entrant list and the window.
ClearingPriceUpdated
The live valuation moved. Emitted by each auction.
EntrantSettled
Per token: what it raised, and the battle's verdict — the same for every entrant.
BattleResolved
The winner, its raise, and the losing side's total.
BattleFinalized
The pool is open and the losing raise has been spent. Claims start here.
BattleCutTaken
The 1% taken from the raise, and the creator's slice of it.
EntryWithdrawn
A queued token went back to its creator — withdrawn, or evicted once stale.
BattleAbandoned
The battle raised less than the target between them. Everything is refunded.
InstantLaunched
A pool opened without an auction.
Swap
A trade through a pool. Uniswap's, on the PoolManager.
Derive from events, never from historical eth_call

A pruned node answers eth_call at an old block with an error that reads like an empty result. Anything an indexer needs should come out of a log.

Errors

BidMustBeAboveClearingPrice
The ceiling named is at or below where the auction has already settled.
CannotExitBid
This bid set the clearing price. It leaves through exitPartiallyFilledBid.
BidNotExited
claimTokens was called before the bid was settled.
NotGraduated
The battle fell short, so there is nothing to claim — only to refund.
VerdictPending
The battle has not been resolved yet. Nothing settles until it is; anyone can call resolveBattle once the window closes.
AlreadyExited
This bid has already been settled.
NothingToClaim
Settled, and the payout was zero.
BattleStillRunning
The window has not closed yet.
BattleNotResolved
finalizeBattle was called before resolveBattle.
NotEnoughEntrants
The queue is too short to open a battle.
CountdownRunning
The queue's hold has not expired.
WrongCreationFee
The value sent is not the current creation fee.
ImageTooLarge
The picture is over 12,000 bytes.
DescriptionTooLong
The description is over 500 bytes.