Six tokens, one pool.Everything about how that works.

What this is

ARCWAR is a launchpad where tokens compete for liquidity instead of each receiving their own. Six tokens enter a four-hour auction together. 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

  1. 01

    Enter the queue

    A creator pays 1 USDC and their token joins the queue. The whole supply is held by the orchestrator, and they can withdraw and take all of it back right up until a battle claims it.

  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.

  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

    Bids fill at one clearing price for everyone. Arriving a block earlier buys nothing, and 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
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. Most 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 0.25% 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 rather than first-come. Everyone who fills, fills at the same price, and the price only moves when demand exceeds the supply being issued. There is no curve to snipe and no advantage to being early in a block.

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 spent either. It stays uncredited and rolls into the next epoch, so trading five dollars an hour for ten hours is paid in the tenth. 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.

Fees

To enter the queue
1 USDC, once, non-refundable
Taken from the raise
Nothing — it all becomes liquidity
Trading fees
0.25% of every trade, swept hourly and split three ways
To claim
Gas only
Buyback
80%
Social contributors
18%
Ctrl88 Lab
2%

The buyback is the share that reaches traders: it is spent buying the protocol’s token and 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.

A creator who switched the creator fee on at launch is paid first, out of their own token’s pool: 0.05% of what that pool’s sweep collected. The three shares above divide what is left.

Nothing is taken out of a raise. The money either becomes liquidity in the winner’s pool or comes back to the people who bid it.

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
59486172
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.

Contracts

BattleOrchestratorproxy · the queue, battles and settlement0x646d1BBC92dfE28Cd890229Fc867C6c820C653eB
BattleMigratorproxy · opens pools, spends the losing raise0x8a7fF7dDa1DD0D01E3938a99213605ceD8Ee489f
PoolVaultholds every position · no exit, not upgradeable0x639cFe26973d286191b7378e0711d91F7b2C512F
ArcSwapRouterbuy and sell against a pool0xB9155c1a527d902be76187923b36a4B1D5c3d763
PoolLensread-only · pool state over eth_call0xC4b6050C14788f517B31d39D303ec7d97976A0a3
BattleTokenimplementation · every launch is a clone0xD319264fccE17C3A28D3C9426D08638FEb6c6953
BidPolicyproxy · currently off0xa41A047cadFF8c996A3cB87a4B3EAAf105A9E06f
RaidToken0xeac4fD6eCa1cA9a1d7Aee7A08CeB55545592d9E8
RaidTreasuryproxy0xe09f70712327Ed8f339FE526f24922aF3a88463a
Continuous Clearing Auction factoryour fork of Uniswap's CCA0x5aAe3a40e7e29Facd4AAb722f4991F8BE303Ed5e
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 0x5aAe3a40e7e29Facd4AAb722f4991F8BE303Ed5e \
  --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 and every fill settles at one clearing price, so a fully subscribed auction has raised = price × 500e6, and the pool it opens is priced at that same clearing price across the whole billion.

Fully diluted value, 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

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 calling it over JSON-RPC returns a revert that looks exactly like a pool with no fees. PoolLens exists for that: it holds nothing, is never sent a transaction, and answers over eth_call.

A token's price and valuation, from its pool
import { createPublicClient, http, parseAbi } from "viem";

const client = createPublicClient({
  transport: http("https://rpc.testnet.arc.io"),
});

const lens = parseAbi([
  "function slot0(address token) view returns (uint160 sqrtPriceX96, int24 tick)",
]);

const [sqrtPriceX96] = await client.readContract({
  address: "0xC4b6050C14788f517B31d39D303ec7d97976A0a3",
  abi: lens,
  functionName: "slot0",
  args: [token],
});

// sqrtPriceX96 is tokens per 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.

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.
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.