Reference

Addresses, config and events

Combined reference - deployed addresses, chain config, wire types, fee schedule, and event signatures.

1. Deployed Contract Addresses

Ethereum (chain 1)

Public API base URL: https://api.motoswap.org.

Deployment status is per contract, never per network. MOTO, the launch farm (VampChef), UniswapZap, MotoStaking, RewardVestingEscrow, TreasuryVesting, the Motocat collection and MotocatStaking went out first. The DEX contracts (factory, router, FeeRouter, Collector, QuoteAssetRegistry, RakebackV2, MasterChef, zap, the creator fee pair, PveVault, BuybackBurner, the moto.fun contracts) went out with the DEX. Contracts in the source tree that are not deployed are called out where they appear below.

Fetch addresses from GET /config rather than hard-coding them. The status table, with every address the site pins and every key that reads 0x0, lives on Contract Addresses, so one page owns it and it cannot drift. This page documents the /config keys themselves:

factory, router, permit2, motoStaking, motoToken, masterChef, tokenLauncher, feeRouter, collector, quoteRegistry, rakeback, zap, vaultCompounder, usdc, usdt, weth, creatorFeeRegistry, creatorFeeVault, motocatNft, motocatStaking, pveVault, pveVaultV2, buybackBurner, buybackDistributor, rewardVestingEscrow, treasuryVesting, launchpadCurve, launchpadLens, motoUniswapPair, vampChef, uniswapZap, uniswapV2Router, uniswapV2Factory, plus the vestigial vaults[0..3] array (MotoStaking holds every lock option in one contract).

Not exposed by /config. Snapshotter is the only contract in the source tree with no key on the endpoint. There is no getter for it; if it ships, its address will be published separately.

An address that reads back as 0x0 from /config means the contract is unset for that chain in the current launchPhase, or its feature is off. It does not mean the key is missing. Never send a transaction to it. tokenLauncher belongs to a retired contract and stays 0x0. rewardVestingEscrow also has an on-chain getter, vestingEscrow() on the chef, which is worth preferring since it survives a redeploy that /config has not caught up with.

Read /config.addresses.masterChef rather than assuming what is behind it. While launchPhase was vamp it held the same address as vampChef, and the contract behind that key is a VampChef (one-step withdraw, its own event set, listed below).

The seeded MOTO/WETH pool for the current phase is served as motoUniswapPair (during launch farming it was a Uniswap V2 pair). Derive any other pair from factory.getPair(tokenA, tokenB) rather than hard-coding it.

/config also carries two moto.fun keys, launchpadCurve and launchpadLens. Both read back as 0x0 unless that surface is enabled for the chain, so gating on the address alone is correct. The top-level motofunEnabled / motofunUrl fields flag the same surface.

Contracts published under Motoswap-adjacent repos are sibling experiments, not the Motoswap DEX. If an address is not in /config and not discoverable from a /config contract's getters, do not integrate against it.

Local development

Local addresses are not listed here. The local stack described below is Motoswap's own development environment and is not public. As an outside integrator, fork Ethereum mainnet with your own node tooling and use the chain 1 addresses from GET https://api.motoswap.org/config.

Discovering addresses at runtime

The recommended integrator path: call GET /config on the backend (https://api.motoswap.org/config). It returns the current chain's contract addresses, so you never hard-code them. The answer below is a complete chain 1 capture taken on 2026-09-28 after the DEX opened, with launchPhase at dex. Any 0x0000000000000000000000000000000000000000 is a contract that is not deployed. Call the endpoint for the values you use:

{
  "chainId": 1,
  "addresses": {
    "factory": "0x81c9cbc47d700da1777abd831d8da3f526dfae24",
    "router": "0x6f0b6a0d84c3cff6f273d5294cda147885225d5e",
    "permit2": "0x000000000022d473030f116ddee9f6b43ac78ba3",
    "motoStaking": "0xce88f2c6b49efbb92555ee5475311f0e250c2528",
    "motoToken": "0xbd965230588eaa536de6aa45e8ebbc01638535e0",
    "masterChef": "0x939f348b6658ce4db7cde088341b00de341fe085",
    "tokenLauncher": "0x0000000000000000000000000000000000000000",
    "feeRouter": "0x9f846ef584fd44d075b5e8df00ddb4416da61a80",
    "collector": "0xc13307272bbf73f2191ce57d0fb714c2a9200cf3",
    "quoteRegistry": "0xfb8ca710b9b242e9f5027272592ef4c19d37e200",
    "rakeback": "0x89e2e1819fc373e3cd840a0ceb2ef1eae79e2db8",
    "zap": "0x26bffd661c3d97b3285afa2a9f05232526a89129",
    "vaultCompounder": "0x0000000000000000000000000000000000000000",
    "usdc": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
    "usdt": "0xdac17f958d2ee523a2206206994597c13d831ec7",
    "weth": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
    "creatorFeeRegistry": "0x6cdec7f49036ccf1bba940011040fa044cfe6d08",
    "creatorFeeVault": "0x8cc7c8e76d9698e5b1026c720a94c1807e613e1f",
    "motocatNft": "0x0b024b3d4ad38bff1acd303cd308d2c49c936e0a",
    "motocatStaking": "0x11890ee9ee6099ac33fd4dfb702f8e8f6d651f17",
    "pveVault": "0x84303a885717c4dd9effbdd2179bbe4b01756740",
    "pveVaultV2": "0x0000000000000000000000000000000000000000",
    "buybackBurner": "0x85b5a2800d7e2d948f21cb8f6e610d2c9b19ae3d",
    "buybackDistributor": "0x0000000000000000000000000000000000000000",
    "rewardVestingEscrow": "0xb94bfadc535d96462854175d776afc168196976b",
    "treasuryVesting": "0x5730abdf3c06c37940fb8b5291277e62d2c15278",
    "launchpadCurve": "0xb65b67e986d7b097652920d72202f2c78319bc2c",
    "launchpadLens": "0xb631697124c8e6bb6c221cc017e47d4168bd3411",
    "motoUniswapPair": "0xad1a21f61d653c6101b92c335f61140459c81c79",
    "vampChef": "0x51e648f08a9a08a724591938d9cbc483c809aca4",
    "sustainChef": "0x939f348b6658ce4db7cde088341b00de341fe085",
    "uniswapZap": "0x532bfb5b8c9e3cef20d36910b90cfbd919b18c31",
    "uniswapV2Router": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
    "uniswapV2Factory": "0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f",
    "vaults": [
      "0x0000000000000000000000000000000000000000",
      "0x0000000000000000000000000000000000000000",
      "0x0000000000000000000000000000000000000000",
      "0x0000000000000000000000000000000000000000"
    ]
  },
  "splitSwapEnabled": true,
  "motofunEnabled": true,
  "bridgeMotoEnabled": false,
  "motofunUrl": "https://moto.fun",
  "pveComboEnabled": false,
  "launchPhase": "dex",
  "dexCutover": false,
  "misconfigured": []
}

There is no rpcUrl field: bring your own RPC endpoint for chain 1.

Top-level fieldTypeMeaning
chainIdnumberThe chain these addresses live on.
addressesobjectThe keys listed above. Lowercase 0x strings; vaults is an array of four.
launchPhase"prelaunch", "vamp" or "dex"vamp: the farm is deployed and the DEX is not, which is how it read before the DEX opened. dex: the DEX is deployed.
splitSwapEnabledbooleanAPI configuration flag read by the Motoswap app: whether it submits a split fill as one swapExact*Split transaction (true) or as one swap per leg (false). Not an on-chain switch: the FeeRouter split entrypoints have no enable flag.
motofunEnabledbooleanWhether the moto.fun surface is on. When false, launchpadCurve and launchpadLens read 0x0.
motofunUrlstringThe moto.fun site URL, or "".
bridgeMotoEnabledbooleanWhether MOTO bridging is switched on in the app.
pveComboEnabledbooleanDead flag. Nothing reads it.
misconfiguredstring[]Names of transaction-target addresses that are unset for the current phase. Empty in normal operation.

2. Chain / Network Config

Supported chain IDs

Ethereum mainnet is chain 1, and it is the only chain an integrator targets. The client also accepts a local development chain id; NEXT_PUBLIC_CHAIN_ID is validated against a fixed allowlist, so no other value is accepted.

Read the chain you are pointed at from /config.chainId rather than assuming one.

Public endpoints

  • REST API base URL: https://api.motoswap.org
  • RPC URL: bring your own for chain 1. /config does not return one. Do NOT ship an API-keyed URL in a browser bundle.
  • CORS: Simple GET requests work from a browser on any origin. Requests that need a CORS preflight, such as one where your script sets If-None-Match, only pass for the Motoswap app origin, so do conditional polling and any write from a server.
  • Endpoint reference: API.
  • Chain head heartbeat: GET /chain/head (block number + timestamp, 1s max-age).

WebSockets

No WebSocket subscriptions are exposed to integrators. Use the REST API (cache-friendly, ETag-versioned; 304s are near-free) or watch on-chain events directly via your own RPC / event-log provider.

Fill-in reference (from source)

The environment variables that decide which chain and backend a client talks to:

NEXT_PUBLIC_CHAIN_ID          # the target chain id
NEXT_PUBLIC_RPC_URL           # browser/wallet-safe (keyless)
RPC_URL                       # server-side (may be keyed; not shipped)
NEXT_PUBLIC_API_BASE_URL      # absolute backend URL for the chain
NEXT_PUBLIC_SENTRY_DSN        # optional, disabled locally

3. Domain / Wire Types

All branded types live in packages/domain/src/*.ts and are re-exported from @motoswap/shared/domain. The rule: one runtime type end-to-end (DB, backend, frontend, chain), a separate WIRE type only when the runtime type is not JSON-serialisable (i.e. bigint).

Domain typeRuntimeWire (JSON)Zod schemaExample
Address`0x${string}` (always lowercase)stringaddressSchema"0xa0b86991…eb48"
TxHash`0x${string}` (32-byte)stringtxHashSchema"0x00…01"
Weibigintstring (decimal) via weiWireweiSchema"1000000000000000000"
Uint256bigintstring (decimal)uint256Schema"1000000000000000000"
Usdbigint (µ-USD, 6dp integer)string (decimal dollars) via usdWireusdSchema"2500.50" (= 2 500 500 000 µ$)
Secondsnumber (Unix seconds)numbersecondsSchema1723456789
Percentnumber (float, e.g. 10.5 = +10.5%)numberpercentSchema10.5
Aprnumber (non-negative integer basis points, 1250 = 12.50% APR)numberaprSchema1250
Ratiobigint (18-dp fixed point, 1.0 = 10^18)string (decimal) via ratioWireratioSchema"0.000300"

There is no Bps brand. Basis-point fields (swapFeeBps, protocolFeeBps, toleranceBps, priceImpactBps, and so on) are plain integer numbers on the wire, or bigint where they feed SDK amount math.

Schema shape (example)

// Address - lowercase, 0x-prefixed, hex-only, length 42
const addressSchema = z
  .string()
  .transform((v) => v.toLowerCase())
  .refine((v) => v.startsWith("0x") && v.length === 42 && /^[a-f0-9]+$/.test(v.slice(2)))
  .brand("Address")
  .meta({ "x-type": "Address" });

// Wei - accepts bigint | string | number at parse time; runtime is bigint
const weiSchema = z
  .union([z.bigint(), z.string(), z.number()])
  .transform((v) => (typeof v === "bigint" ? v : BigInt(v)))
  .refine((n) => n >= 0n && n <= 2n ** 256n - 1n)
  .brand("Wei");

Wire conversion helpers

  • usdToWire(usd: Usd): string - bigint µ$ → decimal dollar string.
  • usdFromWire(s: string): Usd - decimal dollar string → bigint µ$.
  • weiToString(wei: Wei): string - bigint → decimal string.
  • weiSchema.parse(v) - accepts bigint / string / number; returns branded Wei.

null policy for numeric fields

  • usdValue, tvlUsd, volume*Usd, fees*Usd - "0" when zero, never null. (Coerced at the handler edge to keep client math trivial.)
  • priceUsd, aprBps, feeAprBps, delta *Pcts, rank, decimals - kept as null when genuinely unknown. Rendering 0 would mislead (a guessed 18 for unknown decimals mis-scales a token by 10^(18-d)).

4. Fee Schedule & Rakeback Constants

The constants in this section's fee tables are read from the Solidity source the contracts deploy from. Where a value is settable, read it live from the contract rather than trusting a number here.

Protocol-level fee (FeeRouter)

ConstantValueMeaning
LAUNCH_PROTOCOL_FEE_BPS70The launch fee (0.70%). A reference constant: initialize does not apply it.
MAX_PROTOCOL_FEE_BPS100Owner-settable ceiling (1.00%).
protocolFeeBps (live)Read it from the contractprotocolFeeBps is an initialize argument with no default, capped at MAX_PROTOCOL_FEE_BPS, and owner-settable afterwards. It launched at 70. Read it live from the feeRouter address /config serves rather than trusting a number here. See the fee model.
BPS_DENOM10 000Basis-point denominator.
MAX_SPLIT_LEGS4Max legs in one swap*Split call.
Fee sideQuote asset onlyCharged on the quote leg per QuoteAssetRegistry.quoteRank (WETH > USDT > USDC > MOTO). Both-quote routes charge the higher-ranked leg, and a tie goes to the output. A route with no quote asset at either end takes the fee at the first quote asset inside the path. NoQuoteSide() reverts only when no asset anywhere in the path is a quote asset. See which leg pays.

Pair swap fee (MotoSwapFactory)

ConstantValueMeaning
MAX_SWAP_FEE_BPS200Hard ceiling on swapFeeBps (2.00%).
swapFeeBps (launched)300.30% LP fee (entirely to LPs; feeTo is zero, so _mintFee no-ops).

Total swap cost at the planned launch values: 0.30% LP per hop + 0.70% protocol = 1.00% on a one-hop route with no registered moto.fun token, when protocolFeeBps == 70. Each path endpoint with an active creator adds the creator fee. While protocolFeeBps is 0 the protocol part is zero.

Collector split (Collector.buckets)

Default seed on init: 2 : 2 : 2 : 1 (owner-reweightable).

BucketRecipientWeightNotify?
0MotoStaking (staking revshare)2Yes (IStakingRewards.notifyReward)
1Treasury2No
2Rakeback2No
3Buyback and burn1No

Rounding dust accrues to the last bucket. Held earmarks (a bucket whose payout reverted) are excluded from distributable(token) so a failing bucket never re-weights the healthy ones.

Rakeback

ConstantValue
CLAIM_WINDOW30 days, measured from a slice's activation
MIN_ACTIVATION_DELAY / MAX_ACTIVATION_DELAYBounds on the delay between postRoot and activate. Values are not published here; read them, and the current activationDelay(), from the contract.
MAX_TOKENS_PER_EPOCH8
Vest schedule (baked into the leaf at post time)Week 0: 50% of R[week] · Week 1: +25% · Week 2: the remainder
Epoch lengthSunday-anchored week - epoch = floor((seconds − 259200) / 604800)
Quote assetsWETH, USDT, USDC, MOTO

Payout is a merkle claim. One root per weekly epoch covers every token, posted by postRoot (poster-gated, capped at the token's measured Collector inflow), then opened per (epoch, token) slice by the permissionless activate. A leaf is keccak256(abi.encodePacked(index, account, token, amount)) and is all-or-nothing: one bitmap bit, full amount, no partial claim and no cumulative counter. Unclaimed remainders leave via expireRoot after the window and become sweepable to the treasury.

Creator fee (optional; per-token via CreatorFeeRegistry)

ConstantValue
MAX_CREATOR_FEE_BPS50 (0.50% ceiling)
creatorFeeBps (live)0 to 50 (owner-settable); the deploy script writes 20 and the owner sets 30 at launch

Applied on the same quote leg as the protocol fee. Both fees are subject to the caller's amountOutMin (net enforced).

VampChef emission (launch farming)

ConstantValueNotes
DURATION14 daysOne flat emission window. rewardPerSecond = rewardBudget / DURATION.
emissionStart() / emissionEnd()read from the contractUnix seconds. Accrual is zero outside the window. One campaign, no restart.
Withdraw cooldownnonewithdraw(pid, amount) settles rewards and returns principal in one call. No claimWithdrawal.
Deposit feenonePoolAdded and PoolSet carry no depositFeeBps.
MAX_START_DELAY90 daysBounds a scheduled startTime.
HARVEST_GRACE30 daysWindow after emissionEnd before recoverUndistributedRewards opens.
MAX_POOLS500Hard cap.
ACC_PRECISION1e12Reward-per-share scaler.
Reward split50% liquid / 50% vested (RewardVestingEscrow, 180 days)

MasterChef emission

Deployed; no emission campaign is running and none is planned. These are the contract's constants, for reference.

ConstantValueNotes
HALVING_PERIOD (default)42 daysTime-based, not block-based
NUM_PERIODS (default)8~336 days total
MAX_START_DELAY90 daysBounds scheduled startTime
HARVEST_GRACE30 daysPost-emissionEnd window before recoverUndistributedRewards
COOLDOWN24 hoursWithdraw cooldown while the pool earns. None when no campaign is running or the pool's weight is 0. Withdraw is queue, then claim
MAX_DEPOSIT_FEE_BPS1000 (10%)Per-pool ceiling
MAX_POOLS500Hard cap
ACC_PRECISION1e12Reward-per-share scaler
Reward split50% liquid / 50% vested (RewardVestingEscrow, 180 days)

MotoStaking locks

Durationboost bpsMultiplier
3 months01.0x
6 months10 0002.0x
12 months30 0004.0x
24 months70 0008.0x

effectiveStake = amount × (10 000 + boostBps) / 10 000. Principal vests linearly over the lock; requestUnstake moves the vested amount into a 30-day linear drip (UNSTAKE_DRIP).

Motocat staking

MotocatStaking V3 distributes no rewards on its own, so it has no reward constants. It tracks a per-wallet staked cat count as a checkpoint history: each Checkpoint packs a uint32 block number and a uint224 value into one slot, so a count can be read at any historical block. A write above either bound reverts with CheckpointOverflow; two writes in the same block overwrite rather than append.

Rakeback vest math (concrete example)

  • A user earns R of a quote token in epoch 42.
  • Epoch 42: 0.5 × R claimable this week.
  • Epoch 43: +0.25 × R cumulative.
  • Epoch 44: +0.25 × R cumulative - total 100%.
  • After the window: each slice can be claimed for 30 days from its own activation, not from the epoch's end. Past that, anyone can call expireRoot(epoch, token), the unclaimed remainder leaves the liability record, and the owner can sweep that surplus to the treasury. sweep takes no signature and can never touch a live claim.

Each epoch settles independently - there's no FIFO across weeks.

Points ledger (indexer-side)

  • Every fee-paying swap is scored by the season engine into points_events. The scoring internals (rates, curves, tiers, milestone bases, boost formula) are not published; do not reverse-engineer or state them.
  • Referral rate: 10% of the referee's points to the referrer, one level.
  • Motocat boost: the wallet's STAKED Motocat count (staked in MotocatStaking; a merely-held cat does not count), read at the block before the swap. Formula unpublished.
  • Balances publish once a day at the 00:00 UTC drop; per-swap deltas are never observable via the API.

5. Events - Integrator Reference

Grouped by contract. Watch them through your own RPC or event-log provider. Signatures below are the Solidity form, checked against the contract source. Hash the canonical form (types only, no names, no indexed) with keccak256 to get topic0, or run cast sig-event "<signature>".

Filter on the address /config serves for each contract, never on a hard-coded one. The deployed implementations can trail the source: where an event below is in the source but not yet in the deployed code, the text says so.

VampChef (launch farming, ended)

event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event RewardPaid(address indexed user, uint256 indexed pid, uint256 amount);
event RewardShortfall(address indexed user, uint256 indexed pid, uint256 owed, uint256 paid);
event RewardForfeited(address indexed user, uint256 indexed pid, uint256 amount);
event PoolAdded(uint256 indexed pid, address indexed lpToken, uint256 allocPoint, uint256 totalAllocPoint);
event PoolSet(uint256 indexed pid, uint256 allocPoint, uint256 totalAllocPoint);
event PoolUpdated(uint256 indexed pid, uint256 accRewardPerShare, uint256 lastRewardTime);
event EmissionStarted(uint256 budget, uint256 rewardPerSecond, uint64 startTime, uint64 endTime);
event RewardTokenSet(address rewardToken);
event TrustedZapperSet(address trustedZapper);
event UndistributedRewardsRecovered(address to, uint256 amount);

RewardShortfall is in the source but not in the deployed implementation, which has no such topic0 in its bytecode. It arrives with a contract upgrade. Every other event above is in the deployed code.

Emitter: the vampChef address from /config. It is not MasterChef: there is no WithdrawQueued or WithdrawClaimed, and PoolAdded / PoolSet / EmissionStarted have different arguments, so their topic0 values differ from MasterChef's.

Eventtopic0
Deposit(address,uint256,uint256)0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15
Withdraw(address,uint256,uint256)0xf279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568
RewardPaid(address,uint256,uint256)0xd6f2c8500df5b44f11e9e48b91ff9f1b9d81bc496d55570c2b1b75bf65243f51
PoolUpdated(uint256,uint256,uint256)0x17b8644f386d1c7c7138ef98b3c8035622bbe94d7be9b26f71d2654a547c2943

RewardPaid.amount is the full harvest. Half of it moves to the wallet and half is deposited into RewardVestingEscrow, which emits its own Deposited.

UniswapZap

event Zapped(
    address indexed sender,
    address indexed pair,
    address tokenIn,
    uint256 amountIn,
    uint256 swapAmount,
    uint256 lpAmount
);

Emitter: the uniswapZap address from /config. A zap that stakes also produces a VampChef.Deposit whose user is the zapping wallet, not the zap contract.

MotoToken

event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);

Standard ERC-20 events. MOTO has 18 decimals, a fixed supply, ERC-2612 permit, no owner and no mint. The token also emitted a handful of one-time events when it launched. They do not recur, and tradingOpen() returns true, so transfers are unrestricted.

FeeRouter (canonical trade event)

event Swap(
    address indexed user,
    address indexed tokenIn,
    address indexed tokenOut,
    uint256 amountIn,
    uint256 amountOut,
    address feeToken,          // quote asset the fee was charged in
    uint256 feeAmount          // exact protocol fee (quote-side)
);
event ProtocolFeeSet(uint256 protocolFeeBps);
event CreatorFee(
    address indexed token,
    address indexed creator,
    address quoteAsset,
    uint256 amount
);
event Permit2Set(address permit2);
event CreatorFeeConfigSet(address registry, address vault, uint256 creatorFeeBps);
event Rescued(address indexed token, address indexed to, uint256 amount);

FeeRouter.Swap is the canonical trade - one row per fee-paying swap (multi-hop = 1 event). The pair Swap fires N times for N hops. user is msg.sender, the payer. It is never the to recipient. The two coincide for an ordinary wallet swap and diverge when a contract calls FeeRouter: an aggregator's settlement contract is user on every swap it routes, and Points, Rakeback and referral attribution all follow user.

MotoSwapPair

event Swap(
    address indexed sender,
    uint256 amount0In,
    uint256 amount1In,
    uint256 amount0Out,
    uint256 amount1Out,
    address indexed to
);
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Sync(uint112 reserve0, uint112 reserve1);
event Transfer(address indexed from, address indexed to, uint256 value);   // LP token
event Approval(address indexed owner, address indexed spender, uint256 value);

Sync fires after every state-changing pair call and is the canonical reserves snapshot for indexers.

MotoSwapFactory

event PairCreated(address indexed token0, address indexed token1, address pair, uint256 allPairsLength);
event SwapFeeSet(uint256 swapFeeBps);
event QuoteRegistrySet(address indexed quoteRegistry);
event SwapAllowedSet(address indexed account, bool allowed);
event FeeToSet(address indexed previousFeeTo, address indexed newFeeTo);
event FeeToSetterTransferStarted(address indexed previousFeeToSetter, address indexed newFeeToSetter);
event FeeToSetterTransferred(address indexed previousFeeToSetter, address indexed newFeeToSetter);

MasterChef

event PoolAdded(uint256 indexed pid, address indexed lpToken, uint256 allocPoint, uint16 depositFeeBps, uint256 totalAllocPoint);
event PoolSet(uint256 indexed pid, uint256 allocPoint, uint16 depositFeeBps, uint256 totalAllocPoint);
event PoolUpdated(uint256 indexed pid, uint256 accRewardPerShare, uint256 lastRewardTime);
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event WithdrawQueued(address indexed user, uint256 indexed pid, uint256 amount, uint64 cooldownEnd);
event WithdrawClaimed(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event RewardPaid(address indexed user, uint256 indexed pid, uint256 amount);
event RewardShortfall(address indexed user, uint256 indexed pid, uint256 owed, uint256 paid);
event RewardForfeited(address indexed account, uint256 indexed pid, uint256 amount);
event EmissionStarted(uint256 totalReward, uint256 initialPeriodReward, uint64 startTime, uint64 endTime);
event EmissionScheduleSet(uint256 halvingPeriod, uint256 numPeriods);
event FeeRecipientUpdated(address feeRecipient);
event RewardTokenSet(address rewardToken);
event VestingEscrowSet(address vestingEscrow);
event TrustedZapperSet(address trustedZapper);
event UndistributedRewardsRecovered(address to, uint256 amount);

MotoStaking

event Staked(address indexed account, uint256 amount, uint8 durationOption);
event Imported(address indexed account, uint256 amount, uint8 durationOption);
event Appended(address indexed account, uint256 added, uint256 total, uint8 durationOption, uint64 start);
event RewardNotified(address indexed token, uint256 amount, uint256 accRewardPerEffShare);
event RewardForwardedToTreasury(address indexed token, uint256 amount);
event Claimed(address indexed account, address indexed token, uint256 amount);
event ClaimSkipped(address indexed account, address indexed token);
event ClaimedAsMoto(address indexed account, address indexed token, uint256 rewardIn, uint256 motoOut);
event UnstakeRequested(address indexed account, uint256 amount, uint64 start);
event Unstaked(address indexed account, uint256 amount);
event BoostSet(uint8 durationOption, uint256 bps);
event RewardNotifierSet(address rewardNotifier);
event FeeRouterSet(address feeRouter);
event VestAnchorSet(uint64 anchor);
event RewardTokenAdded(address indexed token);
event RewardTokenRemoved(address indexed token);
event RewardTokenPurged(address indexed token);

Every event above is in the deployed implementation. Two of them stay silent until a contract upgrade lands: the deployed MotoStaking has no reward notifier registered, and its feeRouter() is a 0x…dEaD placeholder, so claimAsMoto reverts and ClaimedAsMoto and RewardNotified do not fire.

RakebackV2

event RootPosted(uint256 indexed epoch, bytes32 root, uint64 postedAt);
event SlicePosted(uint256 indexed epoch, address indexed token, uint256 declaredTotal);
event Activated(uint256 indexed epoch, address indexed token, uint64 activatedAt);
event Claimed(
    uint256 indexed epoch,
    address indexed token,
    uint256 index,
    address account,
    uint256 amount
);
event ClaimedAsMoto(
    address indexed user,
    address indexed token,
    uint256 indexed epoch,
    uint256 amountIn,
    uint256 motoOut
);
event Expired(uint256 indexed epoch, address indexed token, uint256 remainder);
event PendingSliceExpired(uint256 indexed epoch, address indexed token, uint256 declared);
event RootCancelled(uint256 indexed epoch);
event InflowSynced(address indexed token, uint256 delta, uint256 lifetimeInflow);
event Swept(address indexed token, uint256 amount);
event PosterSet(address poster);
event GuardianSet(address guardian);
event ActivationDelaySet(uint64 activationDelay);
event TreasurySet(address treasury);
event FeeRouterSet(address feeRouter);

RakebackV2.Claimed has 2 indexed args (epoch, token) and 5 total; MotoStaking.Claimed has 2 indexed (account, token) and 3 total. Different signatures, so their topic0 values do not collide - but both are named Claimed, so filter by emitter address, not by name. Note that the claimant is the un-indexed account field, so you cannot filter claims by wallet in a topic.

MotocatStaking (NFT staking)

event Staked(address indexed wallet, uint256[] tokenIds);
event Unstaked(address indexed wallet, uint256[] tokenIds);
event Seeded(address indexed wallet, uint256[] tokenIds);
event SeedingClosed();
event SeederSet(address indexed seeder);
event SeedSourceSet(address indexed seedSource);
event OutboxAdded(address indexed outbox);
event OutboxRemoved(address indexed outbox);
event Broadcast(address indexed wallet, uint256 stakedCount);
event BroadcastFailed(address indexed outbox, address indexed wallet);
event ERC20Rescued(address indexed token, address indexed to, uint256 amount);
event ERC721Rescued(address indexed token, address indexed to, uint256 tokenId);
event ETHRescued(address indexed to, uint256 amount);
event UpgradesRenounced();

V3 pays no rewards, so it emits no Reward* events. Staked / Unstaked are the only events that move a wallet's cat count; Broadcast mirrors that count to a registered outbox and BroadcastFailed records an outbox that reverted without blocking the stake.

CreatorFeeRegistry / CreatorFeeVault

// Registry
event TokenRegistered(address indexed token, address indexed creator, address indexed registrar);
event CreatorSet(address indexed token, address indexed creator);
event CreatorSetBySelf(address indexed token, address indexed previousCreator, address indexed creator);
event TokenDisabled(address indexed token, bool disabled);
event RegistrarSet(address indexed registrar, bool allowed);

// Vault - emits Accrued on every deposit, Claimed on every payout, DepositorSet on config
event Accrued(address indexed token, address indexed quoteAsset, uint256 amount);
event Claimed(address indexed token, address indexed creator, address indexed quoteAsset, uint256 amount);
event DepositorSet(address indexed depositor, bool allowed);

Collector

event BucketConfigured(uint256 indexed index, address recipient, uint96 weight, bool notify);
event BucketRecipientSet(uint256 indexed index, address recipient, bool notify);
event MinIntervalSet(uint256 minInterval);
event Distributed(address indexed token, uint256 amount);
event BucketPaid(address indexed token, uint256 indexed index, address recipient, uint256 amount);
event BucketSkipped(address indexed token, uint256 indexed index, bytes reason);
event BucketHeld(address indexed token, uint256 indexed index, address recipient, uint256 amount, uint256 totalHeld);
event HeldReleased(address indexed token, uint256 indexed index, address recipient, uint256 amount);
event HeldForceReleased(address indexed token, uint256 indexed index, uint256 amount);

BuybackBurner / BuybackDistributor

// Burner
event KeeperSet(address keeper);
event FeeRouterSet(address feeRouter);
event BoughtBack(address indexed tokenIn, uint256 amountIn, uint256 motoOut);
event Burned(uint256 amount, uint256 totalBurned);
event PinnedPathSet(address indexed tokenIn, address[] path);
event NothingToDo(address indexed tokenIn);
event TwapToleranceSet(uint256 bps);
event CheckpointPoked(address indexed tokenIn, address indexed pair, uint256 priceCumulative, uint32 timestamp);
event TwapFloorBinding(address indexed tokenIn, uint256 keeperFloor, uint256 twapFloor);

// Merkle distributor
event Claimed(uint256 indexed index, address indexed account, uint256 amount);
event Swept(address indexed to, uint256 amount);
event SweptAll(address indexed to, uint256 amount);

The three TWAP events belong to the burner's price floor, which guards a buyback against a manipulated pool. Their configured values are not published here. BuybackDistributor is not deployed and nothing schedules it.

RewardVestingEscrow / TreasuryVesting / Snapshotter

event Deposited(address indexed user, uint256 amount, uint256 scheduleTotal, uint64 start);
event Claimed(address indexed user, uint256 amount);
event DepositorSet(address indexed depositor, bool allowed);

event Released(uint256 amount, uint256 totalReleased);   // TreasuryVesting

event SnapshotTaken(uint256 indexed blockNumber, uint256 timestamp);   // Snapshotter

RewardVestingEscrow.Deposited has topic0 0x19e7166e374f41f05d851e7f5774e0d8424541e4b4353728a88a4c84fe7ba133 and RewardVestingEscrow.Claimed(address,uint256) has 0xd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a.

PveVault

event LauncherSet(address launcher);
event ExtraLauncherSet(address indexed launcher, bool allowed);
event MotocatStakingSet(address staking);
event PveCredited(address indexed token, uint256 amount, uint256 totalStaked, uint256 creditBlock);
event PveHeld(address indexed token, uint256 amount);
event PveClaimed(address indexed token, address indexed wallet, uint256 amount);
event PveReceived(address indexed token, address indexed creator, uint256 amount);
event Forwarded(address indexed token, address indexed to, uint256 amount);
event ExcessRescued(address indexed token, address indexed to, uint256 amount);
event PendingArrivalNoted(address indexed token);
event PendingArrivalCleared(address indexed token);
event PendingArrivalClearedByOwner(address indexed token, address indexed by);

QuoteAssetRegistry

event QuoteSet(address indexed token, bool status);
event QuoteRankSet(address indexed token, uint256 rank);

Integration Checklist

  • Fetch addresses from GET /config. Treat 0x0000000000000000000000000000000000000000 as unset and never send to it.
  • Add all contract addresses to your event-log filter (if watching on-chain events yourself).
  • Decode via the canonical ABIs. The deployed contracts have verified source, and the event signatures on this page match it.
  • The canonical trade event is FeeRouter.Swap. The pair Swap is one-per-hop.
  • Rakeback claims need a merkle proof (GET /rakeback/{address}, or GET /rakeback/{address}/proof for proofs alone).
  • Points are indexer-derived and publish once a day at the 00:00 UTC drop - read via GET /points/{address}, not on-chain.
  • All USD values are decimal-dollar strings on the wire (e.g. "2500.50"); runtime µ-USD bigints exist only server-side.
  • All bigint values are decimal strings on the wire.
  • All addresses are lowercased 0x-prefixed strings.
  • The API caches heavily - send If-None-Match with the previous ETag; expect frequent 304s.
  • List endpoints use cursor pagination; the cursor is HMAC-scope-bound (endpoint + filters). Do not reuse a cursor across queries.

On this page