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.
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).
Key reads:
launchFee(),creatorBps(),treasury(),ownerRegistry(),feeLocker()getLaunch(token)returns(creator, pool, positionId, createdAt)allTokens(i)andallTokensLength()enumerate every launch in ordercomputeTokenAddress(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:
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 oftoken. RevertsNothingToClaim()on zero.protocolRecipient()andburnTokenFees()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:
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 revertsFeeLockerLocked()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 stampedcreatorBps, 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.