Skip to main content

Buy & Sell

One request, one unsigned transaction back, signed and sent by your own script. The snippet below is complete: set the key, the token and the amount, and run it.

Flap
four.meme
PancakeSwap

One endpoint for every Flap and four.meme token on BNB Chain, wherever it lives:

  • On the Flap bonding curve - from launch until 800M tokens are sold.
  • On the four.meme bonding curve - from launch until the raise (18 BNB, or the equivalent in USDT, USD1 or a stock) is complete.
  • On PancakeSwap - after graduation, in the pool the launchpad migrated it to.

You send the token address; the API asks both launchpads whose it is, reads its state and routes accordingly, reporting protocol as FLAP or FOURMEME and the venue as flap_curve, fourmeme_curve or pancakeswap. Tax tokens need no special handling - their tax is already inside the quote.

What you need​

Example​

const { Wallet } = require("ethers");

// ─── change these three ───────────────────────────────
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY";
const TOKEN = "0xTHE_TOKEN_ADDRESS";
const AMOUNT = "0.01"; // to buy: BNB to spend. To sell: "1000" tokens, or "100%"
const ACTION = "buy"; // "buy" or "sell"
const SLIPPAGE = 5; // %, how far the price may move against you
// ──────────────────────────────────────────────────────

async function main() {
const wallet = new Wallet(PRIVATE_KEY); // signs only; no node needed

const res = await fetch("https://api.shrine.trade/bnb/api/local-trade", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
action: ACTION,
token: TOKEN,
amount: AMOUNT,
slippage: SLIPPAGE,
from: wallet.address,
}),
});

const data = await res.json();
if (data.error) throw new Error(`${data.error}: ${data.message}`);
console.log("you should get about", data.quote.expectedOutFormatted,
ACTION === "buy" ? "tokens" : data.receive);

// Sign locally and hand the signed bytes to the API to broadcast - the key
// never leaves this script, and you need no RPC of your own.
for (const tx of data.txs) {
const signed = await wallet.signTransaction({
to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas),
maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas),
nonce: tx.nonce, chainId: tx.chainId, type: 2,
});
const sent = await (await fetch("https://api.shrine.trade/bnb/api/send", {
method: "POST", headers: { "content-type": "application/json" },
body: JSON.stringify({ signedTx: signed }),
})).json();
if (sent.error) throw new Error(`${sent.error}: ${sent.message}`);
if (sent.status !== "landed") throw new Error(`${tx.description} ${sent.status}: ${sent.explorer}`);
console.log(tx.description + ": " + sent.explorer);
}

if (ACTION === "buy") {
console.log(`bought ${data.name} (${data.symbol}) ${data.token} for ${data.amountInFormatted} ${data.payWith}`);
} else {
console.log(`sold ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} for ${data.quote.expectedOutFormatted} ${data.receive}`);
}
}

main();

Save it as trade.js, then:

npm install ethers
node trade.js

Whatever the API returns, the script sends in sequence. A buy is a single transaction. The first sell of a given token is two: a one-time approval, then the sell itself.

Trades are front-run protected: the on-chain minOut guarantees the fill is never worse than your slippage allows, and the signed transaction is broadcast through our own endpoint via /api/send, not a public node, so you need no RPC of your own.

Buy quotas

Some Flap tokens cap how much one wallet may buy on the curve. Your quote already reflects your remaining allowance; a buy past it is filled up to the cap and the rest of your BNB is refunded in the same transaction. Token Info shows the cap and what you have left.

Selling​

Switch ACTION to "sell". For the amount, give either a token count or a percentage of the wallet's balance:

AMOUNTSells
"1000"1000 tokens
"50%"half your balance
"100%"everything

Proceeds arrive in BNB, whatever the token is priced in, whenever Flap can convert on the way out. receive in the response says which asset you end up with.

Tax tokens​

Most Flap launches are tax tokens: the creator takes a percentage of every buy and sell. The tax is applied inside the quote, so expectedOut is what you actually receive - on the curve it is an extra fee on the trade, after graduation it is taken from the tokens as they move through the pool. creatorTaxBps in the response is the rate on your side of the trade. Nothing changes in the script.

Tokens priced in USD1, stocks or other assets​

Flap lets a launch be priced in USD1, a tokenised stock (NVDAB, TSLAB, SPYB, XAUT and more - see Supported quote assets), or another Flap token instead of BNB. Nothing changes in the script: AMOUNT on a buy is always BNB, and Flap swaps it into the quote asset inside the transaction. quoteAsset says what the token is priced in and payWith what left your wallet.

Where Flap cannot swap on the way in (quoteAssetRequired), buy with the asset itself: hold it and send payWithQuote: true with amount in that asset. Selling such a token pays out the quote asset; send receiveQuote: true to insist on it for any token.

four.meme tokens​

The same request trades a four.meme token; the response comes back with protocol: "FOURMEME" and the venue fourmeme_curve or pancakeswap. What is different about four.meme:

  • Quote assets. A four.meme curve is priced in BNB, USDT, USD1 or one of Binance's tokenised stocks (BNCB, DJTB, QQQB and more). A buy is still in BNB: four.meme's own Helper swaps it into the quote asset inside the transaction. To pay with the asset itself, hold it and send payWithQuote: true.
  • Sells pay out the quote asset. A token priced in BNB sells for BNB; one priced in USDT sells for USDT, and so on. receive in the response says which.
  • four.meme's fees are in the quote. The 1% trading fee (0.001 BNB minimum), the opening anti-sniper fee that some launches charge for their first blocks, and a tax token's tax are all already taken out of expectedOut. curveFeeBps is the fee this trade pays right now, so an anti-sniper launch shows a high number that falls block by block; Token Info has the same figure as currentBuyFeeBps for polling.
  • Amounts are whole gwei. four.meme rejects token amounts that are not multiples of 1e9 base units; a sell amount is rounded down to one, which amountIn reflects.
  • Older tokens. four.meme tokens created before September 2024 (its V1 manager) can be read but not traded on their curve: unsupported_version. Once graduated they trade on PancakeSwap like any other.

If it doesn't work​

ErrorWhat to do
insufficient_fundsAdd BNB to the wallet - the amount plus a little for gas.
insufficient_balanceThe sell is bigger than the balance. "100%" always fits.
token_not_foundNeither Flap nor four.meme knows this address. Make sure it is the token contract, not the PancakeSwap pool.
slippage_exceededThe price ran away between quote and send. Retry, with a higher SLIPPAGE on a busy token.
buy_quota_exhaustedThis wallet has bought all it may of this token on the curve.
quote_asset_requiredThe token is priced in an asset the launchpad can't swap BNB into. Hold it and set payWithQuote.
unsupported_versionA four.meme V1 token (pre-September 2024) still on its curve. Not tradeable here until it graduates.

Full list on Errors.

Sending​

POST https://api.shrine.trade/bnb/api/send takes one signed transaction and broadcasts it through our BNB Chain endpoint, so the scripts need no RPC at all. It only forwards transactions this API built - Flap and four.meme trades, launches, approvals and claims - and refuses anything else with not_ours.

Field
signedTx0x-hexThe signed transaction, as wallet.signTransaction returns it.
waitboolean, optionalDefault true: wait for the receipt. false returns the hash as soon as the node accepts it.
{ "hash": "0x…", "status": "landed", "blockNumber": 120162431, "gasUsed": 514058, "explorer": "https://bscscan.com/tx/0x…" }

status is landed, reverted, or pending (not waited for, or not mined within 45 seconds - stuck on nonce or gas).

Request and response

POST https://api.shrine.trade/bnb/api/local-trade

Request

Field
action"buy" or "sell"
tokenaddressThe Flap or four.meme token.
amountdecimal stringOn a buy, the BNB to spend regardless of the token's quote asset. On a sell, a token count such as "1000", or a percentage of the balance such as "50%" or "100%".
fromaddressYour wallet.
slippagenumber, optionalIn percent. 5 when omitted.
payWithQuoteboolean, optionalBuy only, tokens priced in an ERC-20: pay with that asset; amount is then in it.
receiveQuoteboolean, optionalSell only, tokens priced in an ERC-20: receive that asset instead of BNB.

Response - a real one, a buy of a tax token for 0.001 BNB on its curve:

{
"action": "buy",
"protocol": "FLAP",
"token": "0x2f1952E00F6BA7655993120B8c41E5ab511e7777",
"name": "星际巨舰",
"symbol": "星际巨舰",
"status": "Tradable",
"venue": "flap_curve",
"amountIn": "1000000000000000",
"amountInFormatted": "0.001",
"quoteAsset": {
"address": "0x0000000000000000000000000000000000000000",
"symbol": "BNB",
"decimals": 18,
"isNative": true
},
"payWith": "BNB",
"receive": "TOKEN",
"quote": {
"expectedOut": "160442982903129676642962",
"expectedOutFormatted": "160442.982903129676642962",
"minOut": "152420833757973192810813",
"curveFeeBps": 125,
"creatorTaxBps": 1000,
"shrineFeeBps": 50,
"slippagePct": 5.0
},
"txs": [
{
"to": "0x799924b88883cD9436C8B0dfc51660147C8Bcd7C",
"data": "0x…",
"value": "1000000000000000",
"gas": 521904,
"maxFeePerGas": "62500000",
"maxPriorityFeePerGas": "50000000",
"nonce": 5,
"chainId": 56,
"type": 2,
"description": "buy"
}
]
}
  • txs - the transactions to sign and broadcast, in this order. The three wei-denominated fields (value, maxFeePerGas, maxPriorityFeePerGas) are decimal strings so they survive JSON; everything else is a plain number. description labels each: buy, sell, or a one-time approve / approve_quote.
  • name / symbol - read from the token contract, for logging what was traded.
  • protocol - FLAP or FOURMEME, whichever launchpad the token came from. status - Tradable on the curve, DEX after graduation. venue - flap_curve, fourmeme_curve or pancakeswap. The request is the same in every case.
  • quoteAsset - what the token is priced in: BNB, or an ERC-20. payWith / receive - what actually left or reached your wallet (BNB, the quote symbol, or TOKEN).
  • amountIn - what you spend, base units: wei of BNB on a buy, tokens on a sell.
  • quote.expectedOut - the amount you should end up with once Flap's fee, the token's tax and ours are all taken. minOut is that figure less your slippage, and it is the floor the contract enforces. Both are base units; use the *Formatted twins for display.
  • quote fees - curveFeeBps is the launchpad's fee on the curve (Flap's 1.25%; four.meme's 1%, or its current anti-sniper fee; 0 once graduated - PancakeSwap's LP fee applies instead), creatorTaxBps the token's tax on this side, shrineFeeBps ours (50 = 0.5%).