flipmeme-sdk 1.3.74 โ†’ 1.3.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,2190 @@
1
- SDK readme file
1
+ # Flipmeme EVM SDK Documentation
2
+
3
+ ## Table of Contents
4
+
5
+ 1. [Overview](#overview)
6
+ 2. [Installation](#installation)
7
+ 3. [Quick Start](#quick-start)
8
+ 4. [Architecture](#architecture)
9
+ 5. [API Reference](#api-reference)
10
+ - [Initialization](#initialization)
11
+ - [Collection Management](#collection-management)
12
+ - [Trading Operations](#trading-operations)
13
+ - [Query Operations](#query-operations)
14
+ - [Utility Functions](#utility-functions)
15
+ 6. [Types Reference](#types-reference)
16
+ 7. [Constants & Configuration](#constants--configuration)
17
+ 8. [Advanced Usage](#advanced-usage)
18
+ 9. [Error Handling](#error-handling)
19
+ 10. [Best Practices](#best-practices)
20
+ 11. [Examples](#examples)
21
+
22
+ ---
23
+
24
+ ## Overview
25
+
26
+ The Flipmeme EVM SDK provides a comprehensive TypeScript/JavaScript interface for interacting with the Flipmeme protocol on Ethereum-compatible blockchains. It enables developers to:
27
+
28
+ - **Create NFT Collections** with dynamic bonding curve pricing
29
+ - **Mint & Trade NFTs** with integrated liquidity pools
30
+ - **Manage Multiple Collections** with batch operations
31
+ - **Calculate Pricing** with built-in fee handling
32
+ - **Query On-chain Data** efficiently
33
+
34
+ ### Key Features
35
+
36
+ - ๐Ÿ”— **Multi-chain Support**: Works on Ethereum, Base, and other EVM-compatible chains
37
+ - ๐Ÿ’ฐ **Bonding Curve Pricing**: Automated market-making with customizable price curves
38
+ - ๐Ÿ”„ **Liquidity Pools**: Built-in AMM for instant NFT trading
39
+ - ๐Ÿ“ฆ **Batch Operations**: Gas-efficient multi-collection transactions
40
+ - ๐Ÿ›ก๏ธ **Type-Safe**: Full TypeScript support with comprehensive type definitions
41
+ - ๐Ÿงช **Well-Tested**: Production-ready with extensive test coverage
42
+
43
+ ### Protocol Overview
44
+
45
+ The Flipmeme protocol implements a bonding curve NFT marketplace where:
46
+
47
+ 1. **Collections** are created with a defined supply and price range
48
+ 2. **NFTs** can be minted at dynamically calculated prices
49
+ 3. **Liquidity pools** allow instant buying/selling
50
+ 4. **Fees** are distributed to creators, LP providers, and the protocol
51
+ 5. **Liquidity migration** occurs when collections sell out
52
+
53
+ ---
54
+
55
+ ## Installation
56
+
57
+ ### Prerequisites
58
+
59
+ - Node.js >= 16.x
60
+ - npm or yarn or pnpm
61
+
62
+ ### Install Dependencies
63
+
64
+ ```bash
65
+ npm install flipmeme-sdk ethers@^5.7.0
66
+ # or
67
+ yarn add flipmeme-sdk ethers@^5.7.0
68
+ # or
69
+ pnpm add flipmeme-sdk ethers@^5.7.0
70
+ ```
71
+
72
+ > **Note**: The SDK currently uses ethers v5. Compatibility with ethers v6 is planned for future releases.
73
+
74
+ ---
75
+
76
+ ## Quick Start
77
+
78
+ ### Basic Setup
79
+
80
+ ```typescript
81
+ import { ethers } from "ethers";
82
+ import { FlipmemeSDK, BlockchainType, PLATFORM } from "flipmeme-sdk";
83
+
84
+ // 1. Setup provider and signer
85
+ const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
86
+ const signer = new ethers.Wallet(PRIVATE_KEY, provider);
87
+
88
+ // 2. Initialize SDK
89
+ const sdk = new FlipmemeSDK(
90
+ BlockchainType.ETHEREUM,
91
+ PLATFORM.DEV, // or PLATFORM.PROD
92
+ {
93
+ signer,
94
+ chainId: 84532, // Base Sepolia
95
+ provider,
96
+ }
97
+ );
98
+
99
+ // 3. Create a collection
100
+ const { collectionId, collectionAddress } = await sdk.createCollection({
101
+ name: "My NFT Collection",
102
+ symbol: "MNFT",
103
+ totalSupply: 100,
104
+ premint: 5,
105
+ sessionId: `session-${Date.now()}`,
106
+ tokenUri: "ipfs://QmYourCollectionMetadata/",
107
+ startPrice: ethers.utils.parseEther("0.001").toString(),
108
+ endPrice: ethers.utils.parseEther("0.1").toString(),
109
+ });
110
+
111
+ console.log("Collection created at:", collectionAddress);
112
+
113
+ // 4. Buy NFTs
114
+ const result = await sdk.buy({
115
+ collectionAddress,
116
+ baseUri: "ipfs://QmYourTokenMetadata/",
117
+ amount: 3, // Mint 3 new NFTs
118
+ tokenIds: [], // No buying from pool
119
+ });
120
+
121
+ console.log(`Successfully minted ${result.successCount} NFTs`);
122
+ ```
123
+
124
+ ### Example: Complete Trading Flow
125
+
126
+ ```typescript
127
+ // Calculate price before buying
128
+ const totalPrice = await sdk.getTotalPrice(
129
+ PurcahseType.BUY,
130
+ collectionAddress,
131
+ 3
132
+ );
133
+ console.log("Total cost:", ethers.utils.formatEther(totalPrice), "ETH");
134
+
135
+ // Buy 3 NFTs
136
+ await sdk.buy({
137
+ collectionAddress,
138
+ baseUri: "ipfs://tokens/",
139
+ amount: 3,
140
+ tokenIds: [],
141
+ });
142
+
143
+ // Check your balance
144
+ const balance = await sdk.balanceOf(
145
+ collectionAddress,
146
+ await signer.getAddress()
147
+ );
148
+ console.log("You own", balance, "NFTs");
149
+
150
+ // Sell 2 NFTs back
151
+ await sdk.flipSell({
152
+ collectionAddress,
153
+ tokenIds: [0, 1],
154
+ });
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Architecture
160
+
161
+ ### Class Hierarchy
162
+
163
+ ```
164
+ FlipmemeSDK (main entry point)
165
+ โ””โ”€โ”€ EthereumConnector (EVM implementation)
166
+ โ””โ”€โ”€ Factory & Collection Contracts
167
+ ```
168
+
169
+ ### Contract Architecture
170
+
171
+ ```
172
+ Factory Contract
173
+ โ”œโ”€โ”€ Creates Collections
174
+ โ”œโ”€โ”€ Manages Global State
175
+ โ””โ”€โ”€ Handles Multi-collection Operations
176
+
177
+ Collection Contract
178
+ โ”œโ”€โ”€ ERC721A (NFT Standard)
179
+ โ”œโ”€โ”€ Bonding Curve Logic
180
+ โ”œโ”€โ”€ Liquidity Pool Management
181
+ โ””โ”€โ”€ Fee Distribution
182
+ ```
183
+
184
+ ### Data Flow
185
+
186
+ ```
187
+ User โ†’ SDK โ†’ EthereumConnector โ†’ Smart Contracts โ†’ Blockchain
188
+ โ† โ† โ† โ†
189
+ ```
190
+
191
+ ---
192
+
193
+ ## API Reference
194
+
195
+ ### Initialization
196
+
197
+ #### `new FlipmemeSDK(chainType, platform, config)`
198
+
199
+ Creates a new instance of the Flipmeme SDK.
200
+
201
+ **Parameters:**
202
+
203
+ - `chainType`: `BlockchainType.ETHEREUM`
204
+ - `platform`: `PLATFORM.DEV | PLATFORM.STAGE | PLATFORM.PROD`
205
+ - `config`: `EthereumConfig`
206
+
207
+ **EthereumConfig:**
208
+
209
+ ```typescript
210
+ interface EthereumConfig {
211
+ signer?: ethers.Signer; // Optional: required for write operations
212
+ chainId: number; // Network chain ID
213
+ provider: ethers.providers.BaseProvider; // RPC provider
214
+ }
215
+ ```
216
+
217
+ **Example:**
218
+
219
+ ```typescript
220
+ const sdk = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
221
+ signer: wallet,
222
+ chainId: 8453, // Base Mainnet
223
+ provider: provider,
224
+ });
225
+ ```
226
+
227
+ **Throws:**
228
+
229
+ - `Error("Invalid config for the given blockchain type")` if config doesn't match chain type
230
+
231
+ ---
232
+
233
+ ### Collection Management
234
+
235
+ #### `createCollection(params)`
236
+
237
+ Creates a new NFT collection with bonding curve pricing.
238
+
239
+ **Parameters:**
240
+
241
+ ```typescript
242
+ interface CollectionParams {
243
+ sessionId: string; // Unique session identifier
244
+ name: string; // Collection name (e.g., "Cool Cats")
245
+ symbol?: string; // Token symbol (e.g., "COOL")
246
+ tokenUri: string; // Collection metadata URI
247
+ totalSupply: number; // Max number of NFTs
248
+ premint?: number; // NFTs to pre-mint for creator (default: 0)
249
+ startPrice?: string; // Starting price in wei (default: 10^15 = 0.001 ETH)
250
+ endPrice?: string; // Ending price in wei (default: 10^16 = 0.01 ETH)
251
+ }
252
+ ```
253
+
254
+ **Returns:**
255
+
256
+ ```typescript
257
+ Promise<CreateCollectionResponse>;
258
+
259
+ interface CreateCollectionResponse {
260
+ collectionId: string; // On-chain collection ID
261
+ collectionAddress: string; // Contract address
262
+ }
263
+ ```
264
+
265
+ **Example:**
266
+
267
+ ```typescript
268
+ const { collectionId, collectionAddress } = await sdk.createCollection({
269
+ name: "Degen Apes",
270
+ symbol: "DAPE",
271
+ totalSupply: 1000,
272
+ premint: 10,
273
+ sessionId: `create-${Date.now()}-${Math.random()}`,
274
+ tokenUri: "ipfs://QmYourCollectionHash/metadata.json",
275
+ startPrice: ethers.utils.parseEther("0.0001").toString(),
276
+ endPrice: ethers.utils.parseEther("0.5").toString(),
277
+ });
278
+
279
+ console.log("Collection ID:", collectionId);
280
+ console.log(
281
+ "View on explorer:",
282
+ `https://basescan.org/address/${collectionAddress}`
283
+ );
284
+ ```
285
+
286
+ **Events Emitted:**
287
+
288
+ - `CollectionCreated(id, collection, creator, totalSupply, premint)`
289
+
290
+ **Gas Cost:** ~3-5M gas (varies by network)
291
+
292
+ **Important Notes:**
293
+
294
+ - `sessionId` should be unique per collection to avoid conflicts
295
+ - Price curve is logarithmic between `startPrice` and `endPrice`
296
+ - Preminted NFTs are sent to the creator's address
297
+ - Symbol is optional but recommended for better UX
298
+
299
+ ---
300
+
301
+ ### Trading Operations
302
+
303
+ #### `buy(params)`
304
+
305
+ Mints new NFTs and/or buys NFTs from the liquidity pool.
306
+
307
+ **Parameters:**
308
+
309
+ ```typescript
310
+ interface EthBuyParams {
311
+ collectionAddress: string; // Collection contract address
312
+ baseUri?: string; // Token metadata base URI (required if amount > 0)
313
+ amount: number; // Number of new NFTs to mint
314
+ tokenIds: number[]; // Token IDs to buy from pool
315
+ }
316
+ ```
317
+
318
+ **Returns:**
319
+
320
+ ```typescript
321
+ Promise<ConfirmResult>;
322
+
323
+ interface ConfirmResult {
324
+ successCount: number; // Total NFTs acquired
325
+ failedCount: number; // Failed transactions (always 0 on success)
326
+ }
327
+ ```
328
+
329
+ **Examples:**
330
+
331
+ **Mint Only:**
332
+
333
+ ```typescript
334
+ // Mint 5 new NFTs
335
+ const result = await sdk.buy({
336
+ collectionAddress: "0x1234...",
337
+ baseUri: "ipfs://QmTokens/",
338
+ amount: 5,
339
+ tokenIds: [],
340
+ });
341
+ // successCount = 5
342
+ ```
343
+
344
+ **Buy from Pool Only:**
345
+
346
+ ```typescript
347
+ // Buy 3 specific NFTs from liquidity pool
348
+ const result = await sdk.buy({
349
+ collectionAddress: "0x1234...",
350
+ baseUri: "", // Not needed for pool purchases
351
+ amount: 0,
352
+ tokenIds: [10, 15, 20],
353
+ });
354
+ // successCount = 3
355
+ ```
356
+
357
+ **Combined Mint + Buy:**
358
+
359
+ ```typescript
360
+ // Mint 2 new + buy 3 from pool
361
+ const result = await sdk.buy({
362
+ collectionAddress: "0x1234...",
363
+ baseUri: "ipfs://QmTokens/",
364
+ amount: 2,
365
+ tokenIds: [5, 8, 12],
366
+ });
367
+ // successCount = 5 (2 minted + 3 bought)
368
+ ```
369
+
370
+ **Pricing Logic:**
371
+
372
+ - Price increases with each mint/buy according to bonding curve
373
+ - Pool purchases use current price for each NFT
374
+ - Total price includes 2.5% protocol fee (configurable)
375
+ - Use `getTotalPrice()` to calculate cost before buying
376
+
377
+ **Gas Cost:** ~100-300k per NFT (varies by operation)
378
+
379
+ **Throws:**
380
+
381
+ - `Error` if insufficient ETH sent
382
+ - `Error` if collection is sold out and amount > 0
383
+ - `Error` if tokenIds reference non-existent or unavailable tokens
384
+
385
+ ---
386
+
387
+ #### `flipSell(params)`
388
+
389
+ Sells NFTs back to the collection's liquidity pool.
390
+
391
+ **Parameters:**
392
+
393
+ ```typescript
394
+ interface EthSellParams {
395
+ collectionAddress: string; // Collection contract address
396
+ tokenIds: number[]; // Token IDs to sell
397
+ }
398
+ ```
399
+
400
+ **Returns:**
401
+
402
+ ```typescript
403
+ Promise<ConfirmResult>;
404
+ ```
405
+
406
+ **Example:**
407
+
408
+ ```typescript
409
+ // Sell 3 NFTs back to pool
410
+ const result = await sdk.flipSell({
411
+ collectionAddress: "0x1234...",
412
+ tokenIds: [5, 10, 15],
413
+ });
414
+
415
+ console.log(`Sold ${result.successCount} NFTs`);
416
+ ```
417
+
418
+ **Important Notes:**
419
+
420
+ - You must own the NFTs you're selling
421
+ - NFTs must be from the specified collection
422
+ - Price is based on current bonding curve position
423
+ - Seller receives ETH minus protocol fee
424
+ - Sold NFTs return to the liquidity pool
425
+
426
+ **Gas Cost:** ~80-150k per NFT
427
+
428
+ **Throws:**
429
+
430
+ - `Error` if you don't own the tokens
431
+ - `Error` if collection doesn't have enough liquidity
432
+
433
+ ---
434
+
435
+ #### `profileSell(params)`
436
+
437
+ Sells NFTs from multiple collections in a single transaction (gas-efficient).
438
+
439
+ **Parameters:**
440
+
441
+ ```typescript
442
+ interface EthProfileSellParams {
443
+ data: Record<string, EthSellData>; // Map of collectionId to sell data
444
+ slippage: number; // Not used in EVM (reserved for future)
445
+ }
446
+
447
+ interface EthSellData {
448
+ tokenIds: number[]; // Token IDs to sell
449
+ collectionId: string; // Collection ID (not address!)
450
+ }
451
+ ```
452
+
453
+ **Returns:**
454
+
455
+ ```typescript
456
+ Promise<ConfirmResult>;
457
+ ```
458
+
459
+ **Example:**
460
+
461
+ ```typescript
462
+ // Get collection IDs first
463
+ const info1 = await sdk.getCollectionInfo(collectionAddr1);
464
+ const collectionId1 = info1[1].toString();
465
+
466
+ const info2 = await sdk.getCollectionInfo(collectionAddr2);
467
+ const collectionId2 = info2[1].toString();
468
+
469
+ // Sell from multiple collections
470
+ const result = await sdk.profileSell({
471
+ data: {
472
+ [collectionId1]: {
473
+ tokenIds: [1, 2, 3],
474
+ collectionId: collectionId1,
475
+ },
476
+ [collectionId2]: {
477
+ tokenIds: [5, 7],
478
+ collectionId: collectionId2,
479
+ },
480
+ },
481
+ slippage: 0, // Not used currently
482
+ });
483
+
484
+ console.log(`Sold ${result.successCount} total NFTs across collections`);
485
+ ```
486
+
487
+ **Gas Savings:**
488
+
489
+ - ~30-40% cheaper than individual sells
490
+ - More efficient with more collections
491
+
492
+ **Use Cases:**
493
+
494
+ - Portfolio liquidation
495
+ - Mass selling across collections
496
+ - Gas optimization for power users
497
+
498
+ ---
499
+
500
+
501
+ ### Exporting NFT Images & Metadata (Off-chain)
502
+
503
+ 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.
504
+
505
+ #### `getCollectionPriceByTotalSupply(totalSupply)`
506
+
507
+ Calculates the price for exporting a collection based on its total supply.
508
+
509
+ **Parameters:**
510
+
511
+ - `totalSupply`: `number` โ€” The total number of NFTs in the collection to export.
512
+
513
+ **Returns:**
514
+
515
+ ```typescript
516
+ string // Price in wei as a string
517
+ ```
518
+
519
+ **Example:**
520
+
521
+ ```typescript
522
+ const price = sdk.getCollectionPriceByTotalSupply(1000);
523
+ console.log("Export price:", ethers.utils.formatEther(price), "ETH");
524
+ ```
525
+
526
+ ---
527
+
528
+
529
+ #### `exportCollectionByEth(sessionId, totalSupply, slippage?)`
530
+
531
+ 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.
532
+
533
+ **Parameters:**
534
+
535
+ - `sessionId`: `string` โ€” Unique session identifier for the export operation
536
+ - `totalSupply`: `number` โ€” Total number of NFTs to export
537
+ - `slippage?`: `number` (optional) โ€” Slippage tolerance. If omitted, a default of **3%** is used.
538
+
539
+ **Returns:**
540
+
541
+ ```typescript
542
+ Promise<any> // Resolves when export is successful
543
+ ```
544
+
545
+ **Example:**
546
+
547
+ ```typescript
548
+ // Uses default 3% slippage
549
+ await sdk.exportCollectionByEth("session-abc-123", 1000);
550
+
551
+ // Specify custom slippage (e.g., 5%)
552
+ await sdk.exportCollectionByEth("session-abc-123", 1000, 5);
553
+
554
+ console.log("Export initiated. Monitor backend for completion event.");
555
+ ```
556
+
557
+ ---
558
+
559
+ ### Query Operations
560
+
561
+ #### `getCollectionInfo(collectionAddress)`
562
+
563
+ Retrieves comprehensive information about a collection.
564
+
565
+ **Parameters:**
566
+
567
+ - `collectionAddress`: `string` - The collection's contract address
568
+
569
+ **Returns:**
570
+
571
+ ```typescript
572
+ Promise<
573
+ [
574
+ string, // [0] Factory address
575
+ BigNumber, // [1] Collection ID
576
+ string, // [2] Creator address
577
+ BigNumber, // [3] Max supply
578
+ BigNumber, // [4] Current mint count
579
+ boolean, // [5] Is sold out
580
+ BigNumber, // [6] Protocol fee (basis points)
581
+ string, // [7] Collection URI
582
+ string // [8] Base URI
583
+ ]
584
+ >;
585
+ ```
586
+
587
+ **Example:**
588
+
589
+ ```typescript
590
+ const info = await sdk.getCollectionInfo("0x1234...");
591
+
592
+ console.log("Factory:", info[0]);
593
+ console.log("Collection ID:", info[1].toString());
594
+ console.log("Creator:", info[2]);
595
+ console.log("Max Supply:", info[3].toString());
596
+ console.log("Minted:", info[4].toString());
597
+ console.log("Sold Out:", info[5]);
598
+ console.log("Protocol Fee BPS:", info[6].toString()); // 250 = 2.5%
599
+ console.log("Collection URI:", info[7]);
600
+ console.log("Base URI:", info[8]);
601
+
602
+ // Check progress
603
+ const progress = (info[4].toNumber() / info[3].toNumber()) * 100;
604
+ console.log(`Collection is ${progress.toFixed(1)}% minted`);
605
+ ```
606
+
607
+ **Gas Cost:** Free (view function)
608
+
609
+ ---
610
+
611
+ #### `getStateInfo()` (getFactoryInfo)
612
+
613
+ Gets global factory state and configuration.
614
+
615
+ **Returns:**
616
+
617
+ ```typescript
618
+ Promise<FactoryInfo>;
619
+ // Exact return type depends on contract implementation
620
+ ```
621
+
622
+ **Example:**
623
+
624
+ ```typescript
625
+ const factoryInfo = await sdk.getStateInfo();
626
+ console.log("Factory configuration:", factoryInfo);
627
+ ```
628
+
629
+ **Use Cases:**
630
+
631
+ - Debugging
632
+ - Monitoring protocol state
633
+ - Admin operations
634
+
635
+ ---
636
+
637
+ #### `getTotalPrice(type, collectionAddress, amount)`
638
+
639
+ Calculates the total price (including fees) for buying or selling NFTs.
640
+
641
+ **Parameters:**
642
+
643
+ - `type`: `PurcahseType.BUY | PurcahseType.SELL`
644
+ - `collectionAddress`: `string`
645
+ - `amount`: `number` - Number of NFTs
646
+
647
+ **Returns:**
648
+
649
+ ```typescript
650
+ Promise<string>; // Price in wei as string
651
+ ```
652
+
653
+ **Examples:**
654
+
655
+ ```typescript
656
+ import { PurcahseType } from "flipmeme-sdk";
657
+
658
+ // Calculate buy price for 5 NFTs
659
+ const buyPrice = await sdk.getTotalPrice(
660
+ PurcahseType.BUY,
661
+ collectionAddress,
662
+ 5
663
+ );
664
+ console.log("Cost:", ethers.utils.formatEther(buyPrice), "ETH");
665
+
666
+ // Calculate sell price for 3 NFTs
667
+ const sellPrice = await sdk.getTotalPrice(
668
+ PurcahseType.SELL,
669
+ collectionAddress,
670
+ 3
671
+ );
672
+ console.log("You'll receive:", ethers.utils.formatEther(sellPrice), "ETH");
673
+ ```
674
+
675
+ **Price Calculation:**
676
+
677
+ - Uses current bonding curve position
678
+ - Accounts for pool state (nftCount, mintCount)
679
+ - Includes protocol fee (2.5% by default)
680
+ - Sequential pricing for each NFT
681
+
682
+ **Important:**
683
+
684
+ - Prices change with each transaction
685
+ - Use immediately before buying/selling
686
+ - Consider adding slippage tolerance in UI
687
+ - Returns 0 if amount exceeds available supply
688
+
689
+ ---
690
+
691
+ #### `calculatePrice(collectionAddress)`
692
+
693
+ Gets the current spot price for the next NFT purchase.
694
+
695
+ **Parameters:**
696
+
697
+ - `collectionAddress`: `string`
698
+
699
+ **Returns:**
700
+
701
+ ```typescript
702
+ Promise<string>; // Current price in wei
703
+ ```
704
+
705
+ **Example:**
706
+
707
+ ```typescript
708
+ const currentPrice = await sdk.calculatePrice(collectionAddress);
709
+ console.log("Current price:", ethers.utils.formatEther(currentPrice), "ETH");
710
+
711
+ // Monitor price changes
712
+ setInterval(async () => {
713
+ const price = await sdk.calculatePrice(collectionAddress);
714
+ console.log("Price update:", ethers.utils.formatEther(price), "ETH");
715
+ }, 10000); // Every 10 seconds
716
+ ```
717
+
718
+ **Use Cases:**
719
+
720
+ - Real-time price displays
721
+ - Price tracking/charts
722
+ - Market monitoring
723
+
724
+ ---
725
+
726
+ #### `calculateTradeFee(collectionAddress, price)`
727
+
728
+ Calculates the protocol fee for a given price.
729
+
730
+ **Parameters:**
731
+
732
+ - `collectionAddress`: `string`
733
+ - `price`: `string` - Price in wei
734
+
735
+ **Returns:**
736
+
737
+ ```typescript
738
+ Promise<string>; // Fee amount in wei
739
+ ```
740
+
741
+ **Example:**
742
+
743
+ ```typescript
744
+ const price = await sdk.calculatePrice(collectionAddress);
745
+ const fee = await sdk.calculateTradeFee(collectionAddress, price);
746
+
747
+ console.log("Price:", ethers.utils.formatEther(price), "ETH");
748
+ console.log("Fee (2.5%):", ethers.utils.formatEther(fee), "ETH");
749
+ console.log(
750
+ "Total:",
751
+ ethers.utils.formatEther(BigNumber.from(price).add(fee)),
752
+ "ETH"
753
+ );
754
+ ```
755
+
756
+ ---
757
+
758
+ #### `balanceOf(collectionAddress, owner)`
759
+
760
+ Gets the number of NFTs owned by an address in a collection.
761
+
762
+ **Parameters:**
763
+
764
+ - `collectionAddress`: `string`
765
+ - `owner`: `string` - Wallet address
766
+
767
+ **Returns:**
768
+
769
+ ```typescript
770
+ Promise<string>; // Number of NFTs owned
771
+ ```
772
+
773
+ **Example:**
774
+
775
+ ```typescript
776
+ const userAddress = await signer.getAddress();
777
+ const balance = await sdk.balanceOf(collectionAddress, userAddress);
778
+
779
+ console.log(`You own ${balance} NFTs from this collection`);
780
+
781
+ if (parseInt(balance) > 0) {
782
+ console.log("You're a holder! ๐ŸŽ‰");
783
+ }
784
+ ```
785
+
786
+ ---
787
+
788
+ #### `ownerOf(collectionAddress, tokenId)`
789
+
790
+ Gets the owner of a specific NFT.
791
+
792
+ **Parameters:**
793
+
794
+ - `collectionAddress`: `string`
795
+ - `tokenId`: `number`
796
+
797
+ **Returns:**
798
+
799
+ ```typescript
800
+ Promise<string>; // Owner's address
801
+ ```
802
+
803
+ **Example:**
804
+
805
+ ```typescript
806
+ const owner = await sdk.ownerOf(collectionAddress, 42);
807
+ console.log(`Token #42 is owned by ${owner}`);
808
+
809
+ // Check if you own a token
810
+ const yourAddress = await signer.getAddress();
811
+ if (owner.toLowerCase() === yourAddress.toLowerCase()) {
812
+ console.log("You own this token!");
813
+ }
814
+ ```
815
+
816
+ **Throws:**
817
+
818
+ - `Error` if token doesn't exist
819
+ - `Error` if token was burned
820
+
821
+ ---
822
+
823
+ #### `getTokenURI(collectionAddress, tokenId)`
824
+
825
+ Gets the metadata URI for a specific NFT.
826
+
827
+ **Parameters:**
828
+
829
+ - `collectionAddress`: `string`
830
+ - `tokenId`: `number`
831
+
832
+ **Returns:**
833
+
834
+ ```typescript
835
+ Promise<string>; // Token metadata URI
836
+ ```
837
+
838
+ **Example:**
839
+
840
+ ```typescript
841
+ const tokenUri = await sdk.getTokenURI(collectionAddress, 10);
842
+ console.log("Token URI:", tokenUri);
843
+ // e.g., "ipfs://QmHash/10.json"
844
+
845
+ // Fetch and display metadata
846
+ const response = await fetch(
847
+ tokenUri.replace("ipfs://", "https://ipfs.io/ipfs/")
848
+ );
849
+ const metadata = await response.json();
850
+ console.log("Name:", metadata.name);
851
+ console.log("Image:", metadata.image);
852
+ console.log("Attributes:", metadata.attributes);
853
+ ```
854
+
855
+ ---
856
+
857
+ #### `totalSupply(collectionAddress)`
858
+
859
+ Gets the total number of NFTs minted in a collection.
860
+
861
+ **Parameters:**
862
+
863
+ - `collectionAddress`: `string`
864
+
865
+ **Returns:**
866
+
867
+ ```typescript
868
+ Promise<string>; // Total minted count
869
+ ```
870
+
871
+ **Example:**
872
+
873
+ ```typescript
874
+ const total = await sdk.totalSupply(collectionAddress);
875
+ const info = await sdk.getCollectionInfo(collectionAddress);
876
+ const maxSupply = info[3].toString();
877
+
878
+ console.log(`${total} / ${maxSupply} minted`);
879
+
880
+ const percentMinted = (parseInt(total) / parseInt(maxSupply)) * 100;
881
+ console.log(`${percentMinted.toFixed(1)}% of collection minted`);
882
+ ```
883
+
884
+ ---
885
+
886
+ ### Utility Functions
887
+
888
+ #### `moveLiquidity(collectionAddress)`
889
+
890
+ Moves liquidity from the pool when a collection is sold out. Distributes funds to LP providers, creator, and sellout bonus.
891
+
892
+ **Parameters:**
893
+
894
+ - `collectionAddress`: `string`
895
+
896
+ **Returns:**
897
+
898
+ ```typescript
899
+ Promise<void>;
900
+ ```
901
+
902
+ **Example:**
903
+
904
+ ```typescript
905
+ // Check if sold out first
906
+ const info = await sdk.getCollectionInfo(collectionAddress);
907
+ const isSoldOut = info[5];
908
+
909
+ if (isSoldOut) {
910
+ await sdk.moveLiquidity(collectionAddress);
911
+ console.log("โœ… Liquidity moved successfully!");
912
+ console.log("Distribution:");
913
+ console.log(" - 85% โ†’ LP Provider");
914
+ console.log(" - 10% โ†’ LP Sellout Bonus");
915
+ console.log(" - 5% โ†’ Creator");
916
+ } else {
917
+ console.log("โŒ Collection not sold out yet");
918
+ }
919
+ ```
920
+
921
+ **Distribution:**
922
+
923
+ - **85%** to LP Provider
924
+ - **10%** to LP Sellout Bonus Pool
925
+ - **5%** to Collection Creator
926
+
927
+ **Important:**
928
+
929
+ - Can only be called once per collection
930
+ - Collection must be fully sold out
931
+ - Transaction will revert if called prematurely
932
+ - Emits `LiquidityMoved` event
933
+
934
+ **Gas Cost:** ~150-250k gas
935
+
936
+ ---
937
+
938
+ #### `buyCredit(params)`
939
+
940
+ Purchases credits by sending ETH to the admin address. Credits can be used for platform features.
941
+
942
+ **Parameters:**
943
+
944
+ ```typescript
945
+ interface EthTransferParams {
946
+ amount: string; // Amount in ETH (e.g., "0.1")
947
+ }
948
+ ```
949
+
950
+ **Returns:**
951
+
952
+ ```typescript
953
+ Promise<string>; // Transaction hash
954
+ ```
955
+
956
+ **Example:**
957
+
958
+ ```typescript
959
+ // Buy 0.5 ETH worth of credits
960
+ const txHash = await sdk.buyCredit({
961
+ amount: "0.5",
962
+ });
963
+
964
+ console.log("Transaction hash:", txHash);
965
+ console.log("View on explorer:", `https://basescan.org/tx/${txHash}`);
966
+
967
+ // Wait for confirmation
968
+ const receipt = await provider.waitForTransaction(txHash);
969
+ console.log("Credits purchased! Confirmations:", receipt.confirmations);
970
+ ```
971
+
972
+ **Use Cases:**
973
+
974
+ - Premium features
975
+ - Gas-less transactions
976
+ - Platform credits
977
+
978
+ **Note:** The amount is automatically converted from ETH to wei internally.
979
+
980
+ ---
981
+
982
+ #### `claimReferralReward(userAddress, amount)`
983
+
984
+ 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.
985
+
986
+ **โš ๏ธ Important:** The SDK signer must be the reward wallet, not the user's wallet. This is typically used in a backend service.
987
+
988
+ **Parameters:**
989
+
990
+ ```typescript
991
+ userAddress: string; // The address of the user claiming the reward
992
+ amount: string; // Amount in ETH (e.g., "0.1")
993
+ ```
994
+
995
+ **Returns:**
996
+
997
+ ```typescript
998
+ Promise<string>; // Transaction hash
999
+ ```
1000
+
1001
+ **Example:**
1002
+
1003
+ ```typescript
1004
+ // Backend/Admin setup with reward wallet
1005
+ const rewardWalletSigner = new ethers.Wallet(
1006
+ REWARD_WALLET_PRIVATE_KEY,
1007
+ provider
1008
+ );
1009
+
1010
+ const adminSDK = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
1011
+ signer: rewardWalletSigner, // Reward wallet signer, not user's
1012
+ chainId: 8453,
1013
+ provider,
1014
+ });
1015
+
1016
+ // Claim referral reward for a user
1017
+ const userAddress = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb";
1018
+ const rewardAmount = "0.05"; // 0.05 ETH
1019
+
1020
+ const txHash = await adminSDK.claimReferralReward(userAddress, rewardAmount);
1021
+
1022
+ console.log("Referral reward claimed!");
1023
+ console.log("Transaction hash:", txHash);
1024
+ console.log("View on BaseScan:", `https://basescan.org/tx/${txHash}`);
1025
+ ```
1026
+
1027
+ **Flow:**
1028
+
1029
+ 1. **User earns referral rewards** - Backend calculates rewards based on trading fees
1030
+ 2. **Team funds reward wallet** - Manually add ETH to the designated reward wallet
1031
+ 3. **User requests claim** - User initiates claim through your application
1032
+ 4. **Backend processes claim** - Your backend calls this method with the reward wallet signer
1033
+ 5. **ETH transferred** - Reward wallet sends ETH directly to user's address
1034
+
1035
+ **Use Cases:**
1036
+
1037
+ - Referral commission payouts
1038
+ - Trading fee rebates
1039
+ - Affiliate rewards
1040
+ - Promotional incentives
1041
+
1042
+ **Security Considerations:**
1043
+
1044
+ - The reward wallet private key should be securely stored (e.g., AWS Secrets Manager, HashiCorp Vault)
1045
+ - Implement rate limiting and claim verification in your backend
1046
+ - Keep reward wallet funded but with limited balance to minimize risk
1047
+ - Log all claim transactions for audit purposes
1048
+ - Consider implementing multi-signature for large reward wallets
1049
+
1050
+ **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.
1051
+
1052
+ ---
1053
+
1054
+ ## Types Reference
1055
+
1056
+ ### Core Types
1057
+
1058
+ ```typescript
1059
+ // Blockchain selection
1060
+ enum BlockchainType {
1061
+ SOLANA = "solana",
1062
+ ETHEREUM = "ethereum",
1063
+ }
1064
+
1065
+ // Platform environment
1066
+ enum PLATFORM {
1067
+ DEV = "Dev",
1068
+ STAGE = "Stage",
1069
+ PROD = "Prod",
1070
+ }
1071
+
1072
+ // Purchase type for pricing
1073
+ enum PurcahseType {
1074
+ BUY = "buy",
1075
+ SELL = "sell",
1076
+ }
1077
+ ```
1078
+
1079
+ ### Configuration Types
1080
+
1081
+ ```typescript
1082
+ interface EthereumConfig {
1083
+ signer?: ethers.Signer; // Wallet for signing transactions
1084
+ chainId: number; // Network chain ID (8453 for Base)
1085
+ provider: ethers.providers.BaseProvider; // RPC provider instance
1086
+ }
1087
+ ```
1088
+
1089
+ ### Collection Types
1090
+
1091
+ ```typescript
1092
+ interface CollectionParams {
1093
+ sessionId: string; // Unique identifier for this collection creation
1094
+ name: string; // Collection display name
1095
+ symbol?: string; // Token symbol (optional)
1096
+ tokenUri: string; // Collection metadata URI
1097
+ totalSupply: number; // Maximum number of NFTs
1098
+ premint?: number; // Number to pre-mint for creator (default: 0)
1099
+ startPrice?: string; // Starting price in wei (default: 10^15)
1100
+ endPrice?: string; // Ending price in wei (default: 10^16)
1101
+ }
1102
+
1103
+ interface CreateCollectionResponse {
1104
+ collectionId: string; // Unique on-chain ID
1105
+ collectionAddress: string; // Deployed contract address
1106
+ }
1107
+ ```
1108
+
1109
+ ### Trading Types
1110
+
1111
+ ```typescript
1112
+ interface EthBuyParams {
1113
+ collectionAddress: string; // Collection contract address
1114
+ baseUri?: string; // Token metadata base URI (required if minting)
1115
+ amount: number; // Number of new NFTs to mint
1116
+ tokenIds: number[]; // Existing token IDs to buy from pool
1117
+ }
1118
+
1119
+ interface EthSellParams {
1120
+ collectionAddress: string; // Collection contract address
1121
+ tokenIds: number[]; // Token IDs to sell
1122
+ }
1123
+
1124
+ interface EthProfileSellParams {
1125
+ data: Record<string, EthSellData>; // Collection ID โ†’ sell data mapping
1126
+ slippage: number; // Not currently used (reserved)
1127
+ }
1128
+
1129
+ interface EthSellData {
1130
+ tokenIds: number[]; // Token IDs to sell
1131
+ collectionId: string; // Collection ID (not address)
1132
+ }
1133
+
1134
+ interface ConfirmResult {
1135
+ successCount: number; // Number of successful operations
1136
+ failedCount: number; // Number of failed operations
1137
+ }
1138
+ ```
1139
+
1140
+ ### Utility Types
1141
+
1142
+ ```typescript
1143
+ interface EthTransferParams {
1144
+ amount: string; // Amount in ETH (e.g., "0.1")
1145
+ }
1146
+ ```
1147
+
1148
+ ---
1149
+
1150
+ ## Constants & Configuration
1151
+
1152
+ ### Network Addresses
1153
+
1154
+ ```typescript
1155
+ interface ETHAddresses {
1156
+ TREASURY: string; // Protocol treasury
1157
+ LP_SELL_OUT: string; // LP sellout bonus pool
1158
+ LP_PROVIDER: string; // LP provider address
1159
+ ROYALTY: string; // Royalty recipient
1160
+ FACTORY: string; // Factory contract address
1161
+ PROTOCOL_FEE_BPS: number; // Protocol fee in basis points (250 = 2.5%)
1162
+ ADMIN_FOR_CREDIT_BUY: string; // Credit purchase recipient
1163
+ REFERRAL_CLAIM: string; // Referral rewards address
1164
+ }
1165
+ ```
1166
+
1167
+ ### Default Configuration (DEV)
1168
+
1169
+ ```typescript
1170
+ const ETH_DEV = {
1171
+ FACTORY: "0xE9fda705f7cD9D5bf11cffF0997A9ef74927C834",
1172
+ TREASURY: "0x26ee601042126aA53fA212983f96C3571fab8e5E",
1173
+ LP_SELL_OUT: "0x19A1f2d12A7DbD5834787BB98373d93D41682db8",
1174
+ LP_PROVIDER: "0xc796E2c7fD16a8033D55fA61Ab575E2Cd27B4d47",
1175
+ ROYALTY: "0x9c8969323255a476BD5A249DBC9f091728dbD671",
1176
+ ADMIN_FOR_CREDIT_BUY: "0x63B3Cc8944B917AAc841429097F28be09AB636a7",
1177
+ REFERRAL_CLAIM: "0xaE1f8271458285b71b465e4aC00E23a21cD8aF42",
1178
+ PROTOCOL_FEE_BPS: 250, // 2.5%
1179
+ };
1180
+ ```
1181
+
1182
+ ### Supported Networks
1183
+
1184
+ | Network | Chain ID | RPC URL | Explorer |
1185
+ | ---------------------- | -------- | ------------------------ | ---------------------------- |
1186
+ | Base Mainnet | 8453 | https://mainnet.base.org | https://basescan.org |
1187
+ | Base Sepolia (Testnet) | 84532 | https://sepolia.base.org | https://sepolia.basescan.org |
1188
+
1189
+ ---
1190
+
1191
+ ## Advanced Usage
1192
+
1193
+ ### Price Monitoring System
1194
+
1195
+ ```typescript
1196
+ class PriceMonitor {
1197
+ private sdk: FlipmemeSDK;
1198
+ private collectionAddress: string;
1199
+
1200
+ constructor(sdk: FlipmemeSDK, collectionAddress: string) {
1201
+ this.sdk = sdk;
1202
+ this.collectionAddress = collectionAddress;
1203
+ }
1204
+
1205
+ async getCurrentMetrics() {
1206
+ const [info, price, totalSupply, balance] = await Promise.all([
1207
+ this.sdk.getCollectionInfo(this.collectionAddress),
1208
+ this.sdk.calculatePrice(this.collectionAddress),
1209
+ this.sdk.totalSupply(this.collectionAddress),
1210
+ this.sdk.balanceOf(
1211
+ this.collectionAddress,
1212
+ await this.getSigner().getAddress()
1213
+ ),
1214
+ ]);
1215
+
1216
+ return {
1217
+ maxSupply: info[3].toNumber(),
1218
+ currentMint: info[4].toNumber(),
1219
+ isSoldOut: info[5],
1220
+ currentPrice: ethers.utils.formatEther(price),
1221
+ totalSupply: parseInt(totalSupply),
1222
+ userBalance: parseInt(balance),
1223
+ progress: (info[4].toNumber() / info[3].toNumber()) * 100,
1224
+ };
1225
+ }
1226
+
1227
+ async startMonitoring(intervalMs: number = 5000) {
1228
+ console.log("Starting price monitoring...");
1229
+
1230
+ setInterval(async () => {
1231
+ const metrics = await this.getCurrentMetrics();
1232
+ console.log(`
1233
+ Progress: ${metrics.progress.toFixed(1)}%
1234
+ Price: ${metrics.currentPrice} ETH
1235
+ Minted: ${metrics.currentMint}/${metrics.maxSupply}
1236
+ Your Balance: ${metrics.userBalance}
1237
+ `);
1238
+ }, intervalMs);
1239
+ }
1240
+
1241
+ private getSigner(): ethers.Signer {
1242
+ // Return your signer instance
1243
+ return this.sdk["ethereum"]?.["config"].signer!;
1244
+ }
1245
+ }
1246
+
1247
+ // Usage
1248
+ const monitor = new PriceMonitor(sdk, collectionAddress);
1249
+ await monitor.startMonitoring(10000); // Update every 10 seconds
1250
+ ```
1251
+
1252
+ ### Batch NFT Operations
1253
+
1254
+ ```typescript
1255
+ async function batchMintAndDistribute(
1256
+ sdk: FlipmemeSDK,
1257
+ collectionAddress: string,
1258
+ recipients: string[],
1259
+ baseUri: string
1260
+ ) {
1261
+ console.log(`Minting ${recipients.length} NFTs...`);
1262
+
1263
+ // 1. Mint all NFTs to your address
1264
+ const mintResult = await sdk.buy({
1265
+ collectionAddress,
1266
+ baseUri,
1267
+ amount: recipients.length,
1268
+ tokenIds: [],
1269
+ });
1270
+
1271
+ console.log(`Minted ${mintResult.successCount} NFTs`);
1272
+
1273
+ // 2. Get the collection contract
1274
+ const collection = Collection__factory.connect(
1275
+ collectionAddress,
1276
+ sdk["ethereum"]!["config"].signer!
1277
+ );
1278
+
1279
+ // 3. Get current total supply to determine token IDs
1280
+ const totalSupply = await sdk.totalSupply(collectionAddress);
1281
+ const firstTokenId = parseInt(totalSupply) - recipients.length;
1282
+
1283
+ // 4. Transfer to recipients
1284
+ console.log("Distributing NFTs...");
1285
+ for (let i = 0; i < recipients.length; i++) {
1286
+ const tokenId = firstTokenId + i;
1287
+ const recipient = recipients[i];
1288
+
1289
+ console.log(`Transferring token #${tokenId} to ${recipient}...`);
1290
+ const tx = await collection.transferFrom(
1291
+ await sdk["ethereum"]!["config"].signer!.getAddress(),
1292
+ recipient,
1293
+ tokenId
1294
+ );
1295
+ await tx.wait();
1296
+ }
1297
+
1298
+ console.log("โœ… All NFTs distributed!");
1299
+ }
1300
+
1301
+ // Usage
1302
+ await batchMintAndDistribute(
1303
+ sdk,
1304
+ collectionAddress,
1305
+ [
1306
+ "0x1111111111111111111111111111111111111111",
1307
+ "0x2222222222222222222222222222222222222222",
1308
+ "0x3333333333333333333333333333333333333333",
1309
+ ],
1310
+ "ipfs://QmYourTokens/"
1311
+ );
1312
+ ```
1313
+
1314
+ ### Portfolio Management
1315
+
1316
+ ```typescript
1317
+ interface PortfolioItem {
1318
+ collectionAddress: string;
1319
+ collectionId: string;
1320
+ tokenIds: number[];
1321
+ currentValue: string;
1322
+ }
1323
+
1324
+ async function getPortfolio(
1325
+ sdk: FlipmemeSDK,
1326
+ collections: string[],
1327
+ owner: string
1328
+ ): Promise<PortfolioItem[]> {
1329
+ const portfolio: PortfolioItem[] = [];
1330
+
1331
+ for (const collectionAddress of collections) {
1332
+ // Get collection info
1333
+ const info = await sdk.getCollectionInfo(collectionAddress);
1334
+ const collectionId = info[1].toString();
1335
+ const totalMinted = info[4].toNumber();
1336
+
1337
+ // Find owned tokens
1338
+ const tokenIds: number[] = [];
1339
+ for (let i = 0; i < totalMinted; i++) {
1340
+ try {
1341
+ const tokenOwner = await sdk.ownerOf(collectionAddress, i);
1342
+ if (tokenOwner.toLowerCase() === owner.toLowerCase()) {
1343
+ tokenIds.push(i);
1344
+ }
1345
+ } catch {
1346
+ continue;
1347
+ }
1348
+ }
1349
+
1350
+ if (tokenIds.length > 0) {
1351
+ // Calculate current value
1352
+ const value = await sdk.getTotalPrice(
1353
+ PurcahseType.SELL,
1354
+ collectionAddress,
1355
+ tokenIds.length
1356
+ );
1357
+
1358
+ portfolio.push({
1359
+ collectionAddress,
1360
+ collectionId,
1361
+ tokenIds,
1362
+ currentValue: ethers.utils.formatEther(value),
1363
+ });
1364
+ }
1365
+ }
1366
+
1367
+ return portfolio;
1368
+ }
1369
+
1370
+ // Usage
1371
+ const myPortfolio = await getPortfolio(
1372
+ sdk,
1373
+ [collection1, collection2, collection3],
1374
+ await signer.getAddress()
1375
+ );
1376
+
1377
+ console.log("Your Portfolio:");
1378
+ myPortfolio.forEach((item, idx) => {
1379
+ console.log(`\n${idx + 1}. Collection ${item.collectionId}`);
1380
+ console.log(` NFTs owned: ${item.tokenIds.length}`);
1381
+ console.log(` Current value: ${item.currentValue} ETH`);
1382
+ console.log(` Token IDs: ${item.tokenIds.join(", ")}`);
1383
+ });
1384
+ ```
1385
+
1386
+ ### Automated Trading Bot
1387
+
1388
+ ```typescript
1389
+ class FlipBot {
1390
+ private sdk: FlipmemeSDK;
1391
+ private collectionAddress: string;
1392
+ private targetProfit: number; // in percentage
1393
+
1394
+ constructor(
1395
+ sdk: FlipmemeSDK,
1396
+ collectionAddress: string,
1397
+ targetProfit: number = 10
1398
+ ) {
1399
+ this.sdk = sdk;
1400
+ this.collectionAddress = collectionAddress;
1401
+ this.targetProfit = targetProfit;
1402
+ }
1403
+
1404
+ async checkArbitrage() {
1405
+ const currentPrice = await this.sdk.calculatePrice(this.collectionAddress);
1406
+ const info = await this.sdk.getCollectionInfo(this.collectionAddress);
1407
+
1408
+ // Check if there are NFTs in the pool
1409
+ // (You'd need to add a method to check pool size)
1410
+
1411
+ const buyPrice = await this.sdk.getTotalPrice(
1412
+ PurcahseType.BUY,
1413
+ this.collectionAddress,
1414
+ 1
1415
+ );
1416
+
1417
+ const sellPrice = await this.sdk.getTotalPrice(
1418
+ PurcahseType.SELL,
1419
+ this.collectionAddress,
1420
+ 1
1421
+ );
1422
+
1423
+ const buyPriceEth = parseFloat(ethers.utils.formatEther(buyPrice));
1424
+ const sellPriceEth = parseFloat(ethers.utils.formatEther(sellPrice));
1425
+ const profit = ((sellPriceEth - buyPriceEth) / buyPriceEth) * 100;
1426
+
1427
+ console.log(`
1428
+ Buy Price: ${buyPriceEth.toFixed(6)} ETH
1429
+ Sell Price: ${sellPriceEth.toFixed(6)} ETH
1430
+ Potential Profit: ${profit.toFixed(2)}%
1431
+ `);
1432
+
1433
+ return {
1434
+ buyPrice: buyPriceEth,
1435
+ sellPrice: sellPriceEth,
1436
+ profit,
1437
+ shouldTrade: profit >= this.targetProfit,
1438
+ };
1439
+ }
1440
+
1441
+ async executeTrade() {
1442
+ const analysis = await this.checkArbitrage();
1443
+
1444
+ if (analysis.shouldTrade) {
1445
+ console.log(
1446
+ `โœ… Profit opportunity detected: ${analysis.profit.toFixed(2)}%`
1447
+ );
1448
+ console.log("Executing trade...");
1449
+
1450
+ // Buy
1451
+ const buyResult = await this.sdk.buy({
1452
+ collectionAddress: this.collectionAddress,
1453
+ baseUri: "",
1454
+ amount: 0,
1455
+ tokenIds: [0], // You'd need to know available token IDs
1456
+ });
1457
+
1458
+ console.log("Bought NFT");
1459
+
1460
+ // Sell immediately
1461
+ const sellResult = await this.sdk.flipSell({
1462
+ collectionAddress: this.collectionAddress,
1463
+ tokenIds: [0],
1464
+ });
1465
+
1466
+ console.log(`โœ… Trade complete! Profit: ${analysis.profit.toFixed(2)}%`);
1467
+ return true;
1468
+ }
1469
+
1470
+ return false;
1471
+ }
1472
+
1473
+ async monitor(intervalMs: number = 10000) {
1474
+ console.log(`Starting bot with ${this.targetProfit}% profit target...`);
1475
+
1476
+ setInterval(async () => {
1477
+ try {
1478
+ await this.executeTrade();
1479
+ } catch (error) {
1480
+ console.error("Trade failed:", error);
1481
+ }
1482
+ }, intervalMs);
1483
+ }
1484
+ }
1485
+
1486
+ // Usage (use at your own risk!)
1487
+ const bot = new FlipBot(sdk, collectionAddress, 15); // 15% profit target
1488
+ await bot.monitor(5000); // Check every 5 seconds
1489
+ ```
1490
+
1491
+ ---
1492
+
1493
+ ## Error Handling
1494
+
1495
+ ### Common Errors
1496
+
1497
+ #### Insufficient Funds
1498
+
1499
+ ```typescript
1500
+ try {
1501
+ await sdk.buy({
1502
+ collectionAddress,
1503
+ baseUri: "ipfs://...",
1504
+ amount: 10,
1505
+ tokenIds: [],
1506
+ });
1507
+ } catch (error) {
1508
+ if (error.code === "INSUFFICIENT_FUNDS") {
1509
+ console.error("You don't have enough ETH for this transaction");
1510
+ console.error(
1511
+ "Required:",
1512
+ ethers.utils.formatEther(error.transaction?.value || "0")
1513
+ );
1514
+ }
1515
+ }
1516
+ ```
1517
+
1518
+ #### Collection Sold Out
1519
+
1520
+ ```typescript
1521
+ try {
1522
+ await sdk.buy({
1523
+ /* ... */
1524
+ });
1525
+ } catch (error) {
1526
+ if (
1527
+ error.message.includes("sold out") ||
1528
+ error.message.includes("max supply")
1529
+ ) {
1530
+ console.error("Collection is sold out!");
1531
+
1532
+ // Try buying from pool instead
1533
+ await sdk.buy({
1534
+ collectionAddress,
1535
+ baseUri: "",
1536
+ amount: 0,
1537
+ tokenIds: [availableTokenId],
1538
+ });
1539
+ }
1540
+ }
1541
+ ```
1542
+
1543
+ #### User Rejected Transaction
1544
+
1545
+ ```typescript
1546
+ try {
1547
+ await sdk.createCollection({
1548
+ /* ... */
1549
+ });
1550
+ } catch (error) {
1551
+ if (error.code === 4001 || error.code === "ACTION_REJECTED") {
1552
+ console.log("User rejected the transaction");
1553
+ // Show user-friendly message
1554
+ }
1555
+ }
1556
+ ```
1557
+
1558
+ ### Comprehensive Error Handler
1559
+
1560
+ ```typescript
1561
+ async function safeExecute<T>(
1562
+ operation: () => Promise<T>,
1563
+ operationName: string
1564
+ ): Promise<T | null> {
1565
+ try {
1566
+ console.log(`Executing ${operationName}...`);
1567
+ const result = await operation();
1568
+ console.log(`โœ… ${operationName} successful`);
1569
+ return result;
1570
+ } catch (error: any) {
1571
+ console.error(`โŒ ${operationName} failed:`);
1572
+
1573
+ // Ethers errors
1574
+ if (error.code) {
1575
+ switch (error.code) {
1576
+ case "INSUFFICIENT_FUNDS":
1577
+ console.error("Insufficient funds for transaction");
1578
+ break;
1579
+ case "ACTION_REJECTED":
1580
+ console.error("User rejected transaction");
1581
+ break;
1582
+ case "UNPREDICTABLE_GAS_LIMIT":
1583
+ console.error("Cannot estimate gas - transaction may fail");
1584
+ break;
1585
+ case "NETWORK_ERROR":
1586
+ console.error("Network error - check your connection");
1587
+ break;
1588
+ default:
1589
+ console.error(`Error code: ${error.code}`);
1590
+ }
1591
+ }
1592
+
1593
+ // Contract revert errors
1594
+ if (error.reason) {
1595
+ console.error("Contract error:", error.reason);
1596
+ }
1597
+
1598
+ // Full error details
1599
+ console.error("Full error:", error.message);
1600
+
1601
+ return null;
1602
+ }
1603
+ }
1604
+
1605
+ // Usage
1606
+ const result = await safeExecute(
1607
+ () =>
1608
+ sdk.buy({
1609
+ collectionAddress,
1610
+ baseUri: "ipfs://...",
1611
+ amount: 5,
1612
+ tokenIds: [],
1613
+ }),
1614
+ "NFT Purchase"
1615
+ );
1616
+
1617
+ if (result) {
1618
+ console.log("Success:", result);
1619
+ }
1620
+ ```
1621
+
1622
+ ### Retry Logic
1623
+
1624
+ ```typescript
1625
+ async function withRetry<T>(
1626
+ operation: () => Promise<T>,
1627
+ maxRetries: number = 3,
1628
+ delayMs: number = 1000
1629
+ ): Promise<T> {
1630
+ let lastError: Error;
1631
+
1632
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1633
+ try {
1634
+ return await operation();
1635
+ } catch (error: any) {
1636
+ lastError = error;
1637
+ console.log(`Attempt ${attempt} failed:`, error.message);
1638
+
1639
+ // Don't retry user rejections
1640
+ if (error.code === 4001 || error.code === "ACTION_REJECTED") {
1641
+ throw error;
1642
+ }
1643
+
1644
+ if (attempt < maxRetries) {
1645
+ console.log(`Retrying in ${delayMs}ms...`);
1646
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1647
+ delayMs *= 2; // Exponential backoff
1648
+ }
1649
+ }
1650
+ }
1651
+
1652
+ throw lastError!;
1653
+ }
1654
+
1655
+ // Usage
1656
+ const result = await withRetry(
1657
+ () =>
1658
+ sdk.buy({
1659
+ /* ... */
1660
+ }),
1661
+ 3,
1662
+ 2000
1663
+ );
1664
+ ```
1665
+
1666
+ ---
1667
+
1668
+ ## Best Practices
1669
+
1670
+ ### 1. Always Check Prices Before Buying
1671
+
1672
+ ```typescript
1673
+ // โŒ Bad: Blind purchase
1674
+ await sdk.buy({ collectionAddress, amount: 5, tokenIds: [], baseUri: "..." });
1675
+
1676
+ // โœ… Good: Check price first
1677
+ const estimatedPrice = await sdk.getTotalPrice(
1678
+ PurcahseType.BUY,
1679
+ collectionAddress,
1680
+ 5
1681
+ );
1682
+ console.log("This will cost:", ethers.utils.formatEther(estimatedPrice), "ETH");
1683
+
1684
+ const userConfirmed = await confirmWithUser(estimatedPrice);
1685
+ if (userConfirmed) {
1686
+ await sdk.buy({ collectionAddress, amount: 5, tokenIds: [], baseUri: "..." });
1687
+ }
1688
+ ```
1689
+
1690
+ ### 2. Handle Collection State
1691
+
1692
+ ```typescript
1693
+ // โœ… Check if collection is sold out before minting
1694
+ const info = await sdk.getCollectionInfo(collectionAddress);
1695
+ const remaining = info[3].sub(info[4]).toNumber();
1696
+
1697
+ if (remaining === 0) {
1698
+ console.log("Collection sold out! Buying from pool instead...");
1699
+ // Buy from liquidity pool
1700
+ } else {
1701
+ console.log(`${remaining} NFTs remaining`);
1702
+ // Mint new NFTs
1703
+ }
1704
+ ```
1705
+
1706
+ ### 3. Use Environment Variables
1707
+
1708
+ ```typescript
1709
+ // โœ… Good: Secure configuration
1710
+ import dotenv from "dotenv";
1711
+ dotenv.config();
1712
+
1713
+ const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
1714
+ const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
1715
+
1716
+ const sdk = new FlipmemeSDK(
1717
+ BlockchainType.ETHEREUM,
1718
+ process.env.NODE_ENV === "production" ? PLATFORM.PROD : PLATFORM.DEV,
1719
+ { signer, chainId: parseInt(process.env.CHAIN_ID!), provider }
1720
+ );
1721
+ ```
1722
+
1723
+ ### 4. Implement Proper Error Handling
1724
+
1725
+ ```typescript
1726
+ // โœ… Comprehensive error handling
1727
+ try {
1728
+ const result = await sdk.createCollection({
1729
+ name: "My Collection",
1730
+ symbol: "MC",
1731
+ totalSupply: 100,
1732
+ sessionId: `session-${Date.now()}`,
1733
+ tokenUri: "ipfs://...",
1734
+ });
1735
+
1736
+ // Log success
1737
+ console.log("Collection created:", result.collectionAddress);
1738
+
1739
+ // Store in database
1740
+ await database.saveCollection(result);
1741
+ } catch (error: any) {
1742
+ // Log for debugging
1743
+ console.error("Collection creation failed:", error);
1744
+
1745
+ // User-friendly message
1746
+ if (error.code === "INSUFFICIENT_FUNDS") {
1747
+ alert("You need more ETH to create a collection");
1748
+ } else if (error.code === "ACTION_REJECTED") {
1749
+ alert("Transaction was cancelled");
1750
+ } else {
1751
+ alert("Failed to create collection. Please try again.");
1752
+ }
1753
+
1754
+ // Track error
1755
+ analytics.trackError("create_collection_failed", error);
1756
+ }
1757
+ ```
1758
+
1759
+ ### 5. Optimize Gas Usage
1760
+
1761
+ ```typescript
1762
+ // โœ… Use profileSell for multiple collections
1763
+ // Instead of:
1764
+ await sdk.flipSell({ collectionAddress: addr1, tokenIds: [1, 2] });
1765
+ await sdk.flipSell({ collectionAddress: addr2, tokenIds: [3, 4] });
1766
+
1767
+ // Do this (saves ~30% gas):
1768
+ await sdk.profileSell({
1769
+ data: {
1770
+ [collectionId1]: { tokenIds: [1, 2], collectionId: collectionId1 },
1771
+ [collectionId2]: { tokenIds: [3, 4], collectionId: collectionId2 },
1772
+ },
1773
+ slippage: 0,
1774
+ });
1775
+ ```
1776
+
1777
+ ### 6. Monitor Transaction Status
1778
+
1779
+ ```typescript
1780
+ async function buyWithConfirmation(sdk: FlipmemeSDK, params: EthBuyParams) {
1781
+ console.log("Initiating purchase...");
1782
+
1783
+ // Start transaction
1784
+ const result = await sdk.buy(params);
1785
+
1786
+ console.log("Transaction submitted, waiting for confirmation...");
1787
+
1788
+ // Get transaction hash (would need to modify SDK to return this)
1789
+ // const txHash = result.transactionHash;
1790
+
1791
+ // Wait for confirmations
1792
+ // const receipt = await provider.waitForTransaction(txHash, 2);
1793
+
1794
+ console.log("โœ… Confirmed!");
1795
+ return result;
1796
+ }
1797
+ ```
1798
+
1799
+ ### 7. Cache Collection Data
1800
+
1801
+ ```typescript
1802
+ class CollectionCache {
1803
+ private cache = new Map<string, { data: any; timestamp: number }>();
1804
+ private ttl = 60000; // 1 minute
1805
+
1806
+ async getCollectionInfo(sdk: FlipmemeSDK, address: string) {
1807
+ const cached = this.cache.get(address);
1808
+
1809
+ if (cached && Date.now() - cached.timestamp < this.ttl) {
1810
+ return cached.data;
1811
+ }
1812
+
1813
+ const data = await sdk.getCollectionInfo(address);
1814
+ this.cache.set(address, { data, timestamp: Date.now() });
1815
+ return data;
1816
+ }
1817
+
1818
+ invalidate(address: string) {
1819
+ this.cache.delete(address);
1820
+ }
1821
+
1822
+ clear() {
1823
+ this.cache.clear();
1824
+ }
1825
+ }
1826
+
1827
+ // Usage
1828
+ const cache = new CollectionCache();
1829
+ const info = await cache.getCollectionInfo(sdk, collectionAddress);
1830
+ ```
1831
+
1832
+ ### 8. Test on Testnet First
1833
+
1834
+ ```typescript
1835
+ // โœ… Always test on testnet before mainnet
1836
+ const TESTNET_CONFIG = {
1837
+ chainId: 84532, // Base Sepolia
1838
+ rpcUrl: "https://sepolia.base.org",
1839
+ explorer: "https://sepolia.basescan.org",
1840
+ };
1841
+
1842
+ const MAINNET_CONFIG = {
1843
+ chainId: 8453, // Base Mainnet
1844
+ rpcUrl: "https://mainnet.base.org",
1845
+ explorer: "https://basescan.org",
1846
+ };
1847
+
1848
+ const config =
1849
+ process.env.USE_TESTNET === "true" ? TESTNET_CONFIG : MAINNET_CONFIG;
1850
+ ```
1851
+
1852
+ ---
1853
+
1854
+ ## Examples
1855
+
1856
+ ### Complete DApp Integration
1857
+
1858
+ ```typescript
1859
+ import { ethers } from "ethers";
1860
+ import {
1861
+ FlipmemeSDK,
1862
+ BlockchainType,
1863
+ PLATFORM,
1864
+ PurcahseType,
1865
+ } from "flipmeme-sdk";
1866
+
1867
+ class FlipNFT {
1868
+ private sdk: FlipmemeSDK;
1869
+ private provider: ethers.providers.Web3Provider;
1870
+ private signer: ethers.Signer;
1871
+
1872
+ async initialize() {
1873
+ // Connect to MetaMask
1874
+ if (!window.ethereum) {
1875
+ throw new Error("Please install MetaMask");
1876
+ }
1877
+
1878
+ this.provider = new ethers.providers.Web3Provider(window.ethereum);
1879
+ await this.provider.send("eth_requestAccounts", []);
1880
+ this.signer = this.provider.getSigner();
1881
+
1882
+ // Initialize SDK
1883
+ const network = await this.provider.getNetwork();
1884
+ this.sdk = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
1885
+ signer: this.signer,
1886
+ chainId: network.chainId,
1887
+ provider: this.provider,
1888
+ });
1889
+
1890
+ console.log("Connected:", await this.signer.getAddress());
1891
+ }
1892
+
1893
+ async createCollection(params: {
1894
+ name: string;
1895
+ symbol: string;
1896
+ totalSupply: number;
1897
+ premint: number;
1898
+ metadataUri: string;
1899
+ }) {
1900
+ try {
1901
+ const { collectionId, collectionAddress } =
1902
+ await this.sdk.createCollection({
1903
+ name: params.name,
1904
+ symbol: params.symbol,
1905
+ totalSupply: params.totalSupply,
1906
+ premint: params.premint,
1907
+ sessionId: `create-${Date.now()}-${Math.random()}`,
1908
+ tokenUri: params.metadataUri,
1909
+ startPrice: ethers.utils.parseEther("0.001").toString(),
1910
+ endPrice: ethers.utils.parseEther("0.1").toString(),
1911
+ });
1912
+
1913
+ console.log("โœ… Collection created!");
1914
+ console.log("ID:", collectionId);
1915
+ console.log("Address:", collectionAddress);
1916
+
1917
+ return { collectionId, collectionAddress };
1918
+ } catch (error) {
1919
+ console.error("Failed to create collection:", error);
1920
+ throw error;
1921
+ }
1922
+ }
1923
+
1924
+ async buyNFTs(collectionAddress: string, amount: number, baseUri: string) {
1925
+ try {
1926
+ // Get price quote
1927
+ const totalPrice = await this.sdk.getTotalPrice(
1928
+ PurcahseType.BUY,
1929
+ collectionAddress,
1930
+ amount
1931
+ );
1932
+
1933
+ console.log(
1934
+ `Buying ${amount} NFTs for ${ethers.utils.formatEther(totalPrice)} ETH`
1935
+ );
1936
+
1937
+ // Execute purchase
1938
+ const result = await this.sdk.buy({
1939
+ collectionAddress,
1940
+ baseUri,
1941
+ amount,
1942
+ tokenIds: [],
1943
+ });
1944
+
1945
+ console.log(`โœ… Purchased ${result.successCount} NFTs`);
1946
+ return result;
1947
+ } catch (error) {
1948
+ console.error("Purchase failed:", error);
1949
+ throw error;
1950
+ }
1951
+ }
1952
+
1953
+ async sellNFTs(collectionAddress: string, tokenIds: number[]) {
1954
+ try {
1955
+ // Get sell quote
1956
+ const totalPrice = await this.sdk.getTotalPrice(
1957
+ PurcahseType.SELL,
1958
+ collectionAddress,
1959
+ tokenIds.length
1960
+ );
1961
+
1962
+ console.log(
1963
+ `Selling ${tokenIds.length} NFTs for ${ethers.utils.formatEther(
1964
+ totalPrice
1965
+ )} ETH`
1966
+ );
1967
+
1968
+ // Execute sale
1969
+ const result = await this.sdk.flipSell({
1970
+ collectionAddress,
1971
+ tokenIds,
1972
+ });
1973
+
1974
+ console.log(`โœ… Sold ${result.successCount} NFTs`);
1975
+ return result;
1976
+ } catch (error) {
1977
+ console.error("Sale failed:", error);
1978
+ throw error;
1979
+ }
1980
+ }
1981
+
1982
+ async getMyNFTs(collectionAddress: string): Promise<number[]> {
1983
+ const myAddress = await this.signer.getAddress();
1984
+ const balance = await this.sdk.balanceOf(collectionAddress, myAddress);
1985
+ const totalSupply = await this.sdk.totalSupply(collectionAddress);
1986
+
1987
+ const myTokens: number[] = [];
1988
+
1989
+ for (let i = 0; i < parseInt(totalSupply); i++) {
1990
+ try {
1991
+ const owner = await this.sdk.ownerOf(collectionAddress, i);
1992
+ if (owner.toLowerCase() === myAddress.toLowerCase()) {
1993
+ myTokens.push(i);
1994
+ }
1995
+ } catch {
1996
+ continue;
1997
+ }
1998
+ }
1999
+
2000
+ return myTokens;
2001
+ }
2002
+
2003
+ async getCollectionStats(collectionAddress: string) {
2004
+ const info = await this.sdk.getCollectionInfo(collectionAddress);
2005
+ const currentPrice = await this.sdk.calculatePrice(collectionAddress);
2006
+
2007
+ return {
2008
+ creator: info[2],
2009
+ maxSupply: info[3].toNumber(),
2010
+ minted: info[4].toNumber(),
2011
+ remaining: info[3].sub(info[4]).toNumber(),
2012
+ isSoldOut: info[5],
2013
+ currentPrice: ethers.utils.formatEther(currentPrice),
2014
+ progress: (info[4].toNumber() / info[3].toNumber()) * 100,
2015
+ };
2016
+ }
2017
+ }
2018
+
2019
+ // Usage
2020
+ const app = new FlipNFT();
2021
+ await app.initialize();
2022
+
2023
+ // Create collection
2024
+ const { collectionAddress } = await app.createCollection({
2025
+ name: "Cool Cats",
2026
+ symbol: "COOL",
2027
+ totalSupply: 100,
2028
+ premint: 5,
2029
+ metadataUri: "ipfs://QmYourMetadata/",
2030
+ });
2031
+
2032
+ // Buy NFTs
2033
+ await app.buyNFTs(collectionAddress, 3, "ipfs://QmYourTokens/");
2034
+
2035
+ // Check stats
2036
+ const stats = await app.getCollectionStats(collectionAddress);
2037
+ console.log("Collection Stats:", stats);
2038
+
2039
+ // Get my NFTs
2040
+ const myNFTs = await app.getMyNFTs(collectionAddress);
2041
+ console.log("My NFTs:", myNFTs);
2042
+
2043
+ // Sell some
2044
+ if (myNFTs.length > 0) {
2045
+ await app.sellNFTs(collectionAddress, myNFTs.slice(0, 2));
2046
+ }
2047
+ ```
2048
+
2049
+ ### React Integration Example
2050
+
2051
+ ```typescript
2052
+ // hooks/useFlipmeme.ts
2053
+ import { useState, useEffect } from "react";
2054
+ import { ethers } from "ethers";
2055
+ import { FlipmemeSDK, BlockchainType, PLATFORM } from "flipmeme-sdk";
2056
+
2057
+ export function useFlipmeme() {
2058
+ const [sdk, setSdk] = useState<FlipmemeSDK | null>(null);
2059
+ const [isConnected, setIsConnected] = useState(false);
2060
+ const [address, setAddress] = useState<string>("");
2061
+
2062
+ useEffect(() => {
2063
+ initializeSDK();
2064
+ }, []);
2065
+
2066
+ async function initializeSDK() {
2067
+ if (!window.ethereum) return;
2068
+
2069
+ try {
2070
+ const provider = new ethers.providers.Web3Provider(window.ethereum);
2071
+ await provider.send("eth_requestAccounts", []);
2072
+ const signer = provider.getSigner();
2073
+ const network = await provider.getNetwork();
2074
+ const userAddress = await signer.getAddress();
2075
+
2076
+ const flipSDK = new FlipmemeSDK(BlockchainType.ETHEREUM, PLATFORM.PROD, {
2077
+ signer,
2078
+ chainId: network.chainId,
2079
+ provider,
2080
+ });
2081
+
2082
+ setSdk(flipSDK);
2083
+ setIsConnected(true);
2084
+ setAddress(userAddress);
2085
+ } catch (error) {
2086
+ console.error("Failed to initialize SDK:", error);
2087
+ }
2088
+ }
2089
+
2090
+ return { sdk, isConnected, address, initialize: initializeSDK };
2091
+ }
2092
+
2093
+ // components/CollectionCard.tsx
2094
+ import React, { useState, useEffect } from "react";
2095
+ import { useFlipmeme } from "../hooks/useFlipmeme";
2096
+
2097
+ interface CollectionCardProps {
2098
+ collectionAddress: string;
2099
+ }
2100
+
2101
+ export function CollectionCard({ collectionAddress }: CollectionCardProps) {
2102
+ const { sdk } = useFlipmeme();
2103
+ const [stats, setStats] = useState<any>(null);
2104
+ const [loading, setLoading] = useState(true);
2105
+
2106
+ useEffect(() => {
2107
+ loadStats();
2108
+ }, [sdk, collectionAddress]);
2109
+
2110
+ async function loadStats() {
2111
+ if (!sdk) return;
2112
+
2113
+ try {
2114
+ setLoading(true);
2115
+ const info = await sdk.getCollectionInfo(collectionAddress);
2116
+ const price = await sdk.calculatePrice(collectionAddress);
2117
+
2118
+ setStats({
2119
+ minted: info[4].toNumber(),
2120
+ maxSupply: info[3].toNumber(),
2121
+ isSoldOut: info[5],
2122
+ currentPrice: ethers.utils.formatEther(price),
2123
+ });
2124
+ } catch (error) {
2125
+ console.error("Failed to load stats:", error);
2126
+ } finally {
2127
+ setLoading(false);
2128
+ }
2129
+ }
2130
+
2131
+ if (loading) return <div>Loading...</div>;
2132
+ if (!stats) return <div>Error loading collection</div>;
2133
+
2134
+ return (
2135
+ <div className="collection-card">
2136
+ <h3>Collection Stats</h3>
2137
+ <p>
2138
+ Minted: {stats.minted} / {stats.maxSupply}
2139
+ </p>
2140
+ <p>Current Price: {stats.currentPrice} ETH</p>
2141
+ {stats.isSoldOut && <p className="sold-out">SOLD OUT</p>}
2142
+ <button onClick={loadStats}>Refresh</button>
2143
+ </div>
2144
+ );
2145
+ }
2146
+ ```
2147
+
2148
+ ---
2149
+
2150
+ ## Changelog
2151
+
2152
+ ### Version 1.0.0
2153
+
2154
+ - Initial EVM SDK release
2155
+ - Support for Base network
2156
+ - Core collection and trading functionality
2157
+ - Bonding curve pricing system
2158
+ - Multi-collection batch operations
2159
+
2160
+ ---
2161
+
2162
+ ## Support & Resources
2163
+
2164
+ ### Documentation
2165
+
2166
+ - **GitHub**: [flipmeme-sdk repository]
2167
+ - **API Docs**: This document
2168
+ - **Examples**: `/demo/eth/` directory
2169
+
2170
+ ### Community
2171
+
2172
+ - **Discord**: [Join our community]
2173
+ - **Twitter**: [@flipmeme]
2174
+ - **Support**: support@flipmeme.com
2175
+
2176
+ ### Security
2177
+
2178
+ For security concerns, please email security@flipmeme.com
2179
+
2180
+ ---
2181
+
2182
+ ## License
2183
+
2184
+ [License Type] - See LICENSE file for details
2185
+
2186
+ ---
2187
+
2188
+ **Last Updated**: October 6, 2025
2189
+ **SDK Version**: 1.0.0
2190
+ **Compatible Networks**: Ethereum, Base, EVM-compatible chains