Create a New Coin
Launch your own playable token on Forest Protocol.
Launch your own playable token on Forest Protocol.
HTML templates run inside an iframe on the token page. Use Forest's postMessage interface to read the connected wallet address, request swap quotes, and ask the parent page to submit swaps through the user's wallet.
You do not need to install a package. Your HTML app talks to Forest with browser messages.
| Capability | What it does |
|---|---|
| Wallet events | Read the connected wallet address and react to disconnects. |
| Swap quotes | Preview buy/sell output, balance, price impact, liquidity depth, and fees. |
| Buy requests | Ask Forest to submit a buy transaction through the connected wallet. |
| Sell requests | Ask Forest to submit a sell transaction through the connected wallet. |
Add this bridge to your HTML app:
let wallet = null;let latestSnapshot = null;function requestId() {if (crypto.randomUUID) return crypto.randomUUID();return `${Date.now()}-${Math.random().toString(16).slice(2)}`;}function callForest(method, params = {}) {const id = requestId();window.parent.postMessage({type: "FOREST_RPC_REQUEST",version: 1,id,method,params,},"*");return id;}window.addEventListener("message", (event) => {const data = event.data || {};if (data.type === "FOREST_WALLET_CONNECTED") {wallet = data.walletAddress;callForest("forest.swap.quote", { amount: "0.05", direction: "buy" });return;}if (data.type === "FOREST_WALLET_DISCONNECTED") {wallet = null;latestSnapshot = null;return;}if (data.type !== "FOREST_RPC_RESPONSE") return;if (data.result && data.result.snapshot) {latestSnapshot = data.result.snapshot;}if (data.status === "hash") {console.log("Transaction submitted:", data.result && data.result.txHash);}if (data.status === "success") {console.log("Forest request complete:", data.result && data.result.txHash);}if (data.status === "error") {console.error(data.error && data.error.code, data.error && data.error.message);}});window.parent.postMessage({ type: "FOREST_REQUEST_WALLET" }, "*");
forest.swap.buy or forest.swap.sell when the user confirms.success, request another quote to refresh balances.if (response.status === "success") {setTimeout(() => {callForest("forest.swap.quote", {amount: currentAmount,direction: currentDirection,});}, 750);}
Forest sends wallet messages to your iframe. Your app can also request the latest wallet state.
| Message | Direction | Purpose |
|---|---|---|
FOREST_REQUEST_WALLET | iframe to Forest | Ask Forest to send the current wallet state. |
FOREST_WALLET_CONNECTED | Forest to iframe | Provides the connected wallet address. |
FOREST_WALLET_DISCONNECTED | Forest to iframe | Tells your app that no wallet is connected. |
Request the current wallet state:
window.parent.postMessage({ type: "FOREST_REQUEST_WALLET" }, "*");
Handle wallet state:
window.addEventListener("message", (event) => {const data = event.data || {};if (data.type === "FOREST_WALLET_CONNECTED") {wallet = data.walletAddress;}if (data.type === "FOREST_WALLET_DISCONNECTED") {wallet = null;}});
Only the public wallet address is exposed. Forest does not send auth tokens, private keys, cookies, or session data to the iframe.
All Forest RPC calls use this request envelope:
{type: "FOREST_RPC_REQUEST",version: 1,id: "unique-request-id",method: "forest.swap.quote",params: {}}
| Field | Required | Description |
|---|---|---|
type | yes | Always FOREST_RPC_REQUEST. |
version | yes | Use 1. |
id | yes | Unique request id. Responses use the same id. |
method | yes | Forest method name. |
params | yes | Method-specific params. Use {} if there are none. |
Forest replies with:
{type: "FOREST_RPC_RESPONSE",version: 1,id: "same-request-id",status: "pending",result: {},error: undefined}
| Status | Meaning |
|---|---|
pending | Forest accepted the request and is preparing, quoting, or submitting. |
hash | A transaction hash is available, but the transaction is not confirmed yet. |
success | The request completed. For swaps, the transaction receipt has confirmed. |
error | The request failed. Read error.code and error.message. |
Pending responses may include result.stage:
"accepted" | "configured" | "warming" | "quoting" | "quoted" | "submitting";
forest.swap.quoteGets a read-only quote and snapshot. This does not open the wallet or submit a transaction.
callForest("forest.swap.quote", {amount: "0.05",direction: "buy",slippage: 0.5,});
| Param | Required | Description |
|---|---|---|
amount | yes | Positive decimal string or number. |
direction | yes | buy or sell. |
slippage | no | Percent slippage. Forest uses its default when omitted. |
forest.swap.buySubmits a buy transaction through the connected wallet. amount is the amount of the pay token to spend.
callForest("forest.swap.buy", {amount: "0.05",slippage: 0.5,});
forest.swap.sellSubmits a sell transaction through the connected wallet. amount is the amount of the launched token to sell.
callForest("forest.swap.sell", {amount: "100",slippage: 0.5,});
Quote and swap responses can include result.snapshot. Store the latest snapshot and render your UI from it.
{direction: "buy",slippage: 0.5,payToken: {symbol: "BNB",balance: 1.25,locked: 0},receiveToken: {symbol: "TOKEN"},quote: {payAmount: 0.05,receiveAmount: 1234.56,receivePerPay: 24691.2,payPerReceive: 0.0000405},priceImpact: 1.2,liquidityDepth: 8.7,swapBreakdown: {steps: [],totalEffectiveFee: 0.01,expectedOutput: 1234.56}}
Calculate spendable balance from the snapshot:
const available = snapshot.payToken.balance - (snapshot.payToken.locked || 0);
Handle error responses as first-class UI states. The user may reject a wallet request, the quote may fail, or the token may not support swaps.
if (data.status === "error") {showError(data.error.code, data.error.message);}
Common error codes include:
| Code | Meaning |
|---|---|
WALLET_NOT_CONNECTED | The user must connect a wallet before this action. |
QUOTE_FAILED | Forest could not quote the requested amount. |
SWAP_UNAVAILABLE | This token cannot be swapped through the current route. |
CONFIG_TIMEOUT | Direction or slippage did not apply in time. |
Treat incoming messages as untrusted until you verify their type and shape. Keep request ids unique. Do not assume your iframe can access parent-page storage, wallet providers, or cookies. Forest-owned actions should always go through this message interface.