Docs
Write your own block
The block interface, config schema, review and royalties.
Anyone can write a block, submit it to the catalog, and, once approved, earn a royalty from every launch that uses it. Blocks are small Solidity contracts; the native ones in contracts/src/blocks are good starting points.
The interface
interface IRuleBlock {
/// Bitmask of the hook points a block uses: 1 beforeSwap, 2 afterSwap, 4 beforeAddLiquidity.
function hookPoints() external pure returns (uint8);
/// True when `config` is valid for this block in a pool of the given lane.
function validateConfig(bytes calldata config, bool isLaunch) external view returns (bool);
function beforeSwap(SwapContext calldata ctx, bytes calldata config, bytes32 state)
external view returns (uint24 feeAdd, bool reject, bytes32 newState);
function afterSwap(SwapContext calldata ctx, bytes calldata config, bytes32 state)
external view returns (uint16 burnBps, bool reject, bytes32 newState);
function beforeAddLiquidity(LiquidityContext calldata ctx, bytes calldata config, bytes32 state)
external view returns (bool reject);
}What a block sees about a trade:
struct SwapContext {
PoolId poolId;
bool isBuy; // true when the swapper receives the pool's token
bool exactInput;
uint256 amount; // |amountSpecified|
uint256 impactPpm; // trade size against pool depth, in millionths
uint256 subjectAmount; // tokens bought or sold (0 in beforeSwap)
uint40 openedAt; // when the pool opened
uint40 timestamp;
uint256 subjectSupply; // token supply when the pool opened
bool isLaunch;
}Rules every block lives by
- Everything is
vieworpure. The kernel calls withSTATICCALL: no state writes, no transfers, no calls into the pool. - 100,000 gas per call. A block that reverts, runs out of gas or returns malformed data is skipped for that call.
- Per-pool memory is one
bytes32the kernel stores for you: readstate, returnnewState. validateConfigmust reject settings you can't handle, and the lane you don't support. Registration fails if it returns false.- Fees are in pips (10,000 = 1%), burns in basis points (100 = 1%). The kernel caps the totals.
Describing your settings
Settings are ABI-encoded in order and described by a small JSON document stored on chain with your submission. The builder renders a form from it, so your block needs no changes to the app.
{
"name": "Weekend fee",
"summary": "One or two plain sentences a token creator can understand.",
"lanes": "any",
"config": [
{ "key": "extraFee", "type": "uint24", "label": "Extra fee on weekends",
"unit": "pips", "min": 0, "max": 20000, "default": 5000 }
]
}| Field | Values |
|---|---|
type | uint16, uint24 or uint32 |
unit | pips (10,000 = 1%), bps (100 = 1%), seconds, or number |
lanes | "any", or "launch" for new tokens only |
Submit and get paid
- 1
Write and test
Use Foundry; test against the kernel's caps and both lanes. - 2
Deploy on Arc
Deploy your block contract to Arc mainnet. - 3
Submit
On Submit a block, paste the address and describe its settings. The form checks that it implements the interface and accepts its default settings, and previews its fee curve. - 4
Review
The catalog owner reviews the code and approves it with a royalty rate (at most 20% of the protocol's share). Approval pins the contract's code hash. - 5
Earn
Each launch that uses your block pays you its royalty rate, frozen at launch, whenever that launch's fees are collected. Claim in your Portfolio.
Tips
- Keep it cheap and deterministic; use
ctx.timestamprather than assumptions about time. - Prefer raising fees over refusing trades: a block that refuses everything freezes trading in pools that chose it.
- Write the summary for token creators, not developers.
