flipmeme-sdk
v1.3.76
Published
web3 interface for flipmeme
Downloads
1,313
Readme
Flipmeme EVM SDK Documentation
Table of Contents
- Overview
- Installation
- Quick Start
- Architecture
- API Reference
- Types Reference
- Constants & Configuration
- Advanced Usage
- Error Handling
- Best Practices
- Examples
Overview
The Flipmeme EVM SDK provides a comprehensive TypeScript/JavaScript interface for interacting with the Flipmeme protocol on Ethereum-compatible blockchains. It enables developers to:
- Create NFT Collections with dynamic bonding curve pricing
- Mint & Trade NFTs with integrated liquidity pools
- Manage Multiple Collections with batch operations
- Calculate Pricing with built-in fee handling
- Query On-chain Data efficiently
Key Features
- 🔗 Multi-chain Support: Works on Ethereum, Base, and other EVM-compatible chains
- 💰 Bonding Curve Pricing: Automated market-making with customizable price curves
- 🔄 Liquidity Pools: Built-in AMM for instant NFT trading
- 📦 Batch Operations: Gas-efficient multi-collection transactions
- 🛡️ Type-Safe: Full TypeScript support with comprehensive type definitions
- 🧪 Well-Tested: Production-ready with extensive test coverage
Protocol Overview
The Flipmeme protocol implements a bonding curve NFT marketplace where:
- Collections are created with a defined supply and price range
- NFTs can be minted at dynamically calculated prices
- Liquidity pools allow instant buying/selling
- Fees are distributed to creators, LP providers, and the protocol
- Liquidity migration occurs when collections sell out
Installation
Prerequisites
- Node.js >= 16.x
- npm or yarn or pnpm
Install Dependencies
npm install flipmeme-sdk ethers@^5.7.0
# or
yarn add flipmeme-sdk ethers@^5.7.0
# or
pnpm add flipmeme-sdk ethers@^5.7.0Note: The SDK currently uses ethers v5. Compatibility with ethers v6 is planned for future releases.
Quick Start
Basic Setup
import { ethers } from "ethers";
import { FlipmemeSDK, BlockchainType, PLATFORM } from "flipmeme-sdk";
// 1. Setup provider and signer
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
// 2. Initialize SDK
const sdk = new FlipmemeSDK(
BlockchainType.ETHEREUM,
PLATFORM.DEV, // or PLATFORM.PROD
{
signer,
chainId: 84532, // Base Sepolia
provider,
}
);
// 3. Create a collection
const { collectionId, collectionAddress } = await sdk.createCollection({
name: "My NFT Collection",
symbol: "MNFT",
totalSupply: 100,
premint: 5,
sessionId: `session-${Date.now()}`,
tokenUri: "ipfs://QmYourCollectionMetadata/",
startPrice: ethers.utils.parseEther("0.001").toString(),
endPrice: ethers.utils.parseEther("0.1").toString(),
});
console.log("Collection created at:", collectionAddress);
// 4. Buy NFTs
const result = await sdk.buy({
collectionAddress,
baseUri: "ipfs://QmYourTokenMetadata/",
amount: 3, // Mint 3 new NFTs
tokenIds: [], // No buying from pool
});
console.log(`Successfully minted ${result.successCount} NFTs`);Example: Complete Trading Flow
// Calculate price before buying
const totalPrice = await sdk.getTotalPrice(
PurcahseType.BUY,
collectionAddress,
3
);
console.log("Total cost:", ethers.utils.formatEther(totalPrice), "ETH");
// Buy 3 NFTs
await sdk.buy({
collectionAddress,
baseUri: "ipfs://tokens/",
amount: 3,
tokenIds: [],
});
// Check your balance
const balance = await sdk.balanceOf(
collectionAddress,
await signer.getAddress()
);
console.log("You own", balance, "NFTs");
// Sell 2 NFTs back
await sdk.flipSell({
collectionAddress,
tokenIds: [0, 1],
});Architecture
Class Hierarchy
FlipmemeSDK (main entry point)
└── EthereumConnector (EVM implementation)
└── Factory & Collection ContractsContract Architecture
Factory Contract
├── Creates Collections
├── Manages Global State
└── Handles Multi-collection Operations
Collection Contract
├── ERC721A (NFT Standard)
├── Bonding Curve Logic
├── Liquidity Pool Management
└── Fee DistributionData Flow
User → SDK → EthereumConnector → Smart Contracts → Blockchain
← ← ← ←API Reference
Initialization
new FlipmemeSDK(chainType, platform, config)
Creates a new instance of the Flipmeme SDK.
Parameters:
chainType:BlockchainType.ETHEREUMplatform:PLATFORM.DEV | PLATFORM.STAGE | PLATFORM.PRODconfig:EthereumConfig
EthereumConfig:
interface EthereumConfig {
signer?: ethers.Signer; // Optional: required for write operations
chainId: number; // Network chain ID
provider: ethers.providers.BaseProvider; // RPC provider
}Example:
const sdk = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
signer: wallet,
chainId: 8453, // Base Mainnet
provider: provider,
});Throws:
Error("Invalid config for the given blockchain type")if config doesn't match chain type
Collection Management
createCollection(params)
Creates a new NFT collection with bonding curve pricing.
Parameters:
interface CollectionParams {
sessionId: string; // Unique session identifier
name: string; // Collection name (e.g., "Cool Cats")
symbol?: string; // Token symbol (e.g., "COOL")
tokenUri: string; // Collection metadata URI
totalSupply: number; // Max number of NFTs
premint?: number; // NFTs to pre-mint for creator (default: 0)
startPrice?: string; // Starting price in wei (default: 10^15 = 0.001 ETH)
endPrice?: string; // Ending price in wei (default: 10^16 = 0.01 ETH)
}Returns:
Promise<CreateCollectionResponse>;
interface CreateCollectionResponse {
collectionId: string; // On-chain collection ID
collectionAddress: string; // Contract address
}Example:
const { collectionId, collectionAddress } = await sdk.createCollection({
name: "Degen Apes",
symbol: "DAPE",
totalSupply: 1000,
premint: 10,
sessionId: `create-${Date.now()}-${Math.random()}`,
tokenUri: "ipfs://QmYourCollectionHash/metadata.json",
startPrice: ethers.utils.parseEther("0.0001").toString(),
endPrice: ethers.utils.parseEther("0.5").toString(),
});
console.log("Collection ID:", collectionId);
console.log(
"View on explorer:",
`https://basescan.org/address/${collectionAddress}`
);Events Emitted:
CollectionCreated(id, collection, creator, totalSupply, premint)
Gas Cost: ~3-5M gas (varies by network)
Important Notes:
sessionIdshould be unique per collection to avoid conflicts- Price curve is logarithmic between
startPriceandendPrice - Preminted NFTs are sent to the creator's address
- Symbol is optional but recommended for better UX
Trading Operations
buy(params)
Mints new NFTs and/or buys NFTs from the liquidity pool.
Parameters:
interface EthBuyParams {
collectionAddress: string; // Collection contract address
baseUri?: string; // Token metadata base URI (required if amount > 0)
amount: number; // Number of new NFTs to mint
tokenIds: number[]; // Token IDs to buy from pool
}Returns:
Promise<ConfirmResult>;
interface ConfirmResult {
successCount: number; // Total NFTs acquired
failedCount: number; // Failed transactions (always 0 on success)
}Examples:
Mint Only:
// Mint 5 new NFTs
const result = await sdk.buy({
collectionAddress: "0x1234...",
baseUri: "ipfs://QmTokens/",
amount: 5,
tokenIds: [],
});
// successCount = 5Buy from Pool Only:
// Buy 3 specific NFTs from liquidity pool
const result = await sdk.buy({
collectionAddress: "0x1234...",
baseUri: "", // Not needed for pool purchases
amount: 0,
tokenIds: [10, 15, 20],
});
// successCount = 3Combined Mint + Buy:
// Mint 2 new + buy 3 from pool
const result = await sdk.buy({
collectionAddress: "0x1234...",
baseUri: "ipfs://QmTokens/",
amount: 2,
tokenIds: [5, 8, 12],
});
// successCount = 5 (2 minted + 3 bought)Pricing Logic:
- Price increases with each mint/buy according to bonding curve
- Pool purchases use current price for each NFT
- Total price includes 2.5% protocol fee (configurable)
- Use
getTotalPrice()to calculate cost before buying
Gas Cost: ~100-300k per NFT (varies by operation)
Throws:
Errorif insufficient ETH sentErrorif collection is sold out and amount > 0Errorif tokenIds reference non-existent or unavailable tokens
flipSell(params)
Sells NFTs back to the collection's liquidity pool.
Parameters:
interface EthSellParams {
collectionAddress: string; // Collection contract address
tokenIds: number[]; // Token IDs to sell
}Returns:
Promise<ConfirmResult>;Example:
// Sell 3 NFTs back to pool
const result = await sdk.flipSell({
collectionAddress: "0x1234...",
tokenIds: [5, 10, 15],
});
console.log(`Sold ${result.successCount} NFTs`);Important Notes:
- You must own the NFTs you're selling
- NFTs must be from the specified collection
- Price is based on current bonding curve position
- Seller receives ETH minus protocol fee
- Sold NFTs return to the liquidity pool
Gas Cost: ~80-150k per NFT
Throws:
Errorif you don't own the tokensErrorif collection doesn't have enough liquidity
profileSell(params)
Sells NFTs from multiple collections in a single transaction (gas-efficient).
Parameters:
interface EthProfileSellParams {
data: Record<string, EthSellData>; // Map of collectionId to sell data
slippage: number; // Not used in EVM (reserved for future)
}
interface EthSellData {
tokenIds: number[]; // Token IDs to sell
collectionId: string; // Collection ID (not address!)
}Returns:
Promise<ConfirmResult>;Example:
// Get collection IDs first
const info1 = await sdk.getCollectionInfo(collectionAddr1);
const collectionId1 = info1[1].toString();
const info2 = await sdk.getCollectionInfo(collectionAddr2);
const collectionId2 = info2[1].toString();
// Sell from multiple collections
const result = await sdk.profileSell({
data: {
[collectionId1]: {
tokenIds: [1, 2, 3],
collectionId: collectionId1,
},
[collectionId2]: {
tokenIds: [5, 7],
collectionId: collectionId2,
},
},
slippage: 0, // Not used currently
});
console.log(`Sold ${result.successCount} total NFTs across collections`);Gas Savings:
- ~30-40% cheaper than individual sells
- More efficient with more collections
Use Cases:
- Portfolio liquidation
- Mass selling across collections
- Gas optimization for power users
Exporting NFT Images & Metadata (Off-chain)
These functions allow you to export NFT images and metadata from the server, enabling deployment to other platforms. They do not deploy collections to the blockchain directly.
getCollectionPriceByTotalSupply(totalSupply)
Calculates the price for exporting a collection based on its total supply.
Parameters:
totalSupply:number— The total number of NFTs in the collection to export.
Returns:
string // Price in wei as a stringExample:
const price = sdk.getCollectionPriceByTotalSupply(1000);
console.log("Export price:", ethers.utils.formatEther(price), "ETH");exportCollectionByEth(sessionId, totalSupply, slippage?)
Pays the price for exporting a collection's images and metadata, and emits an event for backend monitoring. This is used for off-chain export, not for on-chain deployment.
Parameters:
sessionId:string— Unique session identifier for the export operationtotalSupply:number— Total number of NFTs to exportslippage?:number(optional) — Slippage tolerance. If omitted, a default of 3% is used.
Returns:
Promise<any> // Resolves when export is successfulExample:
// Uses default 3% slippage
await sdk.exportCollectionByEth("session-abc-123", 1000);
// Specify custom slippage (e.g., 5%)
await sdk.exportCollectionByEth("session-abc-123", 1000, 5);
console.log("Export initiated. Monitor backend for completion event.");Query Operations
getCollectionInfo(collectionAddress)
Retrieves comprehensive information about a collection.
Parameters:
collectionAddress:string- The collection's contract address
Returns:
Promise<
[
string, // [0] Factory address
BigNumber, // [1] Collection ID
string, // [2] Creator address
BigNumber, // [3] Max supply
BigNumber, // [4] Current mint count
boolean, // [5] Is sold out
BigNumber, // [6] Protocol fee (basis points)
string, // [7] Collection URI
string // [8] Base URI
]
>;Example:
const info = await sdk.getCollectionInfo("0x1234...");
console.log("Factory:", info[0]);
console.log("Collection ID:", info[1].toString());
console.log("Creator:", info[2]);
console.log("Max Supply:", info[3].toString());
console.log("Minted:", info[4].toString());
console.log("Sold Out:", info[5]);
console.log("Protocol Fee BPS:", info[6].toString()); // 250 = 2.5%
console.log("Collection URI:", info[7]);
console.log("Base URI:", info[8]);
// Check progress
const progress = (info[4].toNumber() / info[3].toNumber()) * 100;
console.log(`Collection is ${progress.toFixed(1)}% minted`);Gas Cost: Free (view function)
getStateInfo() (getFactoryInfo)
Gets global factory state and configuration.
Returns:
Promise<FactoryInfo>;
// Exact return type depends on contract implementationExample:
const factoryInfo = await sdk.getStateInfo();
console.log("Factory configuration:", factoryInfo);Use Cases:
- Debugging
- Monitoring protocol state
- Admin operations
getTotalPrice(type, collectionAddress, amount)
Calculates the total price (including fees) for buying or selling NFTs.
Parameters:
type:PurcahseType.BUY | PurcahseType.SELLcollectionAddress:stringamount:number- Number of NFTs
Returns:
Promise<string>; // Price in wei as stringExamples:
import { PurcahseType } from "flipmeme-sdk";
// Calculate buy price for 5 NFTs
const buyPrice = await sdk.getTotalPrice(
PurcahseType.BUY,
collectionAddress,
5
);
console.log("Cost:", ethers.utils.formatEther(buyPrice), "ETH");
// Calculate sell price for 3 NFTs
const sellPrice = await sdk.getTotalPrice(
PurcahseType.SELL,
collectionAddress,
3
);
console.log("You'll receive:", ethers.utils.formatEther(sellPrice), "ETH");Price Calculation:
- Uses current bonding curve position
- Accounts for pool state (nftCount, mintCount)
- Includes protocol fee (2.5% by default)
- Sequential pricing for each NFT
Important:
- Prices change with each transaction
- Use immediately before buying/selling
- Consider adding slippage tolerance in UI
- Returns 0 if amount exceeds available supply
calculatePrice(collectionAddress)
Gets the current spot price for the next NFT purchase.
Parameters:
collectionAddress:string
Returns:
Promise<string>; // Current price in weiExample:
const currentPrice = await sdk.calculatePrice(collectionAddress);
console.log("Current price:", ethers.utils.formatEther(currentPrice), "ETH");
// Monitor price changes
setInterval(async () => {
const price = await sdk.calculatePrice(collectionAddress);
console.log("Price update:", ethers.utils.formatEther(price), "ETH");
}, 10000); // Every 10 secondsUse Cases:
- Real-time price displays
- Price tracking/charts
- Market monitoring
calculateTradeFee(collectionAddress, price)
Calculates the protocol fee for a given price.
Parameters:
collectionAddress:stringprice:string- Price in wei
Returns:
Promise<string>; // Fee amount in weiExample:
const price = await sdk.calculatePrice(collectionAddress);
const fee = await sdk.calculateTradeFee(collectionAddress, price);
console.log("Price:", ethers.utils.formatEther(price), "ETH");
console.log("Fee (2.5%):", ethers.utils.formatEther(fee), "ETH");
console.log(
"Total:",
ethers.utils.formatEther(BigNumber.from(price).add(fee)),
"ETH"
);balanceOf(collectionAddress, owner)
Gets the number of NFTs owned by an address in a collection.
Parameters:
collectionAddress:stringowner:string- Wallet address
Returns:
Promise<string>; // Number of NFTs ownedExample:
const userAddress = await signer.getAddress();
const balance = await sdk.balanceOf(collectionAddress, userAddress);
console.log(`You own ${balance} NFTs from this collection`);
if (parseInt(balance) > 0) {
console.log("You're a holder! 🎉");
}ownerOf(collectionAddress, tokenId)
Gets the owner of a specific NFT.
Parameters:
collectionAddress:stringtokenId:number
Returns:
Promise<string>; // Owner's addressExample:
const owner = await sdk.ownerOf(collectionAddress, 42);
console.log(`Token #42 is owned by ${owner}`);
// Check if you own a token
const yourAddress = await signer.getAddress();
if (owner.toLowerCase() === yourAddress.toLowerCase()) {
console.log("You own this token!");
}Throws:
Errorif token doesn't existErrorif token was burned
getTokenURI(collectionAddress, tokenId)
Gets the metadata URI for a specific NFT.
Parameters:
collectionAddress:stringtokenId:number
Returns:
Promise<string>; // Token metadata URIExample:
const tokenUri = await sdk.getTokenURI(collectionAddress, 10);
console.log("Token URI:", tokenUri);
// e.g., "ipfs://QmHash/10.json"
// Fetch and display metadata
const response = await fetch(
tokenUri.replace("ipfs://", "https://ipfs.io/ipfs/")
);
const metadata = await response.json();
console.log("Name:", metadata.name);
console.log("Image:", metadata.image);
console.log("Attributes:", metadata.attributes);totalSupply(collectionAddress)
Gets the total number of NFTs minted in a collection.
Parameters:
collectionAddress:string
Returns:
Promise<string>; // Total minted countExample:
const total = await sdk.totalSupply(collectionAddress);
const info = await sdk.getCollectionInfo(collectionAddress);
const maxSupply = info[3].toString();
console.log(`${total} / ${maxSupply} minted`);
const percentMinted = (parseInt(total) / parseInt(maxSupply)) * 100;
console.log(`${percentMinted.toFixed(1)}% of collection minted`);Utility Functions
moveLiquidity(collectionAddress)
Moves liquidity from the pool when a collection is sold out. Distributes funds to LP providers, creator, and sellout bonus.
Parameters:
collectionAddress:string
Returns:
Promise<void>;Example:
// Check if sold out first
const info = await sdk.getCollectionInfo(collectionAddress);
const isSoldOut = info[5];
if (isSoldOut) {
await sdk.moveLiquidity(collectionAddress);
console.log("✅ Liquidity moved successfully!");
console.log("Distribution:");
console.log(" - 85% → LP Provider");
console.log(" - 10% → LP Sellout Bonus");
console.log(" - 5% → Creator");
} else {
console.log("❌ Collection not sold out yet");
}Distribution:
- 85% to LP Provider
- 10% to LP Sellout Bonus Pool
- 5% to Collection Creator
Important:
- Can only be called once per collection
- Collection must be fully sold out
- Transaction will revert if called prematurely
- Emits
LiquidityMovedevent
Gas Cost: ~150-250k gas
buyCredit(params)
Purchases credits by sending ETH to the admin address. Credits can be used for platform features.
Parameters:
interface EthTransferParams {
amount: string; // Amount in ETH (e.g., "0.1")
}Returns:
Promise<string>; // Transaction hashExample:
// Buy 0.5 ETH worth of credits
const txHash = await sdk.buyCredit({
amount: "0.5",
});
console.log("Transaction hash:", txHash);
console.log("View on explorer:", `https://basescan.org/tx/${txHash}`);
// Wait for confirmation
const receipt = await provider.waitForTransaction(txHash);
console.log("Credits purchased! Confirmations:", receipt.confirmations);Use Cases:
- Premium features
- Gas-less transactions
- Platform credits
Note: The amount is automatically converted from ETH to wei internally.
claimReferralReward(userAddress, amount)
Claims referral rewards by transferring ETH from the reward wallet to a user. This method should be called by the backend/admin who has access to the reward wallet's private key.
⚠️ Important: The SDK signer must be the reward wallet, not the user's wallet. This is typically used in a backend service.
Parameters:
userAddress: string; // The address of the user claiming the reward
amount: string; // Amount in ETH (e.g., "0.1")Returns:
Promise<string>; // Transaction hashExample:
// Backend/Admin setup with reward wallet
const rewardWalletSigner = new ethers.Wallet(
REWARD_WALLET_PRIVATE_KEY,
provider
);
const adminSDK = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
signer: rewardWalletSigner, // Reward wallet signer, not user's
chainId: 8453,
provider,
});
// Claim referral reward for a user
const userAddress = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb";
const rewardAmount = "0.05"; // 0.05 ETH
const txHash = await adminSDK.claimReferralReward(userAddress, rewardAmount);
console.log("Referral reward claimed!");
console.log("Transaction hash:", txHash);
console.log("View on BaseScan:", `https://basescan.org/tx/${txHash}`);Flow:
- User earns referral rewards - Backend calculates rewards based on trading fees
- Team funds reward wallet - Manually add ETH to the designated reward wallet
- User requests claim - User initiates claim through your application
- Backend processes claim - Your backend calls this method with the reward wallet signer
- ETH transferred - Reward wallet sends ETH directly to user's address
Use Cases:
- Referral commission payouts
- Trading fee rebates
- Affiliate rewards
- Promotional incentives
Security Considerations:
- The reward wallet private key should be securely stored (e.g., AWS Secrets Manager, HashiCorp Vault)
- Implement rate limiting and claim verification in your backend
- Keep reward wallet funded but with limited balance to minimize risk
- Log all claim transactions for audit purposes
- Consider implementing multi-signature for large reward wallets
Note: This does NOT interact with smart contracts or treasury - it's a simple ETH transfer from a team-controlled wallet to the user, providing maximum flexibility and minimal risk.
Types Reference
Core Types
// Blockchain selection
enum BlockchainType {
SOLANA = "solana",
ETHEREUM = "ethereum",
}
// Platform environment
enum PLATFORM {
DEV = "Dev",
STAGE = "Stage",
PROD = "Prod",
}
// Purchase type for pricing
enum PurcahseType {
BUY = "buy",
SELL = "sell",
}Configuration Types
interface EthereumConfig {
signer?: ethers.Signer; // Wallet for signing transactions
chainId: number; // Network chain ID (8453 for Base)
provider: ethers.providers.BaseProvider; // RPC provider instance
}Collection Types
interface CollectionParams {
sessionId: string; // Unique identifier for this collection creation
name: string; // Collection display name
symbol?: string; // Token symbol (optional)
tokenUri: string; // Collection metadata URI
totalSupply: number; // Maximum number of NFTs
premint?: number; // Number to pre-mint for creator (default: 0)
startPrice?: string; // Starting price in wei (default: 10^15)
endPrice?: string; // Ending price in wei (default: 10^16)
}
interface CreateCollectionResponse {
collectionId: string; // Unique on-chain ID
collectionAddress: string; // Deployed contract address
}Trading Types
interface EthBuyParams {
collectionAddress: string; // Collection contract address
baseUri?: string; // Token metadata base URI (required if minting)
amount: number; // Number of new NFTs to mint
tokenIds: number[]; // Existing token IDs to buy from pool
}
interface EthSellParams {
collectionAddress: string; // Collection contract address
tokenIds: number[]; // Token IDs to sell
}
interface EthProfileSellParams {
data: Record<string, EthSellData>; // Collection ID → sell data mapping
slippage: number; // Not currently used (reserved)
}
interface EthSellData {
tokenIds: number[]; // Token IDs to sell
collectionId: string; // Collection ID (not address)
}
interface ConfirmResult {
successCount: number; // Number of successful operations
failedCount: number; // Number of failed operations
}Utility Types
interface EthTransferParams {
amount: string; // Amount in ETH (e.g., "0.1")
}Constants & Configuration
Network Addresses
interface ETHAddresses {
TREASURY: string; // Protocol treasury
LP_SELL_OUT: string; // LP sellout bonus pool
LP_PROVIDER: string; // LP provider address
ROYALTY: string; // Royalty recipient
FACTORY: string; // Factory contract address
PROTOCOL_FEE_BPS: number; // Protocol fee in basis points (250 = 2.5%)
ADMIN_FOR_CREDIT_BUY: string; // Credit purchase recipient
REFERRAL_CLAIM: string; // Referral rewards address
}Default Configuration (DEV)
const ETH_DEV = {
FACTORY: "0xE9fda705f7cD9D5bf11cffF0997A9ef74927C834",
TREASURY: "0x26ee601042126aA53fA212983f96C3571fab8e5E",
LP_SELL_OUT: "0x19A1f2d12A7DbD5834787BB98373d93D41682db8",
LP_PROVIDER: "0xc796E2c7fD16a8033D55fA61Ab575E2Cd27B4d47",
ROYALTY: "0x9c8969323255a476BD5A249DBC9f091728dbD671",
ADMIN_FOR_CREDIT_BUY: "0x63B3Cc8944B917AAc841429097F28be09AB636a7",
REFERRAL_CLAIM: "0xaE1f8271458285b71b465e4aC00E23a21cD8aF42",
PROTOCOL_FEE_BPS: 250, // 2.5%
};Supported Networks
| Network | Chain ID | RPC URL | Explorer | | ---------------------- | -------- | ------------------------ | ---------------------------- | | Base Mainnet | 8453 | https://mainnet.base.org | https://basescan.org | | Base Sepolia (Testnet) | 84532 | https://sepolia.base.org | https://sepolia.basescan.org |
Advanced Usage
Price Monitoring System
class PriceMonitor {
private sdk: FlipmemeSDK;
private collectionAddress: string;
constructor(sdk: FlipmemeSDK, collectionAddress: string) {
this.sdk = sdk;
this.collectionAddress = collectionAddress;
}
async getCurrentMetrics() {
const [info, price, totalSupply, balance] = await Promise.all([
this.sdk.getCollectionInfo(this.collectionAddress),
this.sdk.calculatePrice(this.collectionAddress),
this.sdk.totalSupply(this.collectionAddress),
this.sdk.balanceOf(
this.collectionAddress,
await this.getSigner().getAddress()
),
]);
return {
maxSupply: info[3].toNumber(),
currentMint: info[4].toNumber(),
isSoldOut: info[5],
currentPrice: ethers.utils.formatEther(price),
totalSupply: parseInt(totalSupply),
userBalance: parseInt(balance),
progress: (info[4].toNumber() / info[3].toNumber()) * 100,
};
}
async startMonitoring(intervalMs: number = 5000) {
console.log("Starting price monitoring...");
setInterval(async () => {
const metrics = await this.getCurrentMetrics();
console.log(`
Progress: ${metrics.progress.toFixed(1)}%
Price: ${metrics.currentPrice} ETH
Minted: ${metrics.currentMint}/${metrics.maxSupply}
Your Balance: ${metrics.userBalance}
`);
}, intervalMs);
}
private getSigner(): ethers.Signer {
// Return your signer instance
return this.sdk["ethereum"]?.["config"].signer!;
}
}
// Usage
const monitor = new PriceMonitor(sdk, collectionAddress);
await monitor.startMonitoring(10000); // Update every 10 secondsBatch NFT Operations
async function batchMintAndDistribute(
sdk: FlipmemeSDK,
collectionAddress: string,
recipients: string[],
baseUri: string
) {
console.log(`Minting ${recipients.length} NFTs...`);
// 1. Mint all NFTs to your address
const mintResult = await sdk.buy({
collectionAddress,
baseUri,
amount: recipients.length,
tokenIds: [],
});
console.log(`Minted ${mintResult.successCount} NFTs`);
// 2. Get the collection contract
const collection = Collection__factory.connect(
collectionAddress,
sdk["ethereum"]!["config"].signer!
);
// 3. Get current total supply to determine token IDs
const totalSupply = await sdk.totalSupply(collectionAddress);
const firstTokenId = parseInt(totalSupply) - recipients.length;
// 4. Transfer to recipients
console.log("Distributing NFTs...");
for (let i = 0; i < recipients.length; i++) {
const tokenId = firstTokenId + i;
const recipient = recipients[i];
console.log(`Transferring token #${tokenId} to ${recipient}...`);
const tx = await collection.transferFrom(
await sdk["ethereum"]!["config"].signer!.getAddress(),
recipient,
tokenId
);
await tx.wait();
}
console.log("✅ All NFTs distributed!");
}
// Usage
await batchMintAndDistribute(
sdk,
collectionAddress,
[
"0x1111111111111111111111111111111111111111",
"0x2222222222222222222222222222222222222222",
"0x3333333333333333333333333333333333333333",
],
"ipfs://QmYourTokens/"
);Portfolio Management
interface PortfolioItem {
collectionAddress: string;
collectionId: string;
tokenIds: number[];
currentValue: string;
}
async function getPortfolio(
sdk: FlipmemeSDK,
collections: string[],
owner: string
): Promise<PortfolioItem[]> {
const portfolio: PortfolioItem[] = [];
for (const collectionAddress of collections) {
// Get collection info
const info = await sdk.getCollectionInfo(collectionAddress);
const collectionId = info[1].toString();
const totalMinted = info[4].toNumber();
// Find owned tokens
const tokenIds: number[] = [];
for (let i = 0; i < totalMinted; i++) {
try {
const tokenOwner = await sdk.ownerOf(collectionAddress, i);
if (tokenOwner.toLowerCase() === owner.toLowerCase()) {
tokenIds.push(i);
}
} catch {
continue;
}
}
if (tokenIds.length > 0) {
// Calculate current value
const value = await sdk.getTotalPrice(
PurcahseType.SELL,
collectionAddress,
tokenIds.length
);
portfolio.push({
collectionAddress,
collectionId,
tokenIds,
currentValue: ethers.utils.formatEther(value),
});
}
}
return portfolio;
}
// Usage
const myPortfolio = await getPortfolio(
sdk,
[collection1, collection2, collection3],
await signer.getAddress()
);
console.log("Your Portfolio:");
myPortfolio.forEach((item, idx) => {
console.log(`\n${idx + 1}. Collection ${item.collectionId}`);
console.log(` NFTs owned: ${item.tokenIds.length}`);
console.log(` Current value: ${item.currentValue} ETH`);
console.log(` Token IDs: ${item.tokenIds.join(", ")}`);
});Automated Trading Bot
class FlipBot {
private sdk: FlipmemeSDK;
private collectionAddress: string;
private targetProfit: number; // in percentage
constructor(
sdk: FlipmemeSDK,
collectionAddress: string,
targetProfit: number = 10
) {
this.sdk = sdk;
this.collectionAddress = collectionAddress;
this.targetProfit = targetProfit;
}
async checkArbitrage() {
const currentPrice = await this.sdk.calculatePrice(this.collectionAddress);
const info = await this.sdk.getCollectionInfo(this.collectionAddress);
// Check if there are NFTs in the pool
// (You'd need to add a method to check pool size)
const buyPrice = await this.sdk.getTotalPrice(
PurcahseType.BUY,
this.collectionAddress,
1
);
const sellPrice = await this.sdk.getTotalPrice(
PurcahseType.SELL,
this.collectionAddress,
1
);
const buyPriceEth = parseFloat(ethers.utils.formatEther(buyPrice));
const sellPriceEth = parseFloat(ethers.utils.formatEther(sellPrice));
const profit = ((sellPriceEth - buyPriceEth) / buyPriceEth) * 100;
console.log(`
Buy Price: ${buyPriceEth.toFixed(6)} ETH
Sell Price: ${sellPriceEth.toFixed(6)} ETH
Potential Profit: ${profit.toFixed(2)}%
`);
return {
buyPrice: buyPriceEth,
sellPrice: sellPriceEth,
profit,
shouldTrade: profit >= this.targetProfit,
};
}
async executeTrade() {
const analysis = await this.checkArbitrage();
if (analysis.shouldTrade) {
console.log(
`✅ Profit opportunity detected: ${analysis.profit.toFixed(2)}%`
);
console.log("Executing trade...");
// Buy
const buyResult = await this.sdk.buy({
collectionAddress: this.collectionAddress,
baseUri: "",
amount: 0,
tokenIds: [0], // You'd need to know available token IDs
});
console.log("Bought NFT");
// Sell immediately
const sellResult = await this.sdk.flipSell({
collectionAddress: this.collectionAddress,
tokenIds: [0],
});
console.log(`✅ Trade complete! Profit: ${analysis.profit.toFixed(2)}%`);
return true;
}
return false;
}
async monitor(intervalMs: number = 10000) {
console.log(`Starting bot with ${this.targetProfit}% profit target...`);
setInterval(async () => {
try {
await this.executeTrade();
} catch (error) {
console.error("Trade failed:", error);
}
}, intervalMs);
}
}
// Usage (use at your own risk!)
const bot = new FlipBot(sdk, collectionAddress, 15); // 15% profit target
await bot.monitor(5000); // Check every 5 secondsError Handling
Common Errors
Insufficient Funds
try {
await sdk.buy({
collectionAddress,
baseUri: "ipfs://...",
amount: 10,
tokenIds: [],
});
} catch (error) {
if (error.code === "INSUFFICIENT_FUNDS") {
console.error("You don't have enough ETH for this transaction");
console.error(
"Required:",
ethers.utils.formatEther(error.transaction?.value || "0")
);
}
}Collection Sold Out
try {
await sdk.buy({
/* ... */
});
} catch (error) {
if (
error.message.includes("sold out") ||
error.message.includes("max supply")
) {
console.error("Collection is sold out!");
// Try buying from pool instead
await sdk.buy({
collectionAddress,
baseUri: "",
amount: 0,
tokenIds: [availableTokenId],
});
}
}User Rejected Transaction
try {
await sdk.createCollection({
/* ... */
});
} catch (error) {
if (error.code === 4001 || error.code === "ACTION_REJECTED") {
console.log("User rejected the transaction");
// Show user-friendly message
}
}Comprehensive Error Handler
async function safeExecute<T>(
operation: () => Promise<T>,
operationName: string
): Promise<T | null> {
try {
console.log(`Executing ${operationName}...`);
const result = await operation();
console.log(`✅ ${operationName} successful`);
return result;
} catch (error: any) {
console.error(`❌ ${operationName} failed:`);
// Ethers errors
if (error.code) {
switch (error.code) {
case "INSUFFICIENT_FUNDS":
console.error("Insufficient funds for transaction");
break;
case "ACTION_REJECTED":
console.error("User rejected transaction");
break;
case "UNPREDICTABLE_GAS_LIMIT":
console.error("Cannot estimate gas - transaction may fail");
break;
case "NETWORK_ERROR":
console.error("Network error - check your connection");
break;
default:
console.error(`Error code: ${error.code}`);
}
}
// Contract revert errors
if (error.reason) {
console.error("Contract error:", error.reason);
}
// Full error details
console.error("Full error:", error.message);
return null;
}
}
// Usage
const result = await safeExecute(
() =>
sdk.buy({
collectionAddress,
baseUri: "ipfs://...",
amount: 5,
tokenIds: [],
}),
"NFT Purchase"
);
if (result) {
console.log("Success:", result);
}Retry Logic
async function withRetry<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
delayMs: number = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error: any) {
lastError = error;
console.log(`Attempt ${attempt} failed:`, error.message);
// Don't retry user rejections
if (error.code === 4001 || error.code === "ACTION_REJECTED") {
throw error;
}
if (attempt < maxRetries) {
console.log(`Retrying in ${delayMs}ms...`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
delayMs *= 2; // Exponential backoff
}
}
}
throw lastError!;
}
// Usage
const result = await withRetry(
() =>
sdk.buy({
/* ... */
}),
3,
2000
);Best Practices
1. Always Check Prices Before Buying
// ❌ Bad: Blind purchase
await sdk.buy({ collectionAddress, amount: 5, tokenIds: [], baseUri: "..." });
// ✅ Good: Check price first
const estimatedPrice = await sdk.getTotalPrice(
PurcahseType.BUY,
collectionAddress,
5
);
console.log("This will cost:", ethers.utils.formatEther(estimatedPrice), "ETH");
const userConfirmed = await confirmWithUser(estimatedPrice);
if (userConfirmed) {
await sdk.buy({ collectionAddress, amount: 5, tokenIds: [], baseUri: "..." });
}2. Handle Collection State
// ✅ Check if collection is sold out before minting
const info = await sdk.getCollectionInfo(collectionAddress);
const remaining = info[3].sub(info[4]).toNumber();
if (remaining === 0) {
console.log("Collection sold out! Buying from pool instead...");
// Buy from liquidity pool
} else {
console.log(`${remaining} NFTs remaining`);
// Mint new NFTs
}3. Use Environment Variables
// ✅ Good: Secure configuration
import dotenv from "dotenv";
dotenv.config();
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const sdk = new FlipmemeSDK(
BlockchainType.ETHEREUM,
process.env.NODE_ENV === "production" ? PLATFORM.PROD : PLATFORM.DEV,
{ signer, chainId: parseInt(process.env.CHAIN_ID!), provider }
);4. Implement Proper Error Handling
// ✅ Comprehensive error handling
try {
const result = await sdk.createCollection({
name: "My Collection",
symbol: "MC",
totalSupply: 100,
sessionId: `session-${Date.now()}`,
tokenUri: "ipfs://...",
});
// Log success
console.log("Collection created:", result.collectionAddress);
// Store in database
await database.saveCollection(result);
} catch (error: any) {
// Log for debugging
console.error("Collection creation failed:", error);
// User-friendly message
if (error.code === "INSUFFICIENT_FUNDS") {
alert("You need more ETH to create a collection");
} else if (error.code === "ACTION_REJECTED") {
alert("Transaction was cancelled");
} else {
alert("Failed to create collection. Please try again.");
}
// Track error
analytics.trackError("create_collection_failed", error);
}5. Optimize Gas Usage
// ✅ Use profileSell for multiple collections
// Instead of:
await sdk.flipSell({ collectionAddress: addr1, tokenIds: [1, 2] });
await sdk.flipSell({ collectionAddress: addr2, tokenIds: [3, 4] });
// Do this (saves ~30% gas):
await sdk.profileSell({
data: {
[collectionId1]: { tokenIds: [1, 2], collectionId: collectionId1 },
[collectionId2]: { tokenIds: [3, 4], collectionId: collectionId2 },
},
slippage: 0,
});6. Monitor Transaction Status
async function buyWithConfirmation(sdk: FlipmemeSDK, params: EthBuyParams) {
console.log("Initiating purchase...");
// Start transaction
const result = await sdk.buy(params);
console.log("Transaction submitted, waiting for confirmation...");
// Get transaction hash (would need to modify SDK to return this)
// const txHash = result.transactionHash;
// Wait for confirmations
// const receipt = await provider.waitForTransaction(txHash, 2);
console.log("✅ Confirmed!");
return result;
}7. Cache Collection Data
class CollectionCache {
private cache = new Map<string, { data: any; timestamp: number }>();
private ttl = 60000; // 1 minute
async getCollectionInfo(sdk: FlipmemeSDK, address: string) {
const cached = this.cache.get(address);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
const data = await sdk.getCollectionInfo(address);
this.cache.set(address, { data, timestamp: Date.now() });
return data;
}
invalidate(address: string) {
this.cache.delete(address);
}
clear() {
this.cache.clear();
}
}
// Usage
const cache = new CollectionCache();
const info = await cache.getCollectionInfo(sdk, collectionAddress);8. Test on Testnet First
// ✅ Always test on testnet before mainnet
const TESTNET_CONFIG = {
chainId: 84532, // Base Sepolia
rpcUrl: "https://sepolia.base.org",
explorer: "https://sepolia.basescan.org",
};
const MAINNET_CONFIG = {
chainId: 8453, // Base Mainnet
rpcUrl: "https://mainnet.base.org",
explorer: "https://basescan.org",
};
const config =
process.env.USE_TESTNET === "true" ? TESTNET_CONFIG : MAINNET_CONFIG;Examples
Complete DApp Integration
import { ethers } from "ethers";
import {
FlipmemeSDK,
BlockchainType,
PLATFORM,
PurcahseType,
} from "flipmeme-sdk";
class FlipNFT {
private sdk: FlipmemeSDK;
private provider: ethers.providers.Web3Provider;
private signer: ethers.Signer;
async initialize() {
// Connect to MetaMask
if (!window.ethereum) {
throw new Error("Please install MetaMask");
}
this.provider = new ethers.providers.Web3Provider(window.ethereum);
await this.provider.send("eth_requestAccounts", []);
this.signer = this.provider.getSigner();
// Initialize SDK
const network = await this.provider.getNetwork();
this.sdk = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
signer: this.signer,
chainId: network.chainId,
provider: this.provider,
});
console.log("Connected:", await this.signer.getAddress());
}
async createCollection(params: {
name: string;
symbol: string;
totalSupply: number;
premint: number;
metadataUri: string;
}) {
try {
const { collectionId, collectionAddress } =
await this.sdk.createCollection({
name: params.name,
symbol: params.symbol,
totalSupply: params.totalSupply,
premint: params.premint,
sessionId: `create-${Date.now()}-${Math.random()}`,
tokenUri: params.metadataUri,
startPrice: ethers.utils.parseEther("0.001").toString(),
endPrice: ethers.utils.parseEther("0.1").toString(),
});
console.log("✅ Collection created!");
console.log("ID:", collectionId);
console.log("Address:", collectionAddress);
return { collectionId, collectionAddress };
} catch (error) {
console.error("Failed to create collection:", error);
throw error;
}
}
async buyNFTs(collectionAddress: string, amount: number, baseUri: string) {
try {
// Get price quote
const totalPrice = await this.sdk.getTotalPrice(
PurcahseType.BUY,
collectionAddress,
amount
);
console.log(
`Buying ${amount} NFTs for ${ethers.utils.formatEther(totalPrice)} ETH`
);
// Execute purchase
const result = await this.sdk.buy({
collectionAddress,
baseUri,
amount,
tokenIds: [],
});
console.log(`✅ Purchased ${result.successCount} NFTs`);
return result;
} catch (error) {
console.error("Purchase failed:", error);
throw error;
}
}
async sellNFTs(collectionAddress: string, tokenIds: number[]) {
try {
// Get sell quote
const totalPrice = await this.sdk.getTotalPrice(
PurcahseType.SELL,
collectionAddress,
tokenIds.length
);
console.log(
`Selling ${tokenIds.length} NFTs for ${ethers.utils.formatEther(
totalPrice
)} ETH`
);
// Execute sale
const result = await this.sdk.flipSell({
collectionAddress,
tokenIds,
});
console.log(`✅ Sold ${result.successCount} NFTs`);
return result;
} catch (error) {
console.error("Sale failed:", error);
throw error;
}
}
async getMyNFTs(collectionAddress: string): Promise<number[]> {
const myAddress = await this.signer.getAddress();
const balance = await this.sdk.balanceOf(collectionAddress, myAddress);
const totalSupply = await this.sdk.totalSupply(collectionAddress);
const myTokens: number[] = [];
for (let i = 0; i < parseInt(totalSupply); i++) {
try {
const owner = await this.sdk.ownerOf(collectionAddress, i);
if (owner.toLowerCase() === myAddress.toLowerCase()) {
myTokens.push(i);
}
} catch {
continue;
}
}
return myTokens;
}
async getCollectionStats(collectionAddress: string) {
const info = await this.sdk.getCollectionInfo(collectionAddress);
const currentPrice = await this.sdk.calculatePrice(collectionAddress);
return {
creator: info[2],
maxSupply: info[3].toNumber(),
minted: info[4].toNumber(),
remaining: info[3].sub(info[4]).toNumber(),
isSoldOut: info[5],
currentPrice: ethers.utils.formatEther(currentPrice),
progress: (info[4].toNumber() / info[3].toNumber()) * 100,
};
}
}
// Usage
const app = new FlipNFT();
await app.initialize();
// Create collection
const { collectionAddress } = await app.createCollection({
name: "Cool Cats",
symbol: "COOL",
totalSupply: 100,
premint: 5,
metadataUri: "ipfs://QmYourMetadata/",
});
// Buy NFTs
await app.buyNFTs(collectionAddress, 3, "ipfs://QmYourTokens/");
// Check stats
const stats = await app.getCollectionStats(collectionAddress);
console.log("Collection Stats:", stats);
// Get my NFTs
const myNFTs = await app.getMyNFTs(collectionAddress);
console.log("My NFTs:", myNFTs);
// Sell some
if (myNFTs.length > 0) {
await app.sellNFTs(collectionAddress, myNFTs.slice(0, 2));
}React Integration Example
// hooks/useFlipmeme.ts
import { useState, useEffect } from "react";
import { ethers } from "ethers";
import { FlipmemeSDK, BlockchainType, PLATFORM } from "flipmeme-sdk";
export function useFlipmeme() {
const [sdk, setSdk] = useState<FlipmemeSDK | null>(null);
const [isConnected, setIsConnected] = useState(false);
const [address, setAddress] = useState<string>("");
useEffect(() => {
initializeSDK();
}, []);
async function initializeSDK() {
if (!window.ethereum) return;
try {
const provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
const network = await provider.getNetwork();
const userAddress = await signer.getAddress();
const flipSDK = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
signer,
chainId: network.chainId,
provider,
});
setSdk(flipSDK);
setIsConnected(true);
setAddress(userAddress);
} catch (error) {
console.error("Failed to initialize SDK:", error);
}
}
return { sdk, isConnected, address, initialize: initializeSDK };
}
// components/CollectionCard.tsx
import React, { useState, useEffect } from "react";
import { useFlipmeme } from "../hooks/useFlipmeme";
interface CollectionCardProps {
collectionAddress: string;
}
export function CollectionCard({ collectionAddress }: CollectionCardProps) {
const { sdk } = useFlipmeme();
const [stats, setStats] = useState<any>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
loadStats();
}, [sdk, collectionAddress]);
async function loadStats() {
if (!sdk) return;
try {
setLoading(true);
const info = await sdk.getCollectionInfo(collectionAddress);
const price = await sdk.calculatePrice(collectionAddress);
setStats({
minted: info[4].toNumber(),
maxSupply: info[3].toNumber(),
isSoldOut: info[5],
currentPrice: ethers.utils.formatEther(price),
});
} catch (error) {
console.error("Failed to load stats:", error);
} finally {
setLoading(false);
}
}
if (loading) return <div>Loading...</div>;
if (!stats) return <div>Error loading collection</div>;
return (
<div className="collection-card">
<h3>Collection Stats</h3>
<p>
Minted: {stats.minted} / {stats.maxSupply}
</p>
<p>Current Price: {stats.currentPrice} ETH</p>
{stats.isSoldOut && <p className="sold-out">SOLD OUT</p>}
<button onClick={loadStats}>Refresh</button>
</div>
);
}Changelog
Version 1.0.0
- Initial EVM SDK release
- Support for Base network
- Core collection and trading functionality
- Bonding curve pricing system
- Multi-collection batch operations
Support & Resources
Documentation
- GitHub: [flipmeme-sdk repository]
- API Docs: This document
- Examples:
/demo/eth/directory
Community
- Discord: [Join our community]
- Twitter: [@flipmeme]
- Support: [email protected]
Security
For security concerns, please email [email protected]
License
[License Type] - See LICENSE file for details
Last Updated: October 6, 2025
SDK Version: 1.0.0
Compatible Networks: Ethereum, Base, EVM-compatible chains
