Architecture
HWAN is one Anchor program, a keeper that reads public prices, and this website. The program holds every dollar; the keeper and the website hold none.
Components
| Part | Runs where | Holds money | Job |
|---|---|---|---|
kimchi program | Solana | yes, in per-market USDC vaults | offers, positions, reports, disputes, votes, settlement, claims |
| Keeper | any machine | no | reads Upbit, Bithumb and the ECB fix, computes S, calls report |
| Arbiters | 1 to 5 keys per market | no | recompute S from the same public data when a report is disputed |
Website and /api/index | web server | no | shows the live index and the app; read-only |
Accounts
All accounts are program-derived addresses (PDAs).
| Account | Seeds | Contents |
|---|---|---|
| Config | ["config"] | authority, arbiter set and threshold, fee routing |
| Market | ["market", expiry] | expiry, floor, cap, fee_bps, bond, dispute and arbitration windows, oi_cap, open interest, status, report, dispute, votes, settlement |
| Vault | ["vault", market] | USDC token account holding every locked margin, fee and bond of the market |
| Offer | ["offer", market, maker, nonce] | side, price, units left |
| Position | ["position", market, owner] | long units, short units |
USDC is fixed in the program (EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v).
Instructions
The program lives on Solana mainnet at 42pubqJMjRpR6EK3bNZML9MFFVgqS7FXMQURsj7Vg7iK.
| Instruction | Signer | Effect |
|---|---|---|
initialize | upgrade authority | creates Config with the arbiter set |
set_arbiters | authority | replaces the arbiter set for markets opened afterwards |
open_market(args) | authority | opens one weekly series with expiry, floor, cap, fee_bps, bond, dispute_window, arbitration_window, oi_cap |
post_offer | maker | locks margin for one side at one price |
take_offer | taker | locks the opposite margin, both pay the fee, a long and a short come into being |
cancel_offer | maker | returns unfilled margin |
report(value) | anyone, with bond | posts S after expiry |
dispute(value) | anyone, with bond | challenges inside the dispute window with a different value |
vote(value) | arbiter | posts a recomputed S while a dispute is open |
settle | anyone | fixes S once the windows allow it |
claim | anyone, pays the owner | pays long (S − floor) and short (cap − S) per unit to the owner's USDC account |
claim_bond | anyone, pays the owner | returns what the outcome owes the reporter or challenger |
sweep_fees | anyone | moves collected fees to the fixed protocol accounts set at initialize |
set_burn_route | authority | names the token and its Raydium CP-Swap pool for the buyback, once |
buyback_burn | anyone | spends the burn share of swept fees on the token and burns what it buys |
enable_tokens | anyone, pays the mint rent | creates the series' LONG and SHORT position-token mints (Token-2022, name and symbol in the mint) |
mint_pair(units) | owner | locks units × band plus one side's fee, mints units of LONG and of SHORT |
redeem_pair(units) | owner | burns units of each side and pays units × band back, at any time |
redeem(side, units) | owner | after settlement, burns one side and pays long (S − floor) or short (cap − S) per unit; half the band each in a void series |
close_token_mints(expiry) | authority | closes a series' two mints once every token is burned and returns their rent |
close_market | authority | closes an empty market and returns rent (refused while any position token is outstanding) |
Schedules enforced on chain
ExpiryNotOnSchedule: expiry must be 16:00 UTC (Korea), 17:00 UTC (India) or 20:00 UTC (Argentina) on a weekday.BandInvalid: −10000 ≤ floor < cap ≤ 10000 ibp, and cap − floor ≤ 3000 ibp (a band up to 30 pp wide, anywhere within ±100 pp).FeeTooHigh: at most 100 bps.WindowTooShort: dispute window at least one hour, arbitration window at least 24 hours.