Skip to main content

Create Token

POST https://api.shrine.trade/evm/api/create-token

Builds the Pons launch transaction for you: metadata, launch config, the pinned economics hash, and — if you want one — a dev buy in the same transaction. You sign and send it; the token and its bonding curve exist as soon as it confirms.

shrine.trade takes no fee on creation. The transaction value covers Pons's own launch fee (plus your dev buy, if any).

Pons

Launching is Pons v2 only: the bonding curve, graduating to Uniswap v4 on its own once it sells out. Pons v1 launches are not offered (v1 is superseded), though v1 tokens still buy and sell here.

About the private key field

The key never leaves your machine. It signs locally and the signed transaction goes straight to the RPC you included in the api request; it is never sent to shrine.trade.

Uploading happens first: Build waits for the image to finish pinning to IPFS, so the token's logo is set the moment it launches rather than being patched in afterwards.

Example

const { readFileSync } = require("node:fs");
const { JsonRpcProvider, Wallet, id, getAddress, dataSlice } = require("ethers");

// ─── your token ───────────────────────────────────────
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY";
const NAME = "Grene";
const SYMBOL = "GRENE";
const IMAGE = "./logo.png"; // image file, next to this script
const DESCRIPTION = "the greenest coin on Robinhood Chain";

// ─── links — all optional, "" to leave one out ────────
const TWITTER = "https://x.com/grene";
const TELEGRAM = "";
const DISCORD = "";
const WEBSITE = "https://grene.example";
const FARCASTER = "";

// ─── economics ────────────────────────────────────────
const PAIR_TOKEN = "ETH"; // what buyers pay with: ETH, USDG, NVDA, MSTR, …
const DEV_BUY = ""; // your own opening buy, in ETH. "" = none
const CREATOR_TAX = 0; // % of every trade you earn, 0–10. Fixed at launch
const FEE_RECIPIENT = ""; // where your fees go. "" = the launching wallet
const EXEMPTIONS = []; // wallets that skip the opening snipe tax.
// Max 32, or 31 when you take a dev buy
const BUYBACK = false; // route creator fees into buybacks
// ──────────────────────────────────────────────────────

async function main() {
const provider = new JsonRpcProvider("https://rpc.mainnet.chain.robinhood.com", 4663);
const wallet = new Wallet(PRIVATE_KEY, provider);

// 1. Upload the image. We pin it to IPFS and hand back a hosted URL.
const form = new FormData();
form.append("file", new Blob([readFileSync(IMAGE)], { type: "image/png" }), "logo.png");
form.append("name", NAME);
form.append("symbol", SYMBOL);
form.append("description", DESCRIPTION);

const up = await fetch("https://api.shrine.trade/evm/api/upload-image", {
method: "POST",
body: form,
});
const uploaded = await up.json();
if (uploaded.error) throw new Error(`${uploaded.error}: ${uploaded.message}`);
console.log("image pinned:", uploaded.image);

// 2. Ask shrine.trade to build the launch transaction.
const res = await fetch("https://api.shrine.trade/evm/api/create-token", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
name: NAME,
symbol: SYMBOL,
description: DESCRIPTION,
logo: uploaded.image,
socials: { twitter: TWITTER, telegram: TELEGRAM, discord: DISCORD,
website: WEBSITE, farcaster: FARCASTER },
pairToken: PAIR_TOKEN,
creatorTaxBps: CREATOR_TAX * 100,
buybackEnabled: BUYBACK,
// Left out entirely when empty - the API picks sane defaults.
...(DEV_BUY ? { initialBuy: DEV_BUY } : {}),
...(EXEMPTIONS.length ? { snipeTaxExemptions: EXEMPTIONS } : {}),
...(FEE_RECIPIENT ? { creatorFeeRecipient: FEE_RECIPIENT } : {}),
from: wallet.address,
}),
});
const body = await res.json();
if (body.error) throw new Error(`${body.error}: ${body.message}`);
console.log("launch fee", body.launchFeeFormatted, "ETH");

// 3. Sign locally - your private key never leaves this script.
// 4. Submit through your own RPC. A dev buy in an ERC-20 needs an approval
// first, so send whatever comes back, in order.
let receipt, hash;
for (const tx of body.txs) {
const sent = await wallet.sendTransaction({
to: tx.to,
data: tx.data,
value: BigInt(tx.value), // launch fee (+ dev buy) in wei
gasLimit: BigInt(tx.gas),
maxFeePerGas: BigInt(tx.maxFeePerGas),
maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas),
nonce: tx.nonce,
chainId: tx.chainId,
type: tx.type,
});
hash = sent.hash;
receipt = await sent.wait();
}

// 5. Read the new addresses out of the TokenLaunched event.
const topic0 = id("TokenLaunched(address,address,address,address,uint256,uint256)");
const log = receipt.logs.find((l) => l.topics[0] === topic0);
console.log("token launched:", getAddress(dataSlice(log.topics[1], 12)));
console.log("curve:", getAddress(dataSlice(log.topics[2], 12)));
console.log("tx:", "https://robinscan.io/tx/" + hash);
}

main();

Save it as launch.js, put your image next to it as logo.png, then:

npm install ethers
node launch.js

Supported quote assets

A Pons token can be priced in ETH or in one of Robinhood Chain's tokenised assets. Pass the ticker as pairToken - "MSTR", "USDG", "NVDA" - or the address if you prefer; both work, and tickers are case-insensitive.

Whatever you pick is fixed at launch and is what buyers pay with. The launch fee itself is always ETH.

TickerDecimalsAddress
ETH18native ETH — no address
USDG60x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
SPCX180x4a0E65A3EcceC6dBe60AE065F2e7bb85Fae35eEa
NVDA180xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC
RDDT180x05b37Fb53A299a1b874A619e1c4C404D52C36F4C
AMZN180x12f190a9F9d7D37a250758b26824B97CE941bF54
DJT180x1D11f0496982706C5e14A514D4E79F2e6BdE4516
TTWO180x5e81213613b6B86EaB4c6c50d718d34359459786
GME180x1b0E319c6A659F002271B69dB8A7df2F911c153E
SPY180x117cc2133c37B721F49dE2A7a74833232B3B4C0C
AAPL180xaF3D76f1834A1d425780943C99Ea8A608f8a93f9
MSFT180xe93237C50D904957Cf27E7B1133b510C669c2e74
COIN180x6330D8C3178a418788dF01a47479c0ce7CCF450b
TSLA180x322F0929c4625eD5bAd873c95208D54E1c003b2d
QQQ180xD5f3879160bc7c32ebb4dC785F8a4F505888de68
PLTR180x894E1EC2D74FFE5AEF8Dc8A9e84686acCB964F2A
cbBTC80xCEC185eB182c47d1bA1EFc84e6959e18cd620Be4
GOOGL180x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3
GLD180xC9a981FEE1F9DEc688bb123ccDeCc63D0deBFC4e
META180xc0D6457C16Cc70d6790Dd43521C899C87ce02f35
CRCL180xdF0992E440dD0be65BD8439b609d6D4366bf1CB5
COST180x4EA005168D7F09a7A0Ba9D1DEf21a479950E44C2
MSTR180xec262a75e413fAfD0dF80480274532C79D42da09
AMD180x86923f96303D656E4aa86D9d42D1e57ad2023fdC
SNDK180xB90A19fF0Af67f7779afF50A882A9CfF42446400
BB180x48E39E56aCdbA37b09020C0b734A613C9a2f100A
MU180xfF080c8ce2E5feadaCa0Da81314Ae59D232d4afD
HIMS180xCceE82fE024c36fA15E1005edE3E9e4787e23D09

Pons scales each curve's economics into its quote asset, so the graduation threshold differs per asset - 4.2 ETH, 8090 USDG, 41.6 NVDA. create-token returns the one that applies as graduationThreshold.

Request

FieldTypeDescription
namestringToken name. Not unique — always identify tokens by address.
symbolstringTicker.
descriptionstringProject description.
socialsobject{ twitter, telegram, discord, website, farcaster } — any may be "".
logostring, optionalHosted image URL. The scripts above pin your image file to IPFS and fill this in for you.
creatorFeeRecipientaddress, optionalWhere creator fees are paid. Defaults to from.
snipeTaxExemptionsstring[], optionalUp to 32 wallets that skip the opening snipe tax (31 with an initialBuy - the dev-buy wallet takes one slot on-chain). In the form above, separate them with commas (spaces and new lines work too). Your own sniper, a partner, whoever. Fixed at launch and never changeable.
creatorTaxBpsnumber, optionalExtra creator tax on every trade, in basis points. Capped by Pons at 10%; immutable after launch. Default 0.
buybackEnabledboolean, optionalRoute the creator's fee share into token buybacks (vested). Default false.
launchConfigIdnumber, optionalWhich Pons launch config to use. Only config 0 exists today and it is the default, so leave it out.
pairTokenstring, optionalWhat the curve is priced in. "ETH" (default) or the address of an approved quote asset — USDG, NVDA, SPCX, GME, cbBTC and the rest of Robinhood Chain's tokenised assets. An asset Pons hasn't approved returns pair_token_not_approved.
initialBuydecimal string, optionalYour own opening buy, in the same transaction, in ETH whatever the token is priced in. On a USDG or NVDA launch the API works out how much of that asset the ETH buys (initialBuy in the response, initialBuyEth echoes your figure); your wallet's own holding of the asset is used first and only the shortfall is swapped, with a buy_quote_with_eth transaction in front. Your wallet is exempt from the snipe tax on this buy, and there is no slippage to set on the buy itself: it runs inside the transaction that creates the curve, so nobody can trade ahead of it.
salt32-byte hex, optionalCREATE2 salt. Lets you know the token address before launching. Random if omitted.
fromaddressYour wallet (deployer).

What a launch costs

Two numbers matter, and they are not the same:

plain launch+ 0.001 dev buy
ETH you must hold~0.0026~0.0036
ETH actually spent~0.0019~0.0029

The gap is not a fee. A node reserves gasLimit x maxFeePerGas for the whole transaction before it runs, and neither figure is what gets used: the limit is padded 20% above the estimate, and the price is a ceiling set at 1.25x the current base fee, not the rate. Unused gas is never taken - you get the difference back in the same block.

So budget around 0.003 ETH on Robinhood Chain for a plain launch, plus your dev buy. A wallet holding exactly the launch fee plus the expected gas will be rejected, which is not a bug. The ceiling is deliberately tight: if the base fee climbs more than 25% between quoting and sending, the node rejects the transaction and you request a fresh one.

Of what is spent, 0.0005 is Pons's launch fee and the rest is gas. shrine.trade takes nothing on creation.

Response

A real one, for a launch with a 0.001 ETH dev buy:

{
"txs": [
{
"to": "0xe33E9E479dF8802cb0866d5d05258bEc4cF62948",
"data": "0x\u2026",
"value": "1500000000000000",
"gas": 4600821,
"maxFeePerGas": "581672501",
"maxPriorityFeePerGas": "1",
"nonce": 5,
"chainId": 4663,
"type": 2,
"description": "launch_and_buy"
}
],
"launchFee": "500000000000000",
"launchFeeFormatted": "0.0005",
"expectedEconomics": "0xa9fc75d4203a33fe660e8fa32c74c3aa41c1fda4bf23d3a39b6bc22a1f8b1ca7",
"launchConfigId": 0,
"pairToken": "ETH",
"pairTokenSymbol": "ETH",
"pairTokenDecimals": 18,
"graduationThreshold": "4200000000000000000",
"graduationThresholdFormatted": "4.2",
"salt": "0x\u2026",
"creatorFeeRecipient": "0x7b444D22f099Fd238210161791dE26d16c3cEdf2",
"creatorTaxBps": 100,
"snipeTaxExemptions": [],
"initialBuy": "1000000000000000",
"expectedTokensOut": "582993253935204464062630",
"minTokensOut": "553843591238444240859498"
}
  • txs - sign and send in order. Usually one: launch (plain) or launch_and_buy (with a dev buy). A dev buy in an ERC-20 pair token can put buy_quote_with_eth (if the wallet is short of it) and approve_quote in front.
  • launchFee - Pons's fee, always ETH, read from the factory at request time. The transaction's value is this plus an ETH dev buy.
  • pairToken, pairTokenSymbol, pairTokenDecimals - what the curve is priced in. graduationThreshold is how much of it the curve must take in before it graduates; Pons scales it per asset.
  • expectedEconomics - the launch config's economics hash, pinned into the transaction so the terms can't change between quote and landing.
  • salt - yours, or the random one we picked. creatorFeeRecipient, creatorTaxBps, snipeTaxExemptions echo what the launch will use.
  • initialBuy, expectedTokensOut, minTokensOut - the dev buy in the pair token's base units and what it returns. Only with an initialBuy. On an ERC-20-priced launch initialBuyEth is the ETH you gave and initialBuy what it became.
  • quoteSwap - only when an ERC-20 dev buy needed a swap in front: what it buys, the ETH quoted and carried, and the pools.