# Claw2Flap Trade Skill Let an Agent execute on‑chain trades on **Flap Portal**. --- ## Overview Claw2Flap Trade Skill is an on‑chain trading skill designed for Agents. This Skill is **not** just a raw swap script; it is the **first‑layer trading execution capability** for Claw2Flap Agents. The current version supports: - Using **BNB** to buy a target token - Swapping between tokens - Serving as the execution primitive for future **Agent‑managed fees, buyback, burn** and other automated behaviors Examples in this document use `WAKE_TOKEN_ADDRESS` as the default target token, demonstrating the **BNB → Token** trade path. In real usage you can replace it with any target token address. --- ## Contract Information Summary This Skill focuses on BSC and the Flap Portal contract, but you can adapt it by swapping out the addresses below. | Item | Description | Value | |---------------------|----------------------------|-----------------------------------------------------------------------| | `RPC_URL` | BSC RPC endpoint | `https://bsc-dataseed1.ninicoin.io` | | `FLAP_PORTAL_ADDR` | Flap Portal contract | `0xe2cE6ab80874Fa9Fa2aAE65D277Dd6B8e65C9De0` | | `WAKE_TOKEN_ADDRESS`| Default target token (WAKE)| `0xb5cedd3832ca973808fbc4299ae7818cc4187777` | You can treat this table as the **single source of truth** for contract configuration in this Skill. When migrating to other networks or tokens, update this table and the constants in the code consistently. --- ## When to Use Use this Skill when an Agent needs to execute on‑chain buy, buyback, or treasury operations, for example: - Use **BNB** to buy a target token - Execute on‑chain **treasury** management actions - Implement **buyback** logic - Provide the trading foundation for automated **Agent fees** --- ## Prerequisites - **Node.js** installed - **ethers.js** installed - A valid private key that can sign transactions - Sufficient **BNB** in the wallet to cover trade amount and gas --- ## Configuration ### Network Configuration ```javascript const RPC_URL = 'https://bsc-dataseed1.ninicoin.io'; // BSC RPC endpoint const FLAP_PORTAL_ADDRESS = '0xe2cE6ab80874Fa9Fa2aAE65D277Dd6B8e65C9De0'; // Flap Portal contract const WAKE_TOKEN_ADDRESS = '0xb5cedd3832ca973808fbc4299ae7818cc4187777'; // WAKE token address ``` **Parameters:** - `RPC_URL`: RPC endpoint for BSC network - `FLAP_PORTAL_ADDRESS`: Flap Portal contract address - `WAKE_TOKEN_ADDRESS`: target token address ### Environment Variables ```bash export PRIVATE_KEY="your_private_key_here" ``` **Security Recommendations:** - Never hardcode private keys in code - Use environment variables or a secrets manager - Ensure private keys are not committed to version control --- ## Functions ### `getWalletBNBBalance()` Get the wallet’s BNB balance. ```javascript async function getWalletBNBBalance() { return await provider.getBalance(signer); } ``` **Returns:** Wallet BNB balance in Wei. **Example:** ```javascript const balance = await getWalletBNBBalance(); console.log(`BNB Balance: ${ethers.formatEther(balance)} BNB`); ``` --- ### `swapToken(value)` Execute a token swap using BNB as input. ```javascript async function swapToken(value) { const portal = new ethers.Contract(FLAP_PORTAL_ADDRESS, ABI, signer); const tx = await portal.swapExactInput( { inputToken: ethers.ZeroAddress, // BNB (zero address) outputToken: WAKE_TOKEN_ADDRESS, // target token address inputAmount: value, // input amount in Wei minOutputAmount: 0, // minimum output amount permitData: ethers.getBytes('0x'), // permit data }, { value }, // BNB value sent ); console.log(tx.hash); } ``` **Parameters:** - `value`: Amount of BNB to swap in Wei. **Returns:** Transaction hash. **Examples:** ```javascript // Swap 1 BNB const value = ethers.parseEther('1.0'); await swapToken(value); // Swap 0.5 BNB const half = ethers.parseEther('0.5'); await swapToken(half); ``` --- ## Swap Parameters ### `ExactInputParams` struct ```solidity struct ExactInputParams { address inputToken; // input token address address outputToken; // output token address uint256 inputAmount; // input amount uint256 minOutputAmount; // minimum output amount bytes permitData; // permit authorization data } ``` **Details:** | Field | Description | Example | |------------------|--------------------------------------------------|--------------------------------------------------------| | `inputToken` | Input token address; use zero address for BNB | `0x0000000000000000000000000000000000000000` | | `outputToken` | Output token address | `0xb5cedd3832ca973808fbc4299ae7818cc4187777` | | `inputAmount` | Input amount in Wei | `ethers.parseEther('1.0')` | | `minOutputAmount`| Minimum output amount (0 = no limit) | `0` | | `permitData` | EIP‑2612 permit data | `ethers.getBytes('0x')` | --- ## Complete Usage Example ```javascript const { ethers } = require('ethers'); const RPC_URL = 'https://bsc-dataseed1.ninicoin.io'; const FLAP_PORTAL_ADDRESS = '0xe2cE6ab80874Fa9Fa2aAE65D277Dd6B8e65C9De0'; const WAKE_TOKEN_ADDRESS = '0xb5cedd3832ca973808fbc4299ae7818cc4187777'; const ABI = [ { inputs: [ { components: [ { internalType: 'address', name: 'inputToken', type: 'address' }, { internalType: 'address', name: 'outputToken', type: 'address' }, { internalType: 'uint256', name: 'inputAmount', type: 'uint256' }, { internalType: 'uint256', name: 'minOutputAmount', type: 'uint256' }, { internalType: 'bytes', name: 'permitData', type: 'bytes' }, ], internalType: 'struct IPortalTradeV2.ExactInputParams', name: 'params', type: 'tuple', }, ], name: 'swapExactInput', outputs: [{ internalType: 'uint256', name: 'outputAmount', type: 'uint256' }], stateMutability: 'payable', type: 'function', }, ]; const provider = new ethers.JsonRpcProvider(RPC_URL); const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider); async function main() { // 1. Check wallet balance const balance = await provider.getBalance(signer.address); console.log(`Wallet address: ${signer.address}`); console.log(`BNB Balance: ${ethers.formatEther(balance)} BNB`); // 2. Execute swap (swap 0.1 BNB) const swapAmount = ethers.parseEther('0.1'); const portal = new ethers.Contract(FLAP_PORTAL_ADDRESS, ABI, signer); const tx = await portal.swapExactInput( { inputToken: ethers.ZeroAddress, outputToken: WAKE_TOKEN_ADDRESS, inputAmount: swapAmount, minOutputAmount: 0, permitData: ethers.getBytes('0x'), }, { value: swapAmount } ); console.log(`Transaction hash: ${tx.hash}`); // 3. Wait for confirmation const receipt = await tx.wait(); console.log(`Transaction confirmed in block: ${receipt.blockNumber}`); } main().catch(console.error); ``` --- ## Error Handling ### Common Errors **Error: Private key undefined** ```javascript // Solution if (!process.env.PRIVATE_KEY) { throw new Error('PRIVATE_KEY environment variable is not set'); } ``` **Error: Insufficient balance** ```javascript // Solution const balance = await provider.getBalance(signer.address); const requiredAmount = ethers.parseEther('1.0'); if (balance < requiredAmount) { throw new Error( `Insufficient balance. Required: ${ethers.formatEther(requiredAmount)} BNB, ` + `Have: ${ethers.formatEther(balance)} BNB` ); } ``` **Error: Transaction failed** ```javascript // Solution try { const tx = await portal.swapExactInput(params, { value }); const receipt = await tx.wait(); if (receipt.status === 0) { console.error('Transaction failed'); } else { console.log('Transaction successful'); } } catch (error) { console.error('Swap error:', error.message); } ``` --- ## Strategy Skill Template: Trade by BNB Balance Threshold Below is a strategy Skill template for OpenClaw: **When the wallet BNB balance is greater than a given threshold, automatically execute a swap with a fixed BNB amount.** ### 1. Strategy Parameters You can define the following parameters in `SKILL.md` or a config file: - **`min_bnb_balance`**: Minimum BNB balance required to trigger a trade (in BNB), e.g. `1.0` - **`trade_bnb_amount`**: BNB amount used per swap (in BNB), e.g. `0.1` - **`output_token`**: Target token address (optional, defaults to `WAKE_TOKEN_ADDRESS`) Example config (pseudo): ```json { "min_bnb_balance": "1.0", "trade_bnb_amount": "0.1", "output_token": "0xb5cedd3832ca973808fbc4299ae7818cc4187777" } ``` ### 2. Execution Flow Pseudo‑code: ```javascript async function runStrategy({ min_bnb_balance, trade_bnb_amount, output_token }) { // 1. Read wallet BNB balance const balanceWei = await provider.getBalance(signer.address); const balanceBNB = Number(ethers.formatEther(balanceWei)); console.log(`Wallet: ${signer.address}`); console.log(`BNB Balance: ${balanceBNB} BNB`); // 2. Check threshold if (balanceBNB <= Number(min_bnb_balance)) { console.log( `Balance below threshold, skip trade. Need > ${min_bnb_balance} BNB, current ${balanceBNB} BNB` ); return; } // 3. Compute trade amount const tradeAmountWei = ethers.parseEther(trade_bnb_amount); // 4. Execute swap (can reuse swapToken or the full example above) const portal = new ethers.Contract( FLAP_PORTAL_ADDRESS, ABI, signer, ); const tx = await portal.swapExactInput( { inputToken: ethers.ZeroAddress, outputToken: output_token || WAKE_TOKEN_ADDRESS, inputAmount: tradeAmountWei, minOutputAmount: 0, permitData: ethers.getBytes('0x'), }, { value: tradeAmountWei }, ); console.log(`Strategy swap tx hash: ${tx.hash}`); } ``` ### 3. Example Skill Description Snippet In a strategy Skill `SKILL.md`, you might describe it like this: - **Skill name**: `claw2flap-trade-skill` - **Purpose**: When the Agent wallet’s BNB balance reaches a configured threshold, automatically execute a single on‑chain buy. This template can be used for basic buys and as a foundation for later Agent‑managed buyback, burn, and fee execution logic. - **Parameters**: - `min_bnb_balance`: minimum BNB balance (in BNB) to trigger the strategy - `trade_bnb_amount`: BNB amount used per trade (in BNB) - `output_token`: target token address, defaults to `WAKE_TOKEN_ADDRESS` if omitted - **Safety notes**: This strategy will automatically send on‑chain transactions. Make sure that: - The private key is secure and the script only runs in trusted environments - You understand the risk of loss and avoid setting `trade_bnb_amount` too high Based on this template, you can easily extend more rules (e.g. time‑based polling, price‑based triggers) and build richer automated trading strategies for your Agents. --- ## Extensibility Ideas This Skill is intentionally minimal in code but **open to extension**. A few recommended patterns: - **Multi‑chain support** - Add a config block for multiple networks (e.g. BSC, opBNB, other EVM chains). - For each network, store `RPC_URL`, `FLAP_PORTAL_ADDRESS`, and default fee token. - Let the Agent choose the network via a simple `chain` parameter in `SKILL.md`. - **Price‑based triggers** - Integrate a price oracle (or off‑chain price feed) and extend the strategy template so that trades only execute when price is within a configured band. - Example parameters: `max_buy_price`, `min_sell_price`, `max_slippage_bps`. - **Agent‑managed flows** - Combine this Skill with other modules for fees, buyback, and burn. - Let the Agent route a portion of income (e.g. fees) into periodic buyback/burn strategies implemented on top of this trade primitive. Documenting these extension points in `SKILL.md` makes it easier for downstream Agents (and humans) to safely compose more advanced behaviors without changing the core trade logic.