UNPKG

four-flap-meme-sdk

Version:

SDK for Flap bonding curve and four.meme TokenManager

1,801 lines (1,359 loc) β€’ 99.8 kB
# four-flap-meme-sdk English Docs A two-in-one SDK for **four.meme** (TokenManager V1/V2/Helper3) and **Flap Protocol** (Portal/CDPV2). This comprehensive guide is designed for **complete beginners** – no prior experience with these platforms required. We'll explain every concept, method, and parameter in detail. ## Why This SDK? This SDK helps you: - **Launch tokens** on four.meme or Flap Protocol with just a few lines of code - **Trade tokens** using bonding curves (buy/sell before DEX listing) - **Query token state** and estimate prices - **Understand two DeFi platforms** that revolutionize token launches ## Runtime Requirements - **Node.js**: Version 18 or higher (uses native fetch API) - **Module Type**: ESM (NodeNext) - **Dependencies**: - `ethers@^6` - For Ethereum interactions ## Installation ```bash npm i four-flap-meme-sdk ethers ``` Optional (use Pinata for IPFS uploads) ```bash npm i pinata ``` --- ## Table of Contents ### πŸ“˜ Platform Overview - [What is four.meme?](#what-is-fourmeme) - [What is Flap Protocol?](#what-is-flap-protocol) - [Understanding Bonding Curves](#understanding-bonding-curves) - [Internal Market vs External Market](#internal-market-vs-external-market) ### 🎯 four.meme - [Platform Architecture](#fourmeme-architecture) - [Token Launch Process](#token-launch-process) - [One-click Launch (Easiest)](#one-click-token-launch) - [Step-by-Step Launch (Advanced)](#step-by-step-launch) - [Trading Tokens](#trading-on-fourmeme) - [Estimating Prices](#price-estimation) - [Buying Tokens](#buying-tokens) - [Selling Tokens](#selling-tokens) - [Auto-Routing (V1/V2)](#auto-routing) - [Error Handling](#error-handling) - [MPC-Exclusive Tokens](#mpc-exclusive-tokens) - [Complete API Reference](#fourmeme-api-reference) ### πŸš€ Flap Protocol - [Platform Architecture](#flap-architecture) - [Reading Token State](#reading-token-state) - [CDPV2 Bonding Curve](#cdpv2-bonding-curve) - [Price Quotes](#flap-price-quotes) - [Token Swapping](#token-swapping) - [Creating Tokens](#creating-tokens-on-flap) - [Vanity Addresses](#vanity-addresses) - [Uploading Token Metadata](#uploading-token-metadata) - [Error Handling](#flap-error-handling) - [Constants](#flap-constants) - [Complete API Reference](#flap-api-reference) ### πŸ” 48.club Private Transactions - [What is 48.club?](#what-is-48club) - [Private Transaction Benefits](#private-transaction-benefits) - [Four.meme Private Trading](#fourmeme-private-trading) - [Flap Protocol Private Trading](#flap-protocol-private-trading) - [48SP Modes & Configuration](#48sp-modes--configuration) - [Low-Level 48.club API](#low-level-48club-api) ### πŸ“š Appendix - [Constants & Addresses](#constants-and-addresses) - [BigInt & Units](#bigint-and-units) - [Common Patterns](#common-patterns) - [FAQ](#frequently-asked-questions) --- # Platform Overview ## What is four.meme? **four.meme** is a token launchpad that uses a **bonding curve** mechanism for price discovery before listing on decentralized exchanges (DEX). ### Key Concepts: 1. **Bonding Curve Phase**: - When a token is first created, it's NOT on a DEX - Instead, prices are determined by a mathematical formula (bonding curve) - As more people buy, the price automatically increases - As people sell, the price automatically decreases 2. **Migration to DEX**: - Once enough funds are raised (reaches threshold), the token "graduates" - It gets listed on PancakeSwap (for BSC) with a liquidity pool - After this, it trades like a normal DEX token 3. **Versions**: - **V1 (TokenManager)**: Original version, still in use - **V2 (TokenManager2)**: Improved version with more features - **Helper3**: A utility contract that helps estimate prices and route trades ### Why Use four.meme? - **Fair Launch**: Everyone buys at the same bonding curve price - **No Rug Pulls**: Liquidity is automatically added to DEX - **Early Access**: Buy before DEX listing at potentially lower prices --- ## What is Flap Protocol? **Flap Protocol** is another token launch platform with advanced bonding curve features (CDPV2 curve). ### Key Features: 1. **Advanced Bonding Curve (CDPV2)**: - More flexible curve parameters: `r`, `h`, `k` - Better price discovery - Customizable migration thresholds 2. **Multi-Chain Support**: - BSC (BNB Chain) - Base - X Layer - Morph 3. **Quote Token Options**: - Can launch with native tokens (BNB, ETH) - Can launch with quote tokens (USDT, etc.) 4. **Tax & Migrator Options**: - Set custom tax rates - Choose V2 or V3 migrators for DEX --- ## Understanding Bonding Curves ### What is a Bonding Curve? A **bonding curve** is a mathematical formula that determines token price based on supply. #### Simple Example: Imagine a token with this rule: - First 1000 tokens: $0.01 each - Next 1000 tokens: $0.02 each - Next 1000 tokens: $0.03 each - And so on... **Bonding curves** do this smoothly with a formula instead of steps. ### The Formula (CDPV2): ``` price = k / (1,000,000,000 + h - supply)Β² ``` Where: - `k`: A constant that affects overall price level - `h`: Height adjustment (shifts the curve) - `supply`: Current circulating supply ### Why It Matters: - **Early buyers**: Get lower prices - **Price increases**: Automatically as supply grows - **Predictable**: Anyone can calculate the price - **No manipulation**: Can't be front-run like DEX orders --- ## Internal Market vs External Market In token launch platforms, there are two important trading phase concepts: ### πŸ”΅ Internal Market (Bonding Curve Phase) **Definition**: The phase where tokens trade on the bonding curve before migrating to a DEX. **Characteristics**: - βœ… **Formula-based pricing**: Uses mathematical curves (like CDPV2) to calculate prices - βœ… **Locked liquidity**: All funds locked in the platform contract - βœ… **Rug-pull prevention**: Developers cannot withdraw liquidity - βœ… **Fair price discovery**: Everyone buys/sells at the same curve price - βœ… **Instant settlement**: No order book or counterparty needed - βœ… **Predictability**: Can precisely calculate buy/sell prices **On four.meme and Flap Protocol**: - Tokens start in the internal market phase when created - Trade using `FourClient` or `FlapPortalWriter` - Prices adjust automatically with buys/sells - Example: `status = 1` (tradable state) **Internal Market Trading Example**: ```typescript // Buy tokens on the internal market (bonding curve) const txHash = await writer.swapExactInput({ inputToken: ZERO_ADDRESS, outputToken: tokenAddress, inputAmount: parseEther('1.0'), minOutputAmount: minAmount, to: yourAddress }); ``` ### 🟒 External Market (DEX Phase) **Definition**: The phase where tokens have "graduated" and migrated to a decentralized exchange (DEX). **Characteristics**: - βœ… **Market pricing**: Price determined by supply/demand, no longer using curves - βœ… **DEX liquidity pools**: Trade on PancakeSwap, Uniswap, etc. - βœ… **Free trading**: Can trade on any supported DEX and aggregator - βœ… **Deeper liquidity**: Usually deeper liquidity with lower slippage - βœ… **Standard ERC20**: Trades like any normal token **Migration Conditions**: - four.meme: When raised funds reach a specific threshold (e.g., 24 BNB) - Flap Protocol: When reserve reaches `dexThresh` (configurable) **After Migration**: - Platform contract automatically adds liquidity to DEX - Bonding curve closes, can no longer trade through platform - Token status becomes `status = 4` (migrated to DEX) **External Market Trading Example**: ```typescript // Token has migrated to DEX, use DEX router for trading // For example, using Uniswap SDK or PancakeSwap SDK import { SwapRouter } from '@uniswap/v3-sdk'; // ... use standard DEX trading methods ``` ### πŸ“Š Internal Market vs External Market Comparison | Feature | Internal Market (Bonding Curve) | External Market (DEX) | |---------|----------------------------------|----------------------| | **Pricing Mechanism** | Mathematical formula (bonding curve) | Market supply/demand | | **Liquidity Source** | Platform contract | DEX liquidity pool | | **Trading Method** | Through platform contract | Through DEX (PancakeSwap/Uniswap) | | **Price Predictability** | High (can calculate precisely) | Low (market volatility) | | **Slippage** | Depends on curve parameters | Depends on liquidity depth | | **Phase** | Early stage | Mature stage | | **SDK Usage** | `FourClient` / `FlapPortalWriter` | DEX SDK (Uniswap/PancakeSwap) | | **Token Status** | `status = 1` | `status = 4` | ### πŸ”„ Migration Process from Internal to External Market 1. **Internal Market Phase**: Token trades on bonding curve 2. **Threshold Reached**: Reserve reaches migration threshold 3. **Automatic Migration**: Platform contract automatically triggers migration 4. **Add Liquidity**: Adds reserve and tokens to DEX 5. **External Market Phase**: Token freely trades on DEX **How to Check Which Phase a Token is In?** ```typescript import { FlapPortal } from 'four-flap-meme-sdk'; const portal = new FlapPortal({ chain: 'BSC', rpcUrl }); const state = await portal.getTokenV5(tokenAddress); if (state.status === 1) { console.log('βœ… Internal Market: Token trading on bonding curve'); console.log('Reserve:', state.reserve); console.log('Migration threshold:', state.dexSupplyThresh); } else if (state.status === 4) { console.log('βœ… External Market: Token has migrated to DEX'); console.log('Please trade on PancakeSwap/Uniswap'); } ``` **Important Notes**: - ⚠️ After token migrates to DEX, cannot trade through platform contract anymore - ⚠️ Migration is one-way and irreversible - ⚠️ After migration, must use DEX trading tools (like PancakeSwap, Uniswap) --- # πŸ”Ž Inspect token LP (auto-detect in-house vs DEX) Use `inspectTokenLP(token, opts)` to detect whether a token is traded on four (bonding curve), Flap (bonding curve), or Pancake V2/V3 (DEX). For DEX, it returns WBNB/USDT pairs and reserves; for in‑house platforms, it returns curve reserves/supply so the UI can display pool-like info. Minimal usage (BSC) ```typescript import { inspectTokenLP } from 'four-flap-meme-sdk'; const info = await inspectTokenLP('0xToken', { chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org', flapChain: 'BSC' }); console.log(info); ``` Optionally resolve factories via Routers ```typescript const info = await inspectTokenLP('0xToken', { chain: 'BSC', rpcUrl, routerV2: '0x10ED43C718714eb63d5aA57B78B54704E256024E', // Pancake V2 Router routerV3: '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4', // Pancake V3 Router // or pass factoryV2/factoryV3 directly }); ``` Return examples ```typescript // four (in-house) { platform: 'FOUR', four: { helper: '0x...', reserveNative: '123456...', offerTokens: '7890...', lastPrice: '1234...' } } // flap (in-house) { platform: 'FLAP', flap: { quoteToken: '0x...', reserveNative: '...', circulatingSupply: '...', price: '...' } } // Pancake V2 { platform: 'PANCAKE_V2', v2: { wbnbPair: { address: '0x...', reserveToken: '...', reserveWBNB: '...' }, usdtPair: { address: '0x...', reserveToken: '...', reserveUSDT: '...' } }} // Pancake V3 (multiple fee tiers) { platform: 'PANCAKE_V3', v3: [ { base: 'WBNB', fee: 500, pool: '0x...', tokenBalance: '...', baseBalance: '...' }, { base: 'USDT', fee: 2500, pool: '0x...', tokenBalance: '...', baseBalance: '...' } ]} ``` # four.meme Platform Guide ## four.meme Architecture four.meme has **three main components**: ### 1. **REST API** (Backend) - User authentication (nonce + signature) - Image upload for token icons - Token metadata management - Create parameter generation ### 2. **Smart Contracts** (On-Chain) - **TokenManagerV1**: Original token manager - **TokenManagerV2**: Improved token manager with more features - **TokenManagerHelper3**: Helper contract for price estimation and routing ### 3. **This SDK** (Your Interface) - Simplifies all REST API calls - Wraps smart contract interactions - Provides unified interfaces for V1/V2 --- ## Token Launch Process Launching a token on four.meme involves **5 steps**: ``` 1. Generate Nonce β†’ Get a random string from server 2. Sign Message β†’ Sign with your wallet to prove ownership 3. Login β†’ Receive access token 4. Upload Image β†’ Upload token logo/icon 5. Create On-Chain β†’ Deploy the token contract ``` ### Why This Process? - **Authentication**: Proves you own the wallet - **Security**: Access token prevents unauthorized actions - **Metadata**: Server stores token info off-chain - **Decentralization**: Actual token is on-chain, not controlled by server --- ## One-Click Token Launch ### The Easiest Way Use `createTokenFlow()` to handle all 5 steps automatically: ```typescript import { createTokenFlow } from 'four-flap-meme-sdk'; const result = await createTokenFlow({ rpcUrl: 'https://bsc-dataseed.binance.org', privateKey: '0x...your-private-key', networkCode: 'BSC', // Optional: provide pre-uploaded image URL imgUrl: 'https://...', // OR: upload new image image: imageBlob, payload: { name: 'My Awesome Token', // Full name shortName: 'MAT', // Symbol (ticker) desc: 'A revolutionary token', // Description label: 'Meme', // Category preSale: '0', // Pre-purchase amount: '0' = no buy, '0.5' = buy 0.5 BNB onlyMPC: false, // MPC-exclusive mode (explained later) // Optional social links webUrl: 'https://example.com', twitterUrl: 'https://twitter.com/...', telegramUrl: 'https://t.me/...', } }); console.log('Token created!'); console.log('Transaction:', result.txReceipt.transactionHash); console.log('Your address:', result.accountAddress); ``` ### Parameter Explanations: | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `rpcUrl` | string | βœ… | RPC endpoint for the blockchain (BSC, Arbitrum, etc.) | | `privateKey` | string | βœ… | Your wallet private key (KEEP SECRET!) | | `networkCode` | 'BSC' | βœ… | Currently only BSC is supported | | `baseUrl` | string | ❌ | four.meme API URL (default: https://four.meme/meme-api) | | `image` | Blob | ❌* | Image file to upload (*required if no imgUrl) | | `imgUrl` | string | ❌* | Pre-uploaded image URL (*required if no image) | ### Payload Fields: | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | βœ… | Token full name (e.g., "Bitcoin") | | `shortName` | string | βœ… | Token symbol (e.g., "BTC") | | `desc` | string | βœ… | Token description | | `label` | string | βœ… | Category: 'Meme', 'AI', 'Defi', 'Games', 'Infra', 'De-Sci', 'Social', 'Depin', 'Charity', 'Others' | | `preSale` | string | βœ… | BNB amount to buy when creating (pre-purchase). Examples: '0' = no buy, '0.1' = buy 0.1 BNB, '1' = buy 1 BNB | | `onlyMPC` | boolean | ❌ | If true, only MPC wallets can buy (anti-bot) | | `launchTime` | number | ❌ | Launch timestamp in milliseconds (default: now) | | `webUrl` | string | ❌ | Project website | | `twitterUrl` | string | ❌ | Twitter/X profile | | `telegramUrl` | string | ❌ | Telegram group/channel | ### Return Value: ```typescript { accountAddress: string, // Your wallet address accessToken: string, // JWT token for future API calls imgUrl: string, // Uploaded image URL api: { createArg: string, // Encoded parameters sent to contract signature: string, // Server signature for verification }, txReceipt: any // Transaction receipt from blockchain } ``` --- ## Step-by-Step Launch ### For Advanced Users If you need more control, use individual methods: ### Step 1: Generate Nonce ```typescript import { FourClient } from 'four-flap-meme-sdk'; const four = new FourClient(); const nonce = await four.generateNonce({ accountAddress: '0x...your-address', verifyType: 'LOGIN', networkCode: 'BSC' }); ``` **What it does**: Gets a random nonce (number used once) from server to prevent replay attacks. ### Step 2: Sign Login Message ```typescript import { buildLoginMessage } from 'four-flap-meme-sdk'; import { Wallet } from 'ethers'; const wallet = new Wallet(privateKey); const message = buildLoginMessage(nonce); // "You are sign in Meme {nonce}" const signature = await wallet.signMessage(message); ``` **What it does**: Creates a signed message proving you own the wallet. ### Step 3: Login to Get Access Token ```typescript const accessToken = await four.loginDex({ region: 'WEB', langType: 'EN', walletName: 'MetaMask', verifyInfo: { address: '0x...your-address', networkCode: 'BSC', signature: signature, verifyType: 'LOGIN' } }); ``` **What it does**: Exchanges your signature for an access token (like a session cookie). ### Step 4: Upload Image ```typescript const imgUrl = await four.uploadImage(accessToken, imageBlob); ``` **What it does**: Uploads token logo to four.meme's CDN, returns URL. ### Step 5: Get Create Parameters ```typescript const { createArg, signature } = await four.createToken(accessToken, { name: 'My Token', shortName: 'MTK', desc: 'Description', imgUrl: imgUrl, launchTime: Date.now(), label: 'Meme', lpTradingFee: 0.0025, // Fixed at 0.25% preSale: '0', onlyMPC: false, webUrl: 'https://...', twitterUrl: 'https://...', telegramUrl: 'https://...', }); ``` **What it does**: Server generates and signs the parameters for on-chain token creation. ### Step 6: Create Token On-Chain ```typescript import { createTokenOnChain } from 'four-flap-meme-sdk'; const receipt = await createTokenOnChain({ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org', signerPrivateKey: privateKey, args: createArg, signature: signature, }); console.log('Token created at tx:', receipt.transactionHash); ``` **What it does**: Sends transaction to TokenManager2 contract, deploying your token. --- ## Trading on four.meme Once a token is created, anyone can buy and sell it using the bonding curve. ### Trading Flow Overview ``` 1. Estimate Price (Optional) β†’ See how much you'll get 2. Check Approval (Sell Only) β†’ Allow TokenManager to spend your tokens 3. Execute Trade β†’ Buy or sell ``` --- ### Price Estimation **Before trading**, you should estimate the cost/return: #### Estimating Buy Price ```typescript import { tryBuy } from 'four-flap-meme-sdk'; // Option 1: Buy with specific BNB amount (funds) const estimate = await tryBuy( 'BSC', rpcUrl, tokenAddress, 0n, // amount = 0 means "buy by funds" 1n * 10n ** 18n // 1 BNB ); console.log('You will receive approximately:', estimate.estimatedAmount); console.log('Cost:', estimate.estimatedCost); console.log('Fee:', estimate.estimatedFee); // Option 2: Buy specific token amount const estimate2 = await tryBuy( 'BSC', rpcUrl, tokenAddress, 10_000n * 10n ** 18n, // Buy 10,000 tokens 0n // funds = 0 means "buy by amount" ); console.log('It will cost:', estimate2.estimatedCost, 'wei'); ``` **Return values explained**: ```typescript { tokenManager: string, // Which TokenManager contract to use (V1 or V2) quote: string, // Quote token address (usually WBNB) estimatedAmount: bigint, // Tokens you'll receive estimatedCost: bigint, // Total cost in wei (including fees) estimatedFee: bigint, // Trading fee in wei amountMsgValue: bigint, // BNB to send as msg.value amountApproval: bigint, // Amount to approve (if using quote token) amountFunds: bigint // Actual funds to use in contract call } ``` #### Estimating Sell Price ```typescript import { trySell } from 'four-flap-meme-sdk'; const estimate = await trySell( 'BSC', rpcUrl, tokenAddress, 1_000n * 10n ** 18n // Sell 1,000 tokens ); console.log('You will receive:', estimate.funds, 'wei'); console.log('Fee:', estimate.fee, 'wei'); ``` **Return values**: ```typescript { tokenManager: string, // Which TokenManager to use quote: string, // Quote token address funds: bigint, // BNB you'll receive (after fees) fee: bigint // Trading fee } ``` --- ### Buying Tokens There are **three ways** to buy tokens: #### Method 1: Simple Buy (Recommended) Use `tradeBuy()` which **auto-detects** V1 or V2: ```typescript import { tradeBuy } from 'four-flap-meme-sdk'; // Buy with specific BNB amount await tradeBuy( 'BSC', rpcUrl, privateKey, tokenAddress, { type: 'funds', // Buy by specifying funds funds: 1n * 10n ** 18n, // 1 BNB minAmount: 0n, // Minimum tokens to receive (slippage protection) to: yourAddress // Optional: send tokens to different address } ); // Buy specific token amount await tradeBuy( 'BSC', rpcUrl, privateKey, tokenAddress, { type: 'amount', // Buy specific amount amount: 10_000n * 10n**18n, // 10,000 tokens maxFunds: 5n * 10n ** 18n, // Maximum BNB to spend (slippage protection) to: yourAddress } ); ``` **Parameters explained**: - `type: 'funds'`: You specify how much BNB to spend - `type: 'amount'`: You specify how many tokens to buy - `minAmount`/`maxFunds`: Slippage protection (prevents bad trades if price changes) - `to`: Optional recipient address (defaults to your address) - `origin`: Optional origin code for referral tracking (default: 0n) #### Method 2: Direct Buy (Advanced) If you already know it's V2, use `buyTokenWithFunds()`: ```typescript import { tryBuy, buyTokenWithFunds } from 'four-flap-meme-sdk'; // First, estimate const estimate = await tryBuy('BSC', rpcUrl, tokenAddress, 0n, 1n * 10n ** 18n); // Then buy await buyTokenWithFunds( 'BSC', rpcUrl, privateKey, tokenAddress, estimate.amountFunds, // Use estimated funds 0n, // minAmount (slippage) yourAddress // recipient ); ``` #### Method 3: Using TM1/TM2 Classes (Expert) For maximum control: ```typescript import { TM2 } from 'four-flap-meme-sdk'; // Use chain enum (SDK handles contract address automatically) const tm2 = TM2.connectByChain('BSC', rpcUrl); // Buy by amount await tm2.buyToken( tokenAddress, 1_000n * 10n ** 18n, // Buy 1,000 tokens 2n * 10n ** 18n // Max 2 BNB ); // Buy by funds (AMAP = As Much As Possible) await tm2.buyTokenAMAP( tokenAddress, 1n * 10n ** 18n, // Spend 1 BNB 0n // Min 0 tokens (no slippage protection) ); ``` --- ### Selling Tokens Selling requires **token approval** first (letting TokenManager spend your tokens). #### Complete Sell Flow ```typescript import { ensureSellApproval, tradeSell } from 'four-flap-meme-sdk'; const tokenAddress = '0x...'; const amountToSell = 1_000n * 10n ** 18n; // 1,000 tokens // Step 1: Approve TokenManager to spend your tokens await ensureSellApproval( 'BSC', rpcUrl, privateKey, tokenAddress, yourAddress, amountToSell ); // Step 2: Sell await tradeSell( 'BSC', rpcUrl, privateKey, tokenAddress, { type: 'direct', amount: amountToSell, minFunds: 0n // Minimum BNB to receive } ); ``` **Why approval?** ERC20 tokens require **two transactions** to sell: 1. **Approve**: Give permission to TokenManager 2. **Sell**: Actually transfer and receive BNB This is a security feature of ERC20 tokens. #### Router Sell (For Third-Party Apps) If you're building a router/aggregator: ```typescript await tradeSell( 'BSC', rpcUrl, privateKey, tokenAddress, { type: 'router', from: userAddress, // Sell from user's wallet amount: amountToSell, minFunds: 0n, feeRate: 100n, // 1% fee (in basis points: 100 = 1%) feeRecipient: routerAddress // Where to send the fee } ); ``` --- ### Auto-Routing **What is auto-routing?** four.meme has two versions (V1 and V2) with **different interfaces**. The SDK provides unified methods that: 1. Detect which version a token uses 2. Call the correct contract 3. Handle parameter differences #### Using Auto-Routing ```typescript import { tradeBuy, tradeSell } from 'four-flap-meme-sdk'; // Works for BOTH V1 and V2 tokens await tradeBuy('BSC', rpcUrl, privateKey, token, params); await tradeSell('BSC', rpcUrl, privateKey, token, params); ``` **Behind the scenes**: 1. Calls `Helper3.getTokenInfo(token)` 2. Checks `version` field (1 or 2) 3. Routes to TM1 or TM2 4. Adapts parameters automatically --- ## Error Handling Trading on four.meme can fail for various reasons. The SDK provides error code parsing: ```typescript import { parseFourError } from 'four-flap-meme-sdk'; try { await tradeBuy(rpcUrl, privateKey, helper3, token, params); } catch (error) { const { code, message } = parseFourError(error); if (code === 'Slippage') { console.error('Price moved too much! Try increasing slippage tolerance'); } else if (code === 'More BNB') { console.error('Not enough BNB sent:', message); } else { console.error('Error:', code, message); } } ``` ### Error Codes Reference | Code | Description | Solution | |------|-------------|----------| | `GW` | Amount not aligned to GWEI | Round to GWEI (divide by 10^9) | | `ZA` | Target address is zero address | Provide valid recipient address | | `TO` | Cannot send to PancakePair | Don't use LP address as recipient | | `Slippage` | Price changed too much | Increase minAmount/maxFunds tolerance | | `More BNB` | Insufficient BNB in msg.value | Send more BNB or check estimate | | `FR` | Fee rate > 5% | Router fee rate must be ≀ 5% | | `SO` | Order too small | Increase trade amount | --- ## MPC-Exclusive Tokens **What is MPC-exclusive?** Some tokens on four.meme are marked as **"MPC-only"**, meaning: - Only **MPC wallets** (multi-party computation wallets) can buy them - This is an **anti-bot** feature - Regular EOA (externally owned account) wallets are blocked ### Why MPC-Exclusive? - **Prevents bots**: Bots usually use simple EOA wallets - **Fair launch**: Gives human users a better chance - **Less manipulation**: Harder to snipe or front-run ### How to Detect MPC-Exclusive Tokens #### On-Chain Detection (Recommended) ```typescript import { isExclusiveOnChain } from 'four-flap-meme-sdk'; const isMPCOnly = await isExclusiveOnChain({ chain: 'BSC', // SDK automatically uses the correct proxy contract tokenAddress: '0x...', rpcUrl: rpcUrl }); if (isMPCOnly) { console.log('This token is MPC-exclusive!'); console.log('You need an MPC wallet to trade it'); } ``` **How it works**: Checks the token's `template` field. If `template & 0x10000 > 0`, it's MPC-only. #### Off-Chain Detection (Using API) ```typescript import { isExclusiveOffChain, FourClient } from 'four-flap-meme-sdk'; const four = new FourClient(); const isMPCOnly = await isExclusiveOffChain( (addr) => four.getTokenByAddress(addr), tokenAddress ); ``` **How it works**: Checks if `version === 'V8'` in API response. --- ## four.meme API Reference ### FourClient Class #### Constructor ```typescript const four = new FourClient({ baseUrl?: string // Default: 'https://four.meme/meme-api' }); ``` --- ### Authentication Methods #### generateNonce() Gets a random nonce for login signature. ```typescript const nonce = await four.generateNonce({ accountAddress: string, // Your wallet address verifyType: 'LOGIN', // Fixed value networkCode: 'BSC' // Fixed value (for now) }); ``` **Returns**: `Promise<string>` - The nonce string --- #### buildLoginMessage() Builds the message to sign for login. ```typescript import { buildLoginMessage } from 'four-flap-meme-sdk'; const message = buildLoginMessage(nonce); // Returns: "You are sign in Meme {nonce}" ``` --- #### loginDex() Exchanges signature for access token. ```typescript const accessToken = await four.loginDex({ region: 'WEB', // Fixed value langType: 'EN' | 'ZH', // Language preference walletName: string, // e.g., 'MetaMask', 'WalletConnect' verifyInfo: { address: string, // Your wallet address networkCode: 'BSC', // Fixed value signature: string, // Signature from signing the nonce message verifyType: 'LOGIN' // Fixed value } }); ``` **Returns**: `Promise<string>` - JWT access token --- ### Token Management Methods #### uploadImage() Uploads token image to CDN. ```typescript const imgUrl = await four.uploadImage( accessToken: string, // From loginDex() file: Blob // Image file (JPEG, PNG, etc.) ); ``` **Returns**: `Promise<string>` - Image URL --- #### createToken() Gets signed parameters for on-chain token creation. ```typescript const { createArg, signature } = await four.createToken( accessToken: string, // From loginDex() { name: string, // Token full name shortName: string, // Token symbol desc: string, // Description imgUrl: string, // Image URL from uploadImage() launchTime: number, // Timestamp in milliseconds label: string, // Category (Meme, AI, etc.) lpTradingFee: 0.0025, // Fixed at 0.25% preSale: string, // Pre-sale amount (e.g., '0', '0.1') onlyMPC?: boolean, // MPC-exclusive flag webUrl?: string, // Optional website twitterUrl?: string, // Optional Twitter telegramUrl?: string // Optional Telegram } ); ``` **Returns**: `Promise<{ createArg: string, signature: string }>` --- #### getTokenByAddress() Gets token metadata by contract address. ```typescript const tokenInfo = await four.getTokenByAddress( address: string, // Token contract address accessToken?: string // Optional access token ); ``` **Returns**: Token metadata object with fields like `name`, `symbol`, `imgUrl`, `version`, etc. --- #### getTokenById() Gets token metadata by token ID. ```typescript const tokenInfo = await four.getTokenById( id: string | number, // Token ID from four.meme accessToken?: string // Optional access token ); ``` --- #### getPublicConfig() Gets four.meme platform configuration. ```typescript const config = await four.getPublicConfig(); ``` --- ### On-Chain Methods #### createTokenOnChain() Deploys the token contract on-chain. ```typescript import { createTokenOnChain } from 'four-flap-meme-sdk'; const receipt = await createTokenOnChain({ chain: 'BSC', // Chain name rpcUrl: string, // Blockchain RPC endpoint signerPrivateKey: string, // Your private key args: BytesLike, // From four.createToken() signature: BytesLike, // From four.createToken() valueWei?: bigint // Optional BNB to send (for pre-sale) }); ``` **Returns**: Transaction receipt --- ### Trading Methods #### tryBuy() Estimates buy cost without executing. ```typescript import { tryBuy } from 'four-flap-meme-sdk'; const estimate = await tryBuy( chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // Chain name rpcUrl: string, token: string, // Token address amount: bigint, // Token amount (0 = buy by funds) funds: bigint // BNB amount (0 = buy by amount) ); ``` **Returns**: `TryBuyResult` object with estimation details --- #### trySell() Estimates sell return without executing. ```typescript import { trySell } from 'four-flap-meme-sdk'; const estimate = await trySell( chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // Chain name rpcUrl: string, token: string, amount: bigint // Token amount to sell ); ``` **Returns**: `TrySellResult` with funds and fee --- #### buyTokenWithFunds() Buys tokens with specific BNB amount (V2 AMAP method). ```typescript import { buyTokenWithFunds } from 'four-flap-meme-sdk'; await buyTokenWithFunds( chain: 'BSC', // Chain name rpcUrl: string, signerPrivateKey: string, token: string, funds: bigint, // BNB amount to spend minAmount: bigint, // Minimum tokens to receive to?: string, // Optional recipient origin?: bigint // Optional origin code (default: 0n) ); ``` --- #### sellToken() Sells tokens for BNB (V2 method). ```typescript import { sellToken } from 'four-flap-meme-sdk'; await sellToken( chain: 'BSC', // Chain name rpcUrl: string, signerPrivateKey: string, token: string, amount: bigint, // Token amount to sell minFunds: bigint, // Minimum BNB to receive origin?: bigint // Optional origin code (default: 0n) ); ``` **Note**: Requires prior token approval (use `ensureSellApproval` first) --- #### tradeBuy() Auto-routing buy method (works for V1 and V2). ```typescript import { tradeBuy } from 'four-flap-meme-sdk'; await tradeBuy( chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // Chain name rpcUrl: string, privateKey: string, token: string, params: { type: 'funds' | 'amount', funds?: bigint, // If type === 'funds' minAmount?: bigint, // If type === 'funds' amount?: bigint, // If type === 'amount' maxFunds?: bigint, // If type === 'amount' to?: string, origin?: bigint } ); ``` --- #### tradeSell() Auto-routing sell method (works for V1 and V2). ```typescript import { tradeSell } from 'four-flap-meme-sdk'; await tradeSell( chain: 'BSC' | 'BASE' | 'ARBITRUM_ONE', // Chain name rpcUrl: string, privateKey: string, token: string, params: { type: 'direct' | 'router', amount: bigint, minFunds?: bigint, from?: string, // If type === 'router' feeRate?: bigint, // If type === 'router', in basis points feeRecipient?: string // If type === 'router' } ); ``` --- ### Utility Methods #### Token Approval Methods The SDK provides **multiple authorization methods** to support different TokenManager versions (V1/V2) and platforms (four.meme/Flap Protocol). ##### Four.meme Token Approval **For V1 Tokens**: ```typescript import { checkSellApprovalV1, ensureSellApprovalV1 } from 'four-flap-meme-sdk'; // Check V1 approval status (read-only) const status = await checkSellApprovalV1( 'BSC', // Supported: 'BSC' | 'BASE' | 'ARBITRUM_ONE' rpcUrl, tokenAddress, ownerAddress, amount ); // Ensure V1 approval (sends tx if needed) const result = await ensureSellApprovalV1( 'BSC', rpcUrl, privateKey, tokenAddress, ownerAddress, amount ); ``` **For V2 Tokens**: ```typescript import { checkSellApprovalV2, ensureSellApprovalV2 } from 'four-flap-meme-sdk'; // Check V2 approval status (read-only) const status = await checkSellApprovalV2( 'BSC', // Supported: 'BSC' | 'BASE' | 'ARBITRUM_ONE' rpcUrl, tokenAddress, ownerAddress, amount ); // Ensure V2 approval (sends tx if needed) const result = await ensureSellApprovalV2( 'BSC', rpcUrl, privateKey, tokenAddress, ownerAddress, amount ); ``` **Universal Methods (defaults to V2)**: ```typescript import { checkSellApproval, ensureSellApproval } from 'four-flap-meme-sdk'; // Check approval (defaults to V2) const status = await checkSellApproval( 'BSC', rpcUrl, tokenAddress, ownerAddress, amount ); // Ensure approval (defaults to V2) const result = await ensureSellApproval( 'BSC', rpcUrl, privateKey, tokenAddress, ownerAddress, amount ); ``` ##### Flap Protocol Token Approval ```typescript import { checkFlapSellApproval, ensureFlapSellApproval } from 'four-flap-meme-sdk'; // Check Flap approval status (read-only) const status = await checkFlapSellApproval( 'BSC', // Supported: 'BSC' | 'BASE' | 'XLAYER' | 'MORPH' rpcUrl, tokenAddress, ownerAddress, amount ); // Ensure Flap approval (sends tx if needed) const result = await ensureFlapSellApproval( 'BSC', rpcUrl, privateKey, tokenAddress, ownerAddress, amount ); ``` **Return Values**: All `check*` methods return: ```typescript { isApproved: boolean, // true if already approved currentAllowance: bigint, // Current approval amount requiredAllowance: bigint // Required approval amount } ``` All `ensure*` methods return: ```typescript { alreadyApproved: boolean, // true if no tx was needed currentAllowance: bigint, requiredAllowance: bigint, txReceipt?: TransactionReceipt // Only if approval tx was sent } ``` **Complete Workflow Examples**: **Four.meme V2 Token Sell**: ```typescript // 1. Check approval status (fast, read-only) const status = await checkSellApprovalV2('BSC', rpcUrl, token, wallet, amount); if (!status.isApproved) { // 2. Send approval transaction if needed console.log('Sending approval...'); await ensureSellApprovalV2('BSC', rpcUrl, privateKey, token, wallet, amount); } // 3. Execute sell await tradeSell('BSC', rpcUrl, privateKey, token, { type: 'direct', amount, minFunds: 0n }); ``` **Flap Protocol Token Sell**: ```typescript // 1. Check approval status const status = await checkFlapSellApproval('BSC', rpcUrl, token, wallet, amount); if (!status.isApproved) { // 2. Approve Flap Portal await ensureFlapSellApproval('BSC', rpcUrl, privateKey, token, wallet, amount); } // 3. Execute sell const writer = new FlapPortalWriter({ chain: 'BSC', rpcUrl }, privateKey); await writer.swapExactInput({ inputToken: token, outputToken: ZERO_ADDRESS, inputAmount: amount, minOutputAmount: 0n, permitData: '0x' }); ``` **UI Integration Example**: ```typescript // Update UI based on approval status const status = await checkSellApprovalV2('BSC', rpcUrl, tokenAddr, walletAddr, sellAmount); if (status.isApproved) { showButton('Sell Now', 'green'); } else { showButton('Approve First', 'orange'); showInfo(`Current: ${status.currentAllowance}, Need: ${status.requiredAllowance}`); } ``` **Important Notes**: - ⚠️ **V1 and V2 use different proxy contracts** - must approve the correct version - ⚠️ **Four.meme and Flap use different contracts** - cannot mix authorization methods - βœ… **Universal methods default to V2** for backward compatibility - βœ… **Recommend using explicit version methods** (`V1`/`V2`) for new code --- #### parseFourError() Parses four.meme error codes. ```typescript import { parseFourError } from 'four-flap-meme-sdk'; const { code, message } = parseFourError(error); ``` **Returns**: `{ code?: FourErrorCode, message: string }` --- #### isExclusiveOnChain() Checks if token is MPC-exclusive (on-chain). ```typescript import { isExclusiveOnChain } from 'four-flap-meme-sdk'; const isExclusive = await isExclusiveOnChain({ chain: 'BSC', // Only BSC supported (TokenManagerV2) tokenAddress: string, rpcUrl: string }); ``` --- #### isExclusiveOffChain() Checks if token is MPC-exclusive (via API). ```typescript import { isExclusiveOffChain } from 'four-flap-meme-sdk'; const isExclusive = await isExclusiveOffChain( getTokenInfo: (addr: string) => Promise<{ version?: string }>, tokenAddress: string ); ``` --- --- # Flap Protocol Guide ## Flap Architecture Flap Protocol is a next-generation token launch platform with these key features: ### Core Components: 1. **Portal Contract**: Main entry point for all operations 2. **CDPV2 Bonding Curve**: Advanced mathematical curve with three parameters (r, h, k) 3. **Multi-Network Support**: BSC, Base, X Layer, Morph 4. **Flexible Configuration**: Custom taxes, quote tokens, migration settings 5. **Configurable Fees**: Different chains can have different buy/sell fee rates ### Token Lifecycle on Flap: ``` 1. Create Token β†’ Deploy with CDPV2 curve 2. Trading Phase β†’ Buy/sell on bonding curve 3. Progress Tracking β†’ Monitor reserve vs. threshold 4. Migration β†’ Auto-migrate to DEX when threshold reached ``` --- ## Reading Token State Flap has **four versions** of token state reading methods: ### Version Comparison | Method | Returns | Use Case | |--------|---------|----------| | `getTokenV2()` | Basic state (7 fields) | Legacy compatibility | | `getTokenV3()` | + quote token info (9 fields) | Quote token support | | `getTokenV4()` | + extension ID (10 fields) | Extension support | | `getTokenV5()` | + full CDPV2 params (12 fields) | Complete information (recommended) | ### Reading Token State (V5 - Recommended) ```typescript import { FlapPortal } from 'four-flap-meme-sdk'; // Use chain enum (SDK handles addresses and default fee rates automatically) const portal = new FlapPortal({ chain: 'BSC', // Supports: 'BSC' | 'BASE' | 'XLAYER' | 'MORPH' rpcUrl: 'https://bsc-dataseed.binance.org' }); const state = await portal.getTokenV5('0x...token-address'); console.log('Token Status:', state.status); // 0=Invalid, 1=Tradable, 4=DEX console.log('Reserve (wei):', state.reserve); // Current BNB in curve console.log('Supply:', state.circulatingSupply); // Tokens in circulation console.log('Price:', state.price); // Current price in wei console.log('Curve Params:', state.r, state.h, state.k); // CDPV2 parameters console.log('DEX Threshold:', state.dexSupplyThresh); // Supply needed for migration console.log('Quote Token:', state.quoteTokenAddress); // 0x0 = native token ``` ### State Fields Explained ```typescript { status: number, // 0=Invalid, 1=Tradable, 2=InDuel, 3=Killed, 4=DEX reserve: bigint, // Current reserve in curve (in wei) circulatingSupply: bigint, // Tokens in circulation (in wei, 18 decimals) price: bigint, // Current price (in wei per token) tokenVersion: number, // Token implementation version r: bigint, // CDPV2 parameter r (reserve offset) h: bigint, // CDPV2 parameter h (height adjustment) k: bigint, // CDPV2 parameter k (curve constant) dexSupplyThresh: bigint, // Supply threshold for DEX migration quoteTokenAddress: Address, // 0x0 for native, or ERC20 address nativeToQuoteSwapEnabled: boolean, // Can swap native to quote extensionID: bytes32 // Extension identifier } ``` --- ## CDPV2 Bonding Curve The **CDPV2** (Constant Dynamic Price V2) curve is the core of Flap's price mechanism. ### Understanding CDPV2 Parameters #### Parameter `r` (Reserve Offset) - **What it is**: Starting reserve amount - **Effect**: Higher `r` = higher initial price - **Typical value**: 0.1 ETH (0.1 Γ— 10^18 wei) #### Parameter `h` (Height Adjustment) - **What it is**: Shifts the supply curve - **Effect**: Adjusts where the curve starts - **Typical value**: 0 (no shift) #### Parameter `k` (Curve Constant) - **What it is**: Determines price growth rate - **Effect**: Higher `k` = higher prices overall - **Typical value**: r Γ— 10^9 (1 billion Γ— r) ### The CDPV2 Formulas ``` Supply (S) = 1,000,000,000 + h - k / (R + r) Reserve (R) = k / (1,000,000,000 + h - S) - r Price (P) = k / (1,000,000,000 + h - S)Β² ``` Where: - S = circulating supply - R = reserve (BNB/ETH in curve) - P = price per token ### Using CDPV2 Class ```typescript import { CDPV2 } from 'four-flap-meme-sdk'; // Create a curve with r=0.1, h=0, k=1e8 const curve = CDPV2.getCurve(0.1, 0, 1e8); // Calculate supply needed for 10 ETH reserve const supply = curve.estimateSupply('10'); console.log('Supply at 10 ETH:', supply.toString()); // Calculate reserve needed for 800M supply const reserve = curve.estimateReserve('800000000'); console.log('Reserve at 800M supply:', reserve.toString()); // Get current price at 800M supply const price = curve.price('800000000'); console.log('Price at 800M supply:', price.toString()); // Get FDV (Fully Diluted Valuation) at 800M supply const fdv = curve.fdv('800000000'); console.log('FDV:', fdv.toString()); ``` ### Calculating Progress **Progress** = How close the token is to DEX migration ```typescript import { FlapPortal } from 'four-flap-meme-sdk'; const portal = new FlapPortal({ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org' }); const state = await portal.getTokenV5(tokenAddress); const { price, progress } = portal.computePriceAndProgress(state); console.log('Current Price:', price, 'ETH per token'); console.log('Progress:', progress); // '0.0000' to '1.0000' (0% to 100%) ``` **What progress means**: - `0.0000`: Just launched - `0.5000`: Halfway to DEX migration - `1.0000`: Ready for DEX migration - Progress = (current reserve) / (reserve needed at threshold) --- ## Flap Price Quotes The SDK provides **two quote methods** with different advantages: | Feature | Offline Quote | On-Chain Quote | |---------|--------------|----------------| | **Method** | `quoteBuy()` / `quoteSell()` | `quoteExactInput()` | | **Speed** | ⚑️ Instant (local computation) | 🐒 Slower (RPC call) | | **Accuracy** | πŸ“Š High (99.9%+) | 🎯 100% exact | | **Cost** | πŸ’° Free | πŸ’Έ Uses RPC quota | | **Use Case** | Real-time UI display | Final confirmation before trade | | **Dependency** | Requires token state | Only requires token address | ### Method 1: Offline Quote (Recommended for UI)⚑️ **Advantages**: - ⚑️ **Instant**: Local computation, zero latency - πŸ’° **Free**: No RPC quota consumption - πŸ“Š **Accurate**: Uses same formulas and fee rates as on-chain - 🎨 **Real-time**: Perfect for live UI updates as user types **Methods**: `quoteBuy()` / `quoteSell()` **How it works**: - Based on CDPV2 bonding curve formula - Automatically deducts platform fees (configurable) - 99.9%+ consistent with on-chain results ```typescript import { FlapPortal, FLAP_DEFAULT_FEE_RATES } from 'four-flap-meme-sdk'; const portal = new FlapPortal({ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org', // Configure fee rates (optional, default is chain-specific) buyFeeRate: FLAP_DEFAULT_FEE_RATES.BSC.buy, // 1% = 0.01 sellFeeRate: FLAP_DEFAULT_FEE_RATES.BSC.sell // 1% = 0.01 }); // 1. Get token state (once) const tokenAddress = '0x...' as any; const state = await portal.getTokenV5(tokenAddress); // 2. Offline buy quote: How many tokens for 1 BNB? const tokenAmount = portal.quoteBuy(state, '1.0'); console.log('πŸ’° Buy Quote:'); console.log(' Pay: 1.0 BNB'); console.log(' Fee: 0.01 BNB (1%)'); console.log(' Used to buy: 0.99 BNB'); console.log(' Expected to receive:', tokenAmount, 'tokens'); // 3. Offline sell quote: How much BNB for 1000000 tokens? const ethAmount = portal.quoteSell(state, '1000000'); console.log('\nπŸ’Έ Sell Quote:'); console.log(' Sell: 1000000 tokens'); console.log(' After 1% fee deduction'); console.log(' You receive:', ethAmount, 'BNB'); ``` **Real-world Use Case - Live UI Updates**: ```typescript // Scenario: User types amount in input box, show quote in real-time let cachedState: TokenStateV5; async function init() { // Fetch token state once on initialization cachedState = await portal.getTokenV5(tokenAddress); } function onUserInputChange(inputValue: string) { // Instantly calculate and display when user types (no delay) const outputAmount = portal.quoteBuy(cachedState, inputValue); updateUI(`You will receive ~${formatNumber(outputAmount)} tokens`); // Optional: Refresh cachedState periodically (e.g. every 10s) for accuracy } ``` ### Method 2: On-Chain Quote (Exact)🎯 **Advantages**: - 🎯 **100% exact**: Directly simulates on-chain contract - βœ… **Real-time state**: Uses latest on-chain data - πŸ”’ **Reliable**: Final confirmation before trade **Disadvantages**: - 🐒 Requires RPC call (slower) - πŸ’Έ Consumes RPC quota **Methods**: `quoteExactInput()` / `previewBuy()` / `previewSell()` ```typescript const portal = new FlapPortal({ chain: 'BSC', rpcUrl: 'https://bsc-dataseed.binance.org' }); // Method A: General quote (supports any input/output token combination) const outputAmount = await portal.quoteExactInput({ inputToken: '0x0000000000000000000000000000000000000000' as any, // Native token (BNB/ETH) outputToken: tokenAddress, // Token you want inputAmount: 1n * 10n ** 18n // 1 BNB (in wei) }); console.log('Exact quote - you will receive:', formatEther(outputAmount), 'tokens'); // Method B: Specialized buy quote (more concise) const tokenAmount = await portal.previewBuy( tokenAddress, 1n * 10n ** 18n // 1 BNB ); console.log('Buy quote - you will receive:', formatEther(tokenAmount), 'tokens'); // Method C: Specialized sell quote (more concise) const ethAmount = await portal.previewSell( tokenAddress, 1000n * 10n ** 18n // 1000 tokens ); console.log('Sell quote - you will receive:', formatEther(ethAmount), 'BNB'); ``` ### πŸ“‹ Recommended Workflow **Best practice flow**: ```typescript import { FlapPortal, FlapPortalWriter, ZERO_ADDRESS } from 'four-flap-meme-sdk'; import { parseEther, formatEther } from 'ethers'; const rpcUrl = 'https://bsc-dataseed.binance.org'; const tokenAddress = '0x...'; // Token address const zeroAddress = ZERO_ADDRESS; // Create read-only instance for quotes const portal = new FlapPortal({ chain: 'BSC', rpcUrl }); // 1️⃣ UI display phase: Use offline quote (fast) const state = await portal.getTokenV5(tokenAddress); const estimatedOutput = portal.quoteBuy(state, userInput); showToUser(`Expected: ${estimatedOutput} tokens`); // 2️⃣ User clicks "Confirm Trade": Use on-chain quote (exact) const exactOutput = await portal.quoteExactInput({ inputToken: zeroAddress, outputToken: tokenAddress, inputAmount: parseEther(userInput) }); showConfirmDialog(`Exact amount: ${formatEther(exactOutput)} tokens`); // 3️⃣ Execute trade - Create Writer instance const writer = new FlapPortalWriter( { chain: 'BSC', rpcUrl }, 'YOUR_PRIVAT