--- name: octopurr description: > Deploy tokens and agentbound tokens on BNB Chain. Supports deploying BEP-20 tokens with PancakeSwap liquidity, ERC-8004 agentbound tokens, buying/selling tokens, collecting and claiming LP fees, managing agent wallets, and claiming vested tokens. metadata: { "author": "Octopurr", "version": "1.2.0", "homepage": "https://octopurr.com", "docs": "https://github.com/octopurr-org/octopurr-docs" } --- # Octopurr Token & Agent Launchpad on BNB Chain. Deploy tokens with permanently locked liquidity. Trading fees accumulate automatically and distribute to wallet addresses or AI agent identities. An **agentbound token** is an ERC-8004 agent NFT + BEP-20 token deployed atomically. The agent receives a share of LP trading fees in WBNB. The agent's NFT owner controls fee claims via `agentWallet`. **SDK:** `@octopurr/sdk` | **Docs:** [GitHub](https://github.com/octopurr-org/octopurr-docs) | **Website:** [octopurr.com](https://octopurr.com) ### Typical Agent Flow 1. **Deploy** agentbound token on-chain -> get `agentId`, `tokenAddress` 2. **Register** with Octopurr API -> token appears on platform 3. **Set agent wallet** -> enable fee withdrawal 4. **First buy** -> trigger DEX indexing (DexScreener, GeckoTerminal) 5. _(Optional)_ **Share** token page on social platforms 6. Trading generates fees -> **Collect** distributes fees -> **Claim** withdraws WBNB to agent wallet ## Prerequisites ### Case 1: Agent already has a wallet Verify the wallet has sufficient BNB before deploying: ```typescript import { formatEther } from 'viem'; const balance = await publicClient.getBalance({ address: account.address }); console.log(`Balance: ${formatEther(balance)} BNB`); // Minimum: ~0.003 BNB (0.001 deploy gas + 0.002 first buy) // Add more if using CreatorBuy extension ``` ### Case 2: Agent needs a new wallet Generate a wallet and request the human owner to deposit BNB: ```typescript import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; const privateKey = generatePrivateKey(); const account = privateKeyToAccount(privateKey); console.log(`Wallet: ${account.address}`); // Store privateKey securely -- loss = loss of funds // Request owner to send BNB to this address before deploying // Minimum: ~0.003 BNB (0.001 deploy gas + 0.002 first buy) // Add more if using CreatorBuy extension ``` ## Install ```bash npm install @octopurr/sdk viem ``` ## Setup ```typescript import { createPublicClient, createWalletClient, http } from 'viem'; import { bsc } from 'viem/chains'; import { privateKeyToAccount } from 'viem/accounts'; const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); const publicClient = createPublicClient({ chain: bsc, transport: http() }); const walletClient = createWalletClient({ chain: bsc, transport: http(), account }); ``` --- ## Deploy Agentbound Token Deploy an ERC-8004 agent identity + token atomically. Agent receives fee share from LP trading. Complete all 3 steps for a functional agent. ### Parameters | Field | Type | Required | Description | |-------|------|----------|-------------| | `agent.name` | string | Yes | Agent display name (max 100 chars) | | `agent.description` | string | No | Agent description (max 1000 chars) | | `agent.image` | string | No | Agent avatar URL | | `token.token.name` | string | Yes | Token name (max 50 chars) | | `token.token.symbol` | string | Yes | Token symbol (max 50 chars) | | `token.marketCapBNB` | number | Yes | Initial market cap parameter in BNB -- sets starting token price on PancakeSwap. This is NOT the BNB amount required to deploy. Default: 30 | | `token.recipients` | `{address, bps}[]` | Yes | Wallet addresses that receive LP trading fees. `bps` = basis points where 10000 = 100%. Each entry: `{address: '0x...', bps: 5000}`. Use `[]` (empty array) when agent gets 100% fees. Examples: `[{address, bps: 10000}]` = 100% to one wallet; `[{address1, bps: 5000}, {address2, bps: 3000}]` + `agentBps: 2000` = split fees | | `agentBps` | number | Yes | Agent's share of LP trading fees in basis points (1-10000). Combined with `token.recipients`: sum of all `recipients[].bps` + `agentBps` must equal exactly 10000. Example: `recipients: []` + `agentBps: 10000` = agent gets 100% | | `token.extensions` | `ExtensionConfig[]` | No | Optional launch features. Build with: `core.buildCreatorBuyExtension(bnbAmount, {recipient, amountOutMinimum}, chainId)` -- buy tokens at launch; `core.buildVestingVaultExtension(bps, {lockupDuration, vestingDuration, agentId: 0n}, chainId)` -- lock % of supply with time vesting to agent; `core.buildAirdropExtension(bps, {merkleRoot, admin}, chainId)` -- merkle airdrop | | `nftRecipient` | address | No | Wallet that receives the ERC-8004 agent NFT. Omit to use deployer wallet. NFT owner controls agent wallet and fee claims | | 4th arg: `chainId` | 56 | No | BSC Mainnet. Default: 56 | ### Step 1: Deploy on-chain (REQUIRED) ```typescript import { deployAgentboundToken } from '@octopurr/sdk'; const result = await deployAgentboundToken({ agent: { name: '', description: '' }, token: { token: { name: '', symbol: '' }, marketCapBNB: 30, recipients: [], // empty when agent gets 100% }, agentBps: 10_000, nftRecipient: account.address, }, publicClient, walletClient, 56); if (result.error) throw new Error(result.error.label); // result: { agentId, tokenAddress, identityHash, txHash } ``` #### Example: Basic Agent Deploy ```typescript const result = await deployAgentboundToken({ agent: { name: 'Trading Agent', description: 'Autonomous trader' }, token: { token: { name: 'AgentCoin', symbol: 'ACOIN' }, marketCapBNB: 30, recipients: [], }, agentBps: 10_000, // 100% fees to agent nftRecipient: account.address, }, publicClient, walletClient, 56); // Then: Steps 2-5 above (Register + Set Wallet + First Buy + Share) ``` #### Example: Agent + Vesting Vault Use `agentId: 0n` as placeholder -- the contract injects the real agentId automatically. ```typescript import { core, deployAgentboundToken } from '@octopurr/sdk'; const vesting = core.buildVestingVaultExtension( 1500, // 15% of supply vests to agent { lockupDuration: 90 * 86400, vestingDuration: 365 * 86400, agentId: 0n }, 56, ); const result = await deployAgentboundToken({ agent: { name: 'Vesting Agent', description: 'Agent with token vesting' }, token: { token: { name: 'VestCoin', symbol: 'VEST' }, marketCapBNB: 30, recipients: [{ address: '0xPartner...', bps: 5000 }], // 50% fees to partner extensions: [vesting], }, agentBps: 5000, // 50% fees to agent nftRecipient: account.address, }, publicClient, walletClient, 56); // Then: Steps 2-5 above (Register + Set Wallet + First Buy + Share) ``` #### Example: Agent + CreatorBuy ```typescript import { core, deployAgentboundToken } from '@octopurr/sdk'; import { parseEther } from 'viem'; const creatorBuy = core.buildCreatorBuyExtension( parseEther('0.5'), // buy 0.5 BNB worth at launch { recipient: account.address, amountOutMinimum: 1n }, 56, ); const result = await deployAgentboundToken({ agent: { name: 'BuyAgent' }, token: { token: { name: 'BuyToken', symbol: 'BUYT' }, marketCapBNB: 30, recipients: [], extensions: [creatorBuy], }, agentBps: 10_000, // 100% fees to agent }, publicClient, walletClient, 56); // Then: Steps 2-5 above (Register + Set Wallet + First Buy + Share) ``` ### Step 2: Register with API (REQUIRED) Register both agent and token so they appear on the platform. ```typescript import { registerAgentWithToken, constructAgentDataUri } from '@octopurr/sdk'; const agentUri = constructAgentDataUri({ name: '', description: '', }); await registerAgentWithToken('https://octopurr.com', { agent: { agentId: result.agentId.toString(), chainId: 56, tokenAddress: result.tokenAddress, identityHash: result.identityHash, deployTx: result.txHash, ownerWallet: account.address, agentName: '', agentDescription: '', agentUri, }, token: { address: result.tokenAddress, name: '', symbol: '', creatorWallet: account.address, deployTx: result.txHash, chainId: 56, boundAgentId: Number(result.agentId), }, }); ``` ### Step 3: Set Agent Wallet (REQUIRED for fee withdrawal) Agent wallet receives LP fees and vested tokens. Must be set before claiming. ```typescript import { core, buildSetAgentWalletTypedData, setAgentWallet } from '@octopurr/sdk'; const info = await core.getAgentInfo(result.agentId, publicClient, 56); const deadline = BigInt(Math.floor(Date.now() / 1000) + 290); // max ~5 min const typedData = buildSetAgentWalletTypedData( result.agentId, account.address, info!.owner, deadline, 56, ); const signature = await walletClient.signTypedData(typedData); await setAgentWallet( result.agentId, account.address, deadline, signature, publicClient, walletClient, 56, ); ``` ### Step 4: First Buy (RECOMMENDED) Perform a small swap to trigger token indexing on DEX tracking platforms (DexScreener, GeckoTerminal). ```typescript import { core } from '@octopurr/sdk'; import { parseEther } from 'viem'; await core.buyToken({ token: result.tokenAddress, amountIn: parseEther('0.002'), // ~0.002 BNB minimum chainId: 56, }, publicClient, walletClient); ``` ### Step 5: Share on Socials (OPTIONAL) Share the token page URL to drive awareness: `https://octopurr.com/token/{tokenAddress}?chainId=56` --- ## Deploy Token Deploy a BEP-20 token with locked LP and fee distribution to wallet addresses. Complete both steps. ### Parameters | Field | Type | Required | Description | |-------|------|----------|-------------| | `token.name` | string | Yes | Token name (max 50 chars) | | `token.symbol` | string | Yes | Token symbol (max 50 chars) | | `marketCapBNB` | number | Yes | Initial market cap parameter in BNB -- sets starting token price on PancakeSwap. This is NOT the BNB amount required to deploy. Default: 30 | | `recipients` | `{address, bps}[]` | Yes | Wallet addresses that receive LP trading fees. `bps` = basis points where 10000 = 100%. Each entry: `{address: '0x...', bps: 5000}`. Sum of all `recipients[].bps` must equal 10000. Example: `[{address, bps: 10000}]` = 100% to deployer | | `extensions` | `ExtensionConfig[]` | No | Optional launch features. Build with: `core.buildCreatorBuyExtension(bnbAmount, {recipient, amountOutMinimum: 1n}, chainId)` -- spend BNB to buy tokens at launch; `core.buildVestingVaultExtension(bps, {lockupDuration, vestingDuration, admin}, chainId)` -- lock % of supply with time vesting; `core.buildAirdropExtension(bps, {merkleRoot, admin}, chainId)` -- merkle airdrop | | `chainId` | 56 | No | BSC Mainnet. Default: 56 | ### Step 1: Deploy on-chain (REQUIRED) ```typescript import { core } from '@octopurr/sdk'; const result = await core.deployToken({ token: { name: '', symbol: '' }, marketCapBNB: 30, recipients: [{ address: account.address, bps: 10_000 }], chainId: 56, }, publicClient, walletClient); if (result.error) throw new Error(result.error.label); // result: { tokenAddress, poolAddress, nftTokenId, txHash } ``` #### Example: Basic Deploy ```typescript const result = await core.deployToken({ token: { name: 'Space Cat', symbol: 'SCAT' }, marketCapBNB: 30, recipients: [{ address: account.address, bps: 10_000 }], chainId: 56, }, publicClient, walletClient); // Then: Steps 2-4 above (Register + First Buy + Share) ``` #### Example: With Extensions ```typescript import { core } from '@octopurr/sdk'; import { parseEther } from 'viem'; const creatorBuy = core.buildCreatorBuyExtension( parseEther('0.5'), { recipient: account.address, amountOutMinimum: 1n }, 56, ); const vesting = core.buildVestingVaultExtension( 1500, // 15% of supply { lockupDuration: 90 * 86400, vestingDuration: 365 * 86400, admin: account.address }, 56, ); const airdrop = core.buildAirdropExtension( 500, // 5% of supply { merkleRoot: '' as `0x${string}`, admin: account.address }, 56, ); const result = await core.deployToken({ token: { name: 'Extended Token', symbol: 'EXT' }, marketCapBNB: 30, recipients: [{ address: account.address, bps: 10_000 }], extensions: [creatorBuy, vesting, airdrop], chainId: 56, }, publicClient, walletClient); // Then: Steps 2-4 above (Register + First Buy + Share) ``` ### Step 2: Register with API (REQUIRED) ```typescript await core.registerToken('https://octopurr.com', { address: result.tokenAddress, name: '', symbol: '', creatorWallet: account.address, deployTx: result.txHash, chainId: 56, }); ``` ### Step 3: First Buy (RECOMMENDED) Perform a small swap to trigger token indexing on DEX tracking platforms (DexScreener, GeckoTerminal). ```typescript import { core } from '@octopurr/sdk'; import { parseEther } from 'viem'; await core.buyToken({ token: result.tokenAddress, amountIn: parseEther('0.002'), // ~0.002 BNB minimum chainId: 56, }, publicClient, walletClient); ``` ### Step 4: Share on Socials (OPTIONAL) Share the token page URL to drive awareness: `https://octopurr.com/token/{tokenAddress}?chainId=56` --- ## Buy & Sell Swap tokens via PancakeSwap. Buy with BNB, sell for BNB. SDK handles Permit2 approval and signing automatically. ### Buy ```typescript import { core } from '@octopurr/sdk'; import { parseEther } from 'viem'; const buy = await core.buyToken({ token: '' as `0x${string}`, amountIn: parseEther('0.1'), chainId: 56, }, publicClient, walletClient); ``` ### Sell ```typescript import { core } from '@octopurr/sdk'; import { parseUnits } from 'viem'; const sell = await core.sellToken({ token: '' as `0x${string}`, amountIn: parseUnits('', 18), chainId: 56, }, publicClient, walletClient); ``` --- ## Claim LP Fees Collect accumulated trading fees from the LP pool and claim agent share. Two-step: collect distributes to all recipients, then claim withdraws agent's pending WBNB to agentWallet. LP_NFT_ID is the LP position NFT token ID. For regular tokens it's `result.nftTokenId` from deploy. For agentbound tokens, query via `core.getPosition` or the API: `GET /api/v1/tokens/
?chainId=56` -> `data.lpNftId`. ### Pre-claim Check ```typescript import { getAgentFeeState } from '@octopurr/sdk'; const state = await getAgentFeeState(, , publicClient, 56); // state.canClaim -- true if balance > 0, wallet set, not expired // state.agentWallet -- address(0) means setAgentWallet() needed first // state.pendingBalance -- accumulated WBNB ``` ### Collect + Claim ```typescript import { core, claimAgentFees } from '@octopurr/sdk'; // 1. Collect fees from pool (anyone can call) await core.claimFees(, publicClient, walletClient); // Batch collect await core.claimFeesMulti([, ], publicClient, walletClient); // 2. Claim agent fees -> WBNB sent to agentWallet await claimAgentFees(, , publicClient, walletClient); ``` --- ## Claim Vesting Vault Withdraw vested tokens from VestingVault after lockup expires. Agent mode: tokens sent to agentWallet. ```typescript import { abi, config } from '@octopurr/sdk'; const cfg = config.getChainConfig(56); // Check available amount const available = await publicClient.readContract({ address: cfg.octopurr.vestingVault, abi: abi.VestingVault_abi, functionName: 'amountAvailableToClaim', args: ['' as `0x${string}`], }); // Agent mode: claim by identity (caller must be agentWallet or NFT owner) const { request } = await publicClient.simulateContract({ address: cfg.octopurr.vestingVault, abi: abi.VestingVault_abi, functionName: 'claimByIdentity', args: ['' as `0x${string}`], account: walletClient.account.address, }); await walletClient.writeContract({ ...request, account: walletClient.account }); // Direct mode (admin wallet): use 'claim' instead of 'claimByIdentity' ``` --- ## Claim Airdrop Claim airdrop allocation using merkle proof. ```typescript import { abi, config } from '@octopurr/sdk'; const cfg = config.getChainConfig(56); const { request } = await publicClient.simulateContract({ address: cfg.octopurr.airdropDistributor, abi: abi.AirdropDistributor_abi, functionName: 'claim', args: [ '' as `0x${string}`, , // uint256 -- exact allocation for msg.sender , // bytes32[] -- proof from merkle tree ], account: walletClient.account.address, }); await walletClient.writeContract({ ...request, account: walletClient.account }); ``` --- ## Query Functions Read on-chain state: agent info, pool price, market cap, fee positions. ```typescript import { core, config, computeErc8004IdentityHash } from '@octopurr/sdk'; // Agent info: { agentId, owner, agentWallet, tokenURI, boundToken } const info = await core.getAgentInfo(, publicClient, 56); // Agent fee state: { identityHash, pendingBalance, agentWallet, canClaim, isExpired } const state = await core.getAgentFeeState(, , publicClient, 56); // Pool price: { tokensPerBNB, bnbPerToken, tick, sqrtPriceX96, liquidity } const price = await core.getPoolPrice('' as `0x${string}`, publicClient, 56); // Market cap in BNB / USD const mcapBNB = await core.getMarketCapBNB('' as `0x${string}`, publicClient, 56); const mcapUSD = await core.getMarketCapUSD('' as `0x${string}`, 600, publicClient, 56); // LP position info const position = await core.getPosition(, publicClient, 56); // Pending WBNB for identity const pending = await core.getPendingBalance('' as `0x${string}`, , publicClient, 56); // Identity hash for agent const agentHash = computeErc8004IdentityHash(42n); // Chain config const cfg = config.getChainConfig(56); ``` --- ## Error Handling All SDK functions return `Result` -- never throw. ```typescript const result = await core.deployToken(params, publicClient, walletClient); if (result.error) { // result.error.type: 'revert' | 'funds' | 'network' | 'unknown' // result.error.label: human-readable message console.error(result.error.label); } else { console.log(result.tokenAddress); } ``` --- ## Chains | Network | Chain ID | Status | |---------|----------|--------| | BNB Chain | 56 | Live | ## Links - **Website:** [octopurr.com](https://octopurr.com) - **Docs:** [GitHub](https://github.com/octopurr-org/octopurr-docs) - **SDK:** [@octopurr/sdk](https://www.npmjs.com/package/@octopurr/sdk) - **Bot:** [@octopurrbot](https://x.com/octopurrbot) on X