RUSHPOT docs

Launch, trade, and build.

The short version for users, followed by the contracts and calls developers need.

For users

How it works

Every coin launches through the same factory into its own Uniswap v4 pool. Creators do not provide liquidity; the curve starts with 2.5 ETH of virtual liquidity and the full token supply.

Launch

Choose a name, ticker, metadata, social links, and an optional first buy.

Trade

Buy and sell against the token's curve through a compatible Uniswap v4 router.

Earn

Trading and creator volume can earn keys in the two active pot rounds.

Live pots

How to win a pot

Half of one percent from every trade goes to each reward pot. A key makes its holder the current leader, and the last eligible keyholder when the round settles receives that pot as claimable ETH. Each round runs for four hours. The separate 1% project share accrues in the hook for treasury to withdraw.

Trader potTrade 0.1 ETH for a key

Every full 0.1 ETH of trade notional earns a trader key. A 0.35 ETH trade earns three keys and makes that wallet the current trader leader.

Creator potGenerate 1 ETH of round volume

Volume from every trade on a creator's coins accumulates during the round. Each full 1 ETH earns that creator a key, even when it comes from many smaller trades by different users.

1Earn a keyQualifying volume updates the leader.
2Stay lastLater qualifying activity can replace the leader.
3Round settlesThe final eligible keyholder wins the accumulated pot.
4Claim ETHThe winner claims from the Rewards or Portfolio page.

Near the end, qualifying keys can extend the round up to its fixed cap. If that cap is reached, the hash of a future Robinhood L2 block selects a cutoff inside the closing window before the winner is finalized.

Token lifecycle

Graduation

Graduation happens once a token reaches a 30 ETH fully diluted market cap. The hook emits the migration event and permanently marks the token as graduated. The interface shows the live USD equivalent of that 30 ETH target.

For developers

Contract addresses

Addresses below are from the live RUSHPOT deployment on Robinhood Chain.

Fair launch deployerUnavailable
RUSHPOT hookUnavailable
Uniswap v4 routerUnavailable
Factory

Launch a token

Tokens must be created through FairLaunchDeployer. The factory creates the ERC-20, initializes its pool with the approved hook, and performs the optional first buy atomically.

launch-token.ts
import { parseEther } from "viem";
import { fairLaunchDeployerAbi } from "./abis";

const initialDevBuy = parseEther("0.1");

const hash = await walletClient.writeContract({
  address: "DEPLOYER_ADDRESS",
  abi: fairLaunchDeployerAbi,
  functionName: "launch",
  args: [{
    name: "Internet Money",
    symbol: "JPEG",
    twitter: "https://x.com/yourcoin",
    website: "https://yourcoin.xyz",
    telegram: "https://t.me/yourcoin",
    metadataUri: "ipfs://bafy...",
    initialDevBuy,
  }],
  value: initialDevBuy,
});
WebSocket

Listen for live events

Connect to the RUSHPOT event stream to refresh your interface when a launch, trade, graduation, key, round, or payout event is confirmed.

live-events.ts
const socket = new WebSocket("wss://api.rushpot.fun/v1/ws");

socket.addEventListener("message", (message) => {
  const event = JSON.parse(message.data);

  if (event.type === "TradeExecuted") {
    refreshToken(event.token);
  }

  if (event.type === "RoundFinalized") {
    refreshPots();
  }
});
Universal Router

Buy and sell

ETH is currency0, the launch token is currency1, and the launchpad hook must be included in the pool key. Encode the address that should receive trader keys in hookData; this lets bots and smart routers credit the user they are trading for. Set a real quoted minimum output in production. Robinhood trades use the Uniswap Universal Router's V4_SWAP command.

buy-token.ts
import { encodeAbiParameters, maxUint256, parseEther, zeroAddress } from "viem";

const amountIn = parseEther("0.1");
const keyRecipientData = encodeAbiParameters(
  [{ type: "address" }],
  [account],
);
const poolKey = {
  currency0: zeroAddress,
  currency1: tokenAddress,
  fee: 3000,
  tickSpacing: 60,
  hooks: "HOOK_ADDRESS",
};

const swap = encodeAbiParameters([{
  type: "tuple",
  components: [
    { name: "poolKey", type: "tuple", components: [
      { name: "currency0", type: "address" },
      { name: "currency1", type: "address" },
      { name: "fee", type: "uint24" },
      { name: "tickSpacing", type: "int24" },
      { name: "hooks", type: "address" },
    ]},
    { name: "zeroForOne", type: "bool" },
    { name: "amountIn", type: "uint128" },
    { name: "amountOutMinimum", type: "uint128" },
    { name: "minHopPriceX36", type: "uint256" },
    { name: "hookData", type: "bytes" },
  ],
}], [{
  poolKey,
  zeroForOne: true,
  amountIn,
  amountOutMinimum: quotedMinimumOut,
  minHopPriceX36: 0n,
  hookData: keyRecipientData,
}]);
const settle = encodeAbiParameters(
  [{ type: "address" }, { type: "uint256" }],
  [zeroAddress, maxUint256],
);
const take = encodeAbiParameters(
  [{ type: "address" }, { type: "uint256" }],
  [tokenAddress, quotedMinimumOut],
);
const inputs = [encodeAbiParameters(
  [{ type: "bytes" }, { type: "bytes[]" }],
  ["0x060c0f", [swap, settle, take]],
)];

await walletClient.writeContract({
  address: "ROUTER_ADDRESS",
  abi: universalRouterAbi,
  functionName: "execute",
  args: ["0x10", inputs, deadline],
  value: amountIn,
});
sell-token.ts
import { encodeAbiParameters, maxUint256, parseEther, zeroAddress } from "viem";

const amountIn = parseEther("1000000");
const permit2 = "0x000000000022D473030F116dDEE9F6B43aC78BA3";

await walletClient.writeContract({
  address: tokenAddress,
  abi: erc20Abi,
  functionName: "approve",
  args: [permit2, maxUint256],
});

await walletClient.writeContract({
  address: permit2,
  abi: permit2Abi,
  functionName: "approve",
  args: [tokenAddress, "ROUTER_ADDRESS", (1n << 160n) - 1n, permitExpiry],
});

const swap = encodeAbiParameters([{
  type: "tuple",
  components: [
    { name: "poolKey", type: "tuple", components: [
      { name: "currency0", type: "address" },
      { name: "currency1", type: "address" },
      { name: "fee", type: "uint24" },
      { name: "tickSpacing", type: "int24" },
      { name: "hooks", type: "address" },
    ]},
    { name: "zeroForOne", type: "bool" },
    { name: "amountIn", type: "uint128" },
    { name: "amountOutMinimum", type: "uint128" },
    { name: "minHopPriceX36", type: "uint256" },
    { name: "hookData", type: "bytes" },
  ],
}], [{
  poolKey,
  zeroForOne: false,
  amountIn,
  amountOutMinimum: quotedMinimumEthOut,
  minHopPriceX36: 0n,
  hookData: keyRecipientData,
}]);
const settle = encodeAbiParameters(
  [{ type: "address" }, { type: "uint256" }],
  [tokenAddress, maxUint256],
);
const take = encodeAbiParameters(
  [{ type: "address" }, { type: "uint256" }],
  [zeroAddress, quotedMinimumEthOut],
);
const inputs = [encodeAbiParameters(
  [{ type: "bytes" }, { type: "bytes[]" }],
  ["0x060c0f", [swap, settle, take]],
)];

await walletClient.writeContract({
  address: "ROUTER_ADDRESS",
  abi: universalRouterAbi,
  functionName: "execute",
  args: ["0x10", inputs, deadline],
});
RUSHPOT hook

Read and claim winnings

Read both live rounds directly from the hook. Winnings are pull-based, so the winner claims them from their own wallet after settlement.

rewards.ts
const traderRound = await publicClient.readContract({
  address: "HOOK_ADDRESS",
  abi: rewardLaunchpadHookAbi,
  functionName: "getCurrentRound",
  args: [0],
});

const creatorRound = await publicClient.readContract({
  address: "HOOK_ADDRESS",
  abi: rewardLaunchpadHookAbi,
  functionName: "getCurrentRound",
  args: [1],
});

const claimable = await publicClient.readContract({
  address: "HOOK_ADDRESS",
  abi: rewardLaunchpadHookAbi,
  functionName: "pendingWinnings",
  args: [account],
});

await walletClient.writeContract({
  address: "HOOK_ADDRESS",
  abi: rewardLaunchpadHookAbi,
  functionName: "claimWinnings",
});