Skip to content

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

IRuleBlock.sol
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:

SwapContext
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 view or pure. The kernel calls with STATICCALL: 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 bytes32 the kernel stores for you: read state, return newState.
  • validateConfig must 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.

metadata.json
{
  "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 }
  ]
}
FieldValues
typeuint16, uint24 or uint32
unitpips (10,000 = 1%), bps (100 = 1%), seconds, or number
lanes"any", or "launch" for new tokens only

Submit and get paid

  1. 1

    Write and test

    Use Foundry; test against the kernel's caps and both lanes.
  2. 2

    Deploy on Arc

    Deploy your block contract to Arc mainnet.
  3. 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. 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. 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.timestamp rather 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.