# factory.ninja — Factory Ninja (app) > Factory Ninja is a mission-first funding launchpad. A founder ships a working prototype first — built in the > Dōjō (ide.factory.ninja, with Sensei the AI agent) and deployed to .factory.ninja — then opens a mission. > Backers commit the chain's native asset to an on-chain escrow (MissionCampaign). Goal met: the escrow and the > $NINJA stake release to the creator, who builds the real product, and the mission token launches with 100% of > supply locked as Uniswap v4 liquidity forever (LP fees 100% burned, zero platform fee). Deadline passed with the > goal unmet: every backer pulls their own refund. The prototype is the gate — missions list with a live prototype, > not a logo. Today the mission chains are testnets (Base Sepolia, Arc Testnet; Robinhood Chain Testnet not yet > deployed); the mainnets carry the token launchpad only. ## Terminology - Sensei: the AI coding agent in the Dōjō - Dōjō: the web IDE at ide.factory.ninja where prototypes are built - Mission: a funded campaign — backers escrow the native asset for a deliverable the founder builds - Kunai: the build phase - Shuriken: the prototype deploy to .factory.ninja - Ninpō: the founder's wallet-signed pledge, shown on the mission page - Mon: the reputation profile (/mon/) — missions founded and backed - Jutsu: a starter template - Teisatsu / Kanchō / Kishu: backer tiers by contribution (scout, spy, raider) - Nine Gates: the nine-step founder flow — Connect, Brief, Pledge, Forge, Throw, Verify, Arm, Live, Strike - Mission states: BUILDING · LIVE · FUNDED · FULLY_LAUNCHED · FAILED ## Mission contracts (escrow: create / back / release / refund) - Base Sepolia (84532): MissionCampaign 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D · $NINJA 0x9d9f4B6C0e9695E390d59ff1CE5757f96b181291 - Robinhood Chain Testnet (46630): (not deployed) - Arc Testnet (5042002): MissionCampaign 0x050AA998403C0e4C63266AEe90274F775aD0C62d · $NINJA 0xe2AD0B9456944241B16b16698F1FE58605a2A532 - Base (8453): (not deployed) - Robinhood Chain (4663): (not deployed) - Arc (5042): (not deployed) The $NINJA stake is pulled via transferFrom — approve the campaign first. Escrow asset = the chain's native asset (ETH; USDC on Arc). missionId = keccak256(slug). ## Token launchpad contracts - Base (8453): LaunchFactory (not deployed) · LaunchLocker (not deployed) - Robinhood Chain (4663): LaunchFactory (not deployed) · LaunchLocker (not deployed) - Arc (5042): LaunchFactory (not deployed) · LaunchLocker (not deployed) - Base Sepolia (84532): LaunchFactory 0xD67E1477f8668749328e46f75DCa78ad88CAa92E · LaunchLocker 0xe2AD0B9456944241B16b16698F1FE58605a2A532 - Robinhood Chain Testnet (46630): LaunchFactory (not deployed) · LaunchLocker (not deployed) - Arc Testnet (5042002): LaunchFactory 0x4668f9f2BD1695aAab378324bC66e2E6c8cC41B3 · LaunchLocker 0xD67E1477f8668749328e46f75DCa78ad88CAa92E ## Mission calls (cast, Base Sepolia) cast send 0x9d9f4B6C0e9695E390d59ff1CE5757f96b181291 "approve(address,uint256)" 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D 1000000000000000000000 --rpc-url https://sepolia.base.org --private-key $PK cast send 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D "create(string,uint256,uint64,uint256)" "my-mission" 100000000000000000 $(( $(date +%s) + 604800 )) 1000000000000000000000 --rpc-url https://sepolia.base.org --private-key $PK cast call 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D "missionIdOf(string)" "my-mission" --rpc-url https://sepolia.base.org cast send 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D "back(bytes32)" $MISSION_ID --value 0.01ether --rpc-url https://sepolia.base.org --private-key $PK cast send 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D "release(bytes32)" $MISSION_ID --rpc-url https://sepolia.base.org --private-key $PK # goal met → escrow + stake → creator cast send 0xa0bF2a9Ae83602D159F475414F0a1f65aB3f4C3D "refund(bytes32)" $MISSION_ID --rpc-url https://sepolia.base.org --private-key $PK # deadline passed, goal unmet → caller pulls their commit missionOf(bytes32) → (creator, goal, stake, total, deadline, state, slashed); state 0 active · 1 funded · 2 failed. commitOf(bytes32,address) → the backer's committed native wei. release and refund are permissionless. ## Token launch call (cast, Base) cast send "launch((string,string,string,address,uint256,int24,uint24,bytes32,(address,uint16)[]))" "(My Token,MYT,,0x0000000000000000000000000000000000000000,0,184200,10000,0x$(openssl rand -hex 32),[])" --rpc-url https://mainnet.base.org --private-key $PK quote 0x0 = ETH (USDG on Robinhood Chain 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168, USDC on Arc 0x3600000000000000000000000000000000000000); supply 0 → 1B default; startTick 184200 ≈ 10 ETH FDV; lpFee pips (0 / 10000 = 1% / 30000 = 3%); recipients [] = fees burned. Pools are plain Uniswap v4 (tick spacing 200, no hook) — swap through the Universal Router. ## API (JSON, no key) - GET https://app.factory.ninja/api/mission/list?sort=live|new|trending|funded&chain=&limit=40&offset=0 → {sort, chain, limit, offset, has_more, ethUsd, missions[]} — money fields are exact wei strings - GET https://app.factory.ninja/api/mission/live?sort=&chain=&limit= → {at, missions[], has_more, tape[], totals{live, funded, byChain, escrowedUsd, usd_partial}, ethUsd, sort, chain, limit} - GET https://app.factory.ninja/api/mission// → {mission, updates[{id, author, body, createdAt}], backs[{txHash, logIndex, backer, amountWei, blockNumber, blockTime}]} - POST https://app.factory.ninja/api/mission/meta {chain, slug, creator, name, tagline, description?, prototypeUrl?, website?, xHandle?, imageUrl?, ninpo?, ninpoSig?} → {chain, slug} INSERT-only (the brief reserves the slug); identical re-sends are idempotent; conflicts 409. - POST https://app.factory.ninja/api/mission/update {chain, slug, wallet, nonce, ts, signature, body} → {ok, update} — signer must be the mission's creator. {chain, slug, wallet, nonce, ts, signature, productionUrl} flips the display state to FULLY_LAUNCHED (funded missions only). - POST https://app.factory.ninja/api/mission/sync?chain=&tx=0x… → index one receipt now (idempotent, keyed by tx_hash + log_index); no tx → poll every configured chain - GET https://app.factory.ninja/api/mission/verify?url=https://… → {ok, status} — the prototype gate check (SSRF-safe fetch) - GET https://app.factory.ninja/api/launch/list?chain=&sort=live|new|mcap|volume|gainers|holders&window=1h|24h|all&limit=50 - GET https://app.factory.ninja/api/launch/feed - POST https://app.factory.ninja/api/launch/meta {chain, launcher, salt, name, symbol, description?, image_url?, website?, x_handle?} → {uri, token} - POST https://app.factory.ninja/api/launch/sync?chain=&tx=0x… - GET https://app.factory.ninja/api/health - POST https://app.factory.ninja/api/rpc?chain= — same-origin read-only JSON-RPC proxy (API key stays server-side) Mission row example: { "chain": "base_sepolia", "chain_id": 84532, "slug": "my-mission", "creator": "0x…", "goalWei": "100000000000000000", "stakeWei": "1000000000000000000000", "totalWei": "30000000000000000", "deadline": 1760000000, "state": "live", "slashed": false, "backs": 3, "token": null, "lastBackAt": "…", "blockNumber": 12345, "txHash": "0x…", "createdAt": "…", "name": "My Mission", "tagline": "…", "description": null, "prototypeUrl": "https://my-mission.factory.ninja", "productionUrl": null, "website": null, "xHandle": null, "imageUrl": null, "ninpo": null, "ninpoSig": null } state = live | funded | fully_launched | failed (display state; "building" is private to the founder's Mon). Zero platform fee anywhere. Poll modestly and back off on errors; indexing lags chain state by seconds. ## Pages / (mission board), /start (Nine Gates), /m/ (mission detail), /t// (token, post-launch), /mon/ (Mon profile), /rules (how it works), /agents (this reference, in HTML).