The keeper
The keeper is a Node service in keeper/. It takes launch requests and launches coins on both chains. It talks to Solana through @solana/web3.js and to Robinhood Chain through viem.
Modules
| File | What it does |
|---|---|
pump.mjs | pump.fun instructions: create_v2, fee sharing, with simulation (buy and sell exist but are not used in a launch) |
rh.mjs | Robinhood Chain: the launcher and vault ABIs, curve reads |
fx.mjs | The ETH/SOL rate from Coinbase, Binance and Jupiter, the median, and a flag when they disagree |
pipeline.mjs | The launch as a saved state machine, with retries and refunds |
rhdeposit.mjs | Verifies the creator's ETH deposit on Robinhood Chain: recipient, sender, reference in the data, success, amount |
metadata.mjs | Uploads the image and metadata to pump.fun's IPFS endpoint |
adapters.mjs | The real chain calls behind each pipeline step, dry or live |
server.mjs | The HTTP API for the launch page and the loops that watch deposits and run launches |
index.mjs | Dry-run reads of both chains |
The API
| Route | What it does |
|---|---|
GET /api/config | Deposit address, image limits |
POST /api/quote | The deposit for a set of options, itemised |
POST /api/metadata | Uploads the logo (base64, 1.5 MB at most) and the metadata to IPFS, returns the metadata URI |
POST /api/requests | Validates the parameters, reads the rate, returns an id, the deposit address, the amount in ETH and the expiry |
POST /api/requests/:id/deposit | Takes the transaction hash of the ETH deposit, reads it on Robinhood Chain and starts the launch if it is valid |
GET /api/requests/:id | Status and public log of a launch |
GET /api/health | Alive |
Commands
| Command | What it does |
|---|---|
node keeper/index.mjs newest | Dry run on the newest live pump.fun coin and the newest Pons coin: reads both curves and the rate. Sends nothing |
node keeper/launch.mjs params.json | Dry run of a whole launch through the pipeline: simulates the Pons launch and the pump.fun creation, plans the fee sharing |
node keeper/launch.mjs params.json --live | The real launch, with keys |
node keeper/server.mjs | The API and the background loops, dry by default; --live for real launches |
node keeper/check-solana.mjs | Simulates a buy, a sell, a create_v2 and a create_v2 with the fee sharing config against mainnet state |
node keeper/test-rh-fork.mjs | Integration test of the Robinhood path on an anvil fork |
Keys and configuration
| Variable | Used for |
|---|---|
KEEPER_SOL_SECRET | The Solana keeper wallet: deposit address, creator of record on pump.fun |
KEEPER_EVM_KEY | The Robinhood Chain keeper address, the only one the contracts accept |
LAUNCHER | The address of HingeLauncher once it is deployed |
SOLANA_RPC, RH_RPC | RPC endpoints, public ones by default |
SITE_ORIGIN, PORT | CORS origin and port of the API |
Without the keys the keeper stays in dry-run mode and can only read and simulate.
What the dry runs prove
- The Solana creation and fee sharing configuration are valid against the live pump.fun program and state.
- The Robinhood path works against the real Pons: launch, buy, sell and sweep, with the engine's prediction equal to the chain's result.
- The whole pipeline runs from a request to a registered coin against a fork and live Solana state.
What they do not prove
- A live run with real funds, which has not been done.
- The behaviour of the keeper through a long outage, an RPC failure or a pump.fun program change.
update_fee_shares_v2on a new coin: its layout comes from the AuronV2 code that ran it on mainnet, and a single transaction with the creation and both fee sharing instructions would exceed the size limit.
Public limits
- 12 launch requests and 20 uploads per hour and address.
- A deposit counts only if it comes from the Robinhood Chain address given in the request and carries the request's reference.
- Public requests cannot change the pump.fun fee share, and there is no alignment buy and no maker cash.
- Pipeline steps never overlap: a request already being worked on is skipped by the next pass, so a step cannot run twice.