Documentation

Contracts

The five launchpad contracts, their key functions and events, the token metadata surfaces, and exactly what the admin can and cannot do.

On this page

Five contracts. The launcher is the only entry point; the other four hold state it writes once and that creators or anyone can act on afterwards.

ContractAddressApeScan
ArmoryLauncher0x69d3…c8C5
ArmoryLaunchLocker0x0972…Cf55
ArmoryLaunchFeeReceiver0x20bF…57c0
ArmoryTokenOwnerRegistry0xA360…5dDD

ArmoryToken has no fixed address. One is deployed per launch, at the address computeTokenAddress predicts.

ArmoryLauncher

The factory. launch(LaunchParams) does everything described on the overview in one transaction and returns (token, pool, positionId).

ConstantValue
POOL_FEE25000 (2.5%)
TICK_SPACING500
MAX_USABLE_TICK887000
DEFAULT_SUPPLY1,000,000,000 tokens (18 decimals)
MIN_CREATOR_BPS1000 (10%)
MAX_LAUNCH_FEE500 APE

Key reads:

  • launchFee(), creatorBps(), treasury(), ownerRegistry(), feeLocker()
  • getLaunch(token) returns (creator, pool, positionId, createdAt)
  • allTokens(i) and allTokensLength() enumerate every launch in order
  • computeTokenAddress(deployer, params) predicts the CREATE2 address

The CREATE2 salt is keccak256(abi.encode(msg.sender, userSalt)), so a salt mined for one sender is useless to another. The predicted address also commits to name, symbol, supply, every metadata field and the launcher's current owner registry. Change any of them and the address changes.

Reverts worth handling:

ErrorCause
InsufficientValue()msg.value is below launchFee()
InvalidTick()start tick is not a multiple of 500, or is outside [-887000, 887000)
EmptyString()empty name or symbol
PoolPriceMismatch()the pool for the predicted token already existed at another price
NotSingleSided()the mint consumed WAPE; should be unreachable
TokenOwnerRegistryNotSet(), FeeLockerNotSet()launcher not wired

PoolPriceMismatch is the one an integrator can hit. Because the token address is predictable, somebody can create its pool first at a hostile price. Retry with a fresh userSalt: a new salt is a new token address and a new pool.

TokenLaunched

event TokenLaunched(
    address indexed token,
    address indexed creator,
    address indexed pool,
    uint256 positionId,
    uint256 supply,
    int24 startTick,       // as passed: tickIfToken0IsNewToken
    uint16 creatorBps,     // the split stamped into this launch, forever
    string name,
    string symbol,
    string metadataURI,    // the ERC-7572 contractURI
    uint256 devBuyApe,     // APE spent on the dev buy, wei
    uint256 devBuyTokens   // tokens the dev buy returned
);

One event carries everything an indexer needs to list a launch. The token's own getters carry the rest.

ArmoryLaunchLocker

Holds every launch position forever. Positions enter only through onERC721Received, only from the Armory position manager, only when sent by the launcher, and only with a range that reaches the extreme usable tick. There is no function that moves a position out or reduces its liquidity.

  • collect(tokenId) collects the position's fees and hands both sides to the fee receiver. No access control. Returns (amount0, amount1).
  • collectMany(tokenIds) is the keeper batch. One unknown id reverts the whole batch.
  • updateCreatorRecipient(tokenId, newCreator) is token owner only. See Creator tools.
  • getConfig(tokenId) returns (creator, creatorBps, token0, token1).
  • feeReceiver() is the current fee policy contract.

A collect that finds nothing returns (0, 0) and emits nothing. A collect on an id that was never locked reverts NotLocked().

event PositionLocked(uint256 indexed tokenId, address indexed pool, address token0, address token1, address indexed creator, uint16 creatorBps);
event FeesCollected(uint256 indexed tokenId, address indexed receiver, uint256 amount0, uint256 amount1);
event CreatorRecipientUpdated(uint256 indexed tokenId, address indexed previousCreator, address indexed newCreator);
event FeeReceiverUpdated(address indexed previousReceiver, address indexed newReceiver);

ArmoryLaunchFeeReceiver

The fee policy. The locker transfers both fee amounts to it and calls onFeesCollected, which only the locker may call. The split rules are on Fees.

  • claimable(recipient, token) is an amount a failed push left behind.
  • claim(token) pays the caller their claimable balance of token. Reverts NothingToClaim() on zero.
  • protocolRecipient() and burnTokenFees() are the two settings.
event FeesDistributed(uint256 indexed tokenId, address indexed token, address indexed creator, uint256 creatorAmount, uint256 protocolAmount);
event FeeCredited(address indexed recipient, address indexed token, uint256 amount);
event FeesClaimed(address indexed recipient, address indexed token, uint256 amount);

One FeesCollected from the locker is followed by up to two FeesDistributed, one per side with a non-zero amount. When the token side is burned, its protocolAmount went to the dead address.

TokenOwnerRegistry

Who controls each launched token. The launcher registers the creator as owner during launch; a token can be registered once and never again.

  • ownerOf(token) is the current owner. Zero means renounced.
  • transferTokenOwnership(token, newOwner) is current owner only. Zero renounces.
  • registered(token) is true for every launched token, renounced or not.
event TokenOwnershipTransferred(address indexed token, address indexed previousOwner, address indexed newOwner);

ArmoryToken

ERC-20 with burn and burnFrom, 18 decimals, fixed supply. No owner role, no mint, no pause, no tax, no hooks.

  • launcher(), creator(), ownerRegistry() are immutable.
  • pool() is the launch pool, set once inside the launch transaction.
  • tokenOwner() resolves the current owner through the registry.
  • metadataLocked() is true once the one-time edit is spent.
  • updateMetadata(TokenMetadata) is the one-time edit, token owner only.

Metadata surfaces

Metadata is exposed three ways, so any indexer finds a format it reads:

GetterReturns
image()artwork URI; logo() is an alias
description()plain text
socials()one JSON string, e.g. keys x, telegram, discord, website
contractURI()ERC-7572 contract metadata, a URI to a JSON document

Tokens launched through the app store artwork and the contractURI JSON on Arweave. socials() omits keys that were left empty, and may be an empty string. Parse it defensively.

event PoolSet(address indexed pool);
event MetadataUpdated();
event ContractURIUpdated(); // ERC-7572; carries no args, re-read contractURI()

ContractURIUpdated fires at deployment and again on the metadata edit.

Admin powers

Each admin below is ApeOwnable, which resolves to the owner of the platform's GovernanceManager: the platform multisig. This is the complete list.

On ArmoryLauncher, affecting future launches only:

  • setLaunchFee: the flat fee, never above 500 APE.
  • setCreatorBps: the creator share for future launches, never below 10%. Launched tokens keep the share they were stamped with.
  • setTreasury: where launch fees go.
  • setTokenOwnerRegistry: which registry new launches use.
  • setFeeLocker: where launch positions are locked. This ossified after the first launch: it reverts FeeLockerLocked() once a locker is set and any token exists.

On ArmoryLaunchLocker:

  • setFeeReceiver: point fee routing at a new fee receiver contract. The fee receiver decides how future collected fees are split and paid, so this is the one admin power that reaches already-launched tokens. It cannot touch the positions, the stamped creatorBps, or the fee recipients, which the locker passes to whichever receiver is set.

On ArmoryLaunchFeeReceiver:

  • setProtocolRecipient: where the protocol's WAPE share goes.
  • setBurnTokenFees: burn the protocol's token share, or send it to the protocol recipient instead.

On TokenOwnerRegistry:

  • setLauncher: which contract may register new tokens. No power over existing owners.

Nobody can touch locked liquidity

No admin function on any of these contracts moves a launch position, reduces its liquidity, changes a token's owner, or edits a token's metadata. The launch locker has no code path that does those things for anyone.