Reference

Documentation

Technical reference for the Glasspad token factory.

SDK Integration

Integrate with Glasspad using viem to deploy tokens and interact with the factory programmatically. Glasspad runs on Base (chain 8453, the default), Robinhood Chain (chain 4663) and Arc (chain 5042) — each has its own factory, hooks, and locker deployed at different addresses, and a deployment is only ever valid on the chain it names via originatingChainId. Select a chain below to view its addresses and launch ticks.

Arc pairs against USDC, not WETH. Arc has no WETH: its paired token is USDC’s 6-decimal ERC-20 interface (0x3600000000000000000000000000000000000000), and launch ticks are a price in the paired token’s units, so an Arc launch needs different ticks for the same opening market cap. Reusing Base’s ticks on Arc opens the pool 1012× too expensive (about $100 per token). The example below already uses each chain’s own ticks.

Deploy a token

import { encodeAbiParameters, parseAbiParameters } from 'viem';

const FACTORY = '0x04f034649b72e7f4F167BeE683797C0C35067528';
const DYNAMIC_HOOK = '0xb084C242F382Bdae5dFeDCd96dC10F16603FE8cC';
const LP_LOCKER = '0x7Fe433A7E1a89ab598834ac2fB0695041F8DB7Ca';
const MEV_MODULE = '0xeF4419227355269952801EdA885C30fFEBD2E557';
const FEE_LOCKER = '0xA6B95c1d3168fCB07738B45803a89b28873963D5';
const WETH = '0x3600000000000000000000000000000000000000'; // Arc has no WETH: USDC's 6-decimal ERC-20 interface
const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
const CHAIN_ID = 5042n; // Arc

const feeDataBytes = encodeAbiParameters(
  parseAbiParameters('uint24, uint24, uint256, uint256, int24, uint256, uint24'),
  [30000, 100000, 30n, 120n, 200, 500000000n, 7500]
);

const poolDataBytes = encodeAbiParameters(
  parseAbiParameters('(address extension, bytes extensionData, bytes feeData)'),
  [{ extension: ZERO_ADDR, extensionData: '0x', feeData: feeDataBytes }]
);

const deploymentConfig = {
  tokenConfig: {
    tokenAdmin: myAddress,
    name: 'My Token',
    symbol: 'MTK',
    salt: '0x' + '00'.repeat(32),
    image: '',
    metadata: '',
    context: '',
    originatingChainId: CHAIN_ID,
  },
  poolConfig: {
    hook: DYNAMIC_HOOK,
    pairedToken: WETH,
    tickIfToken0IsBonker: -428800, // Arc's opening price
    tickSpacing: 200,
    poolData: poolDataBytes,
  },
  lockerConfig: {
    locker: LP_LOCKER,
    rewardAdmins: [myAddress],
    rewardRecipients: [myAddress],
    rewardBps: [10000],       // 100% to creator
    // Every position must start at or above tickIfToken0IsBonker (TickRangeLowerThanStartingTick).
    tickLower: [-428800, -412400, -400400, -353400, -339400],
    tickUpper: [-412400, -353400, -353400, -318400, -318400],
    positionBps: [1000, 5000, 1500, 2000, 500],
    lockerData: encodeAbiParameters([{ type: 'tuple', components: [{ type: 'uint8[]', name: 'feePreference' }] }], [{ feePreference: [1] }]),
  },
  mevModuleConfig: {
    mevModule: MEV_MODULE,
    mevModuleData: encodeAbiParameters(parseAbiParameters('(uint24 startingFee, uint24 endingFee, uint256 secondsToDecay)'), [{ startingFee: 666777, endingFee: 41673, secondsToDecay: 15n }]),
  },
  extensionConfigs: [],       // no extensions
};

// The chain you broadcast this on must match originatingChainId above — walletClient's
// own chain, e.g. via viem's `chain` param or wagmi's connected chain.
const tx = await walletClient.writeContract({
  address: FACTORY,
  abi: factoryAbi,
  functionName: 'deployToken',
  args: [deploymentConfig],
});

Robinhood Chain's and Arc's UniversalRouter are a fork with an extra field in their swap structs. This is only relevant if you build swaps yourself rather than using the deployed pool's default routing. See Architecture and the Deployed Contracts page for the full address list on every chain.

Claiming fees

// Check available fees — FEE_LOCKER and WETH from whichever chain's constants you're
// using above (the same on every chain; on Arc, fees accrue in USDC).
const available = await publicClient.readContract({
  address: FEE_LOCKER,
  abi: feeLockerAbi,
  functionName: 'availableFees',
  args: [myAddress, WETH],
});

// Claim fees (called by the reward recipient)
await walletClient.writeContract({
  address: FEE_LOCKER,
  abi: feeLockerAbi,
  functionName: 'claim',
  args: [myAddress, WETH],
});