Chapter 08 · Builder and stacks

Builder and stacks

Designing a block stack off-chain, share links, storage and the hand-off to Launch.

The Builder is a canvas for designing a block configuration before launching. It never writes to the chain. A design is a "stack": a name plus a BlockConfig. Stacks live in the browser's local storage and in share links, and the Launch flow picks one up as its step 2.

What a stack is

type Stack = { name: string; cfg: BlockConfig };

BlockConfig is the same shape the contract takes (mask, bps, blocks, seconds, raw quote units). The Builder edits it in UI units (percent, blocks, hours, whole USDC or cirBTC) through a set of parameter specs and snaps every value to the slider's step and the contract's hard range. Storage stays in contract units so the same validate() and normalize() from the Launch flow apply. The one quote-dependent field, potMinBuy, is shown in the quote chosen in Launch step 1 and stored raw (6 decimals for USDC, 8 for cirBTC).

Stack hand-offA stack is a named BlockConfig. It never touches the chain until Launch normalises it into launchWithBlocks.
saveopen in LaunchloadStackBuilder canvaspalette · chassisStack { name, cfg }BlockConfig unitsencodeStack → base64url{ n, m, w, b, t, bu, p, pn, mb, h }?stack= linklocalStoragehookarc.stack.v1decodeStack → coerceConfigsnap to ranges · restore defaultsLaunch · step 2compact BlockWorkbenchnormalize(cfg)zero disabled blockslaunchWithBlocks

encodeStack serialises a stack to a short JSON object with one-letter keys and base64url-encodes it:

KeyField
nname
mmask
wsnipeWindowBlocks
bsnipeMaxBuyBps
tsnipeTaxBps
buburnBps
ppotBps
pnpotN
mbpotMinBuy (decimal string, raw quote units)
hhaltMaxStaleness

The link is /launch?stack=<base64url> or /builder?stack=<base64url>. decodeStack tolerates garbage: unknown keys are dropped, unknown mask bits are cleared, out-of-range values are clamped by coerceConfig, and a block that is on but has a zero field gets the default restored. A link can therefore only ever produce a config that passes validation, or nothing.

Local storage

The Builder saves the current stack under hookarc.stack.v1. Launch reads it on mount when no ?stack= parameter is present. Clearing site data resets the design; nothing is stored server-side.

The workbench

The same BlockWorkbench component renders in two modes:

  • Full (/builder): a palette of the four blocks, a chassis showing the execution order (Halt Guard, Anti-Snipe, pot, then Auto Burn after the swap), a swap-flow view that traces one buy through the active blocks, and an inspector with sliders per parameter.
  • Compact (Launch step 2): the same state without the palette copy, so the launcher tunes and moves on.

Both show derived figures: the nominal buy drag in basis points (80 plus the pot share, plus the snipe tax while the window is open), a gas estimate per block, and warnings such as a snipe tax at its 50 % ceiling, a pot that fills too slowly for its N, or an Anti-Snipe window that lasts only a few seconds at Arc's block time.

Hand-off to Launch

Launch step 2 shows the loaded stack's name and a link back to the Builder with the current config encoded, so edits round-trip. On deploy, the config is normalised (fields of disabled blocks zeroed) and sent to launchWithBlocks, or to launch when the mask is zero.

read the code
  • web/lib/builder.ts block metadata, parameter specs, snapping, drag and gas estimates, warnings
  • web/lib/stack.ts encodeStack, decodeStack, coerceConfig, localStorage
  • web/components/builder/BlockWorkbench.tsx the shared canvas
  • web/lib/stack.test.ts round-trips and garbage tolerance