@net-protocol/bazaar 0.1.0

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/dist/react.js ADDED
@@ -0,0 +1,1397 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var react$1 = require('@net-protocol/core/react');
5
+ var viem = require('viem');
6
+ var core = require('@net-protocol/core');
7
+ var seaportJs = require('@opensea/seaport-js');
8
+ var ethers = require('ethers');
9
+ var actions = require('viem/actions');
10
+
11
+ // src/hooks/useBazaarListings.ts
12
+
13
+ // src/abis/helpers.ts
14
+ var BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI = [
15
+ { type: "constructor", inputs: [], stateMutability: "nonpayable" },
16
+ {
17
+ type: "function",
18
+ name: "getOrderStatuses",
19
+ inputs: [
20
+ { name: "seaport", type: "address", internalType: "address" },
21
+ { name: "orderHashes", type: "bytes32[]", internalType: "bytes32[]" }
22
+ ],
23
+ outputs: [
24
+ {
25
+ name: "results",
26
+ type: "tuple[]",
27
+ internalType: "struct BulkSeaportOrderStatusFetcher.OrderStatusInfo[]",
28
+ components: [
29
+ { name: "isValidated", type: "bool", internalType: "bool" },
30
+ { name: "isCancelled", type: "bool", internalType: "bool" },
31
+ { name: "totalFilled", type: "uint256", internalType: "uint256" },
32
+ { name: "totalSize", type: "uint256", internalType: "uint256" }
33
+ ]
34
+ }
35
+ ],
36
+ stateMutability: "view"
37
+ }
38
+ ];
39
+ var ERC721_OWNER_OF_HELPER_ABI = [
40
+ {
41
+ type: "function",
42
+ name: "getTokenOwners",
43
+ inputs: [
44
+ { name: "nftContract", type: "address", internalType: "address" },
45
+ { name: "tokenIds", type: "uint256[]", internalType: "uint256[]" }
46
+ ],
47
+ outputs: [
48
+ { name: "owners", type: "address[]", internalType: "address[]" }
49
+ ],
50
+ stateMutability: "view"
51
+ },
52
+ { type: "error", name: "InvalidAddress", inputs: [] },
53
+ { type: "error", name: "TokenQueryFailed", inputs: [] }
54
+ ];
55
+ var ERC20_BULK_BALANCE_CHECKER_ABI = [
56
+ {
57
+ type: "function",
58
+ name: "getBalances",
59
+ inputs: [
60
+ { name: "token", type: "address", internalType: "address" },
61
+ { name: "addresses", type: "address[]", internalType: "address[]" }
62
+ ],
63
+ outputs: [
64
+ { name: "balances", type: "uint256[]", internalType: "uint256[]" }
65
+ ],
66
+ stateMutability: "view"
67
+ }
68
+ ];
69
+
70
+ // src/abis/seaport.ts
71
+ var SEAPORT_CANCEL_ABI = [
72
+ {
73
+ inputs: [
74
+ {
75
+ components: [
76
+ { internalType: "address", name: "offerer", type: "address" },
77
+ { internalType: "address", name: "zone", type: "address" },
78
+ {
79
+ components: [
80
+ { internalType: "enum ItemType", name: "itemType", type: "uint8" },
81
+ { internalType: "address", name: "token", type: "address" },
82
+ { internalType: "uint256", name: "identifierOrCriteria", type: "uint256" },
83
+ { internalType: "uint256", name: "startAmount", type: "uint256" },
84
+ { internalType: "uint256", name: "endAmount", type: "uint256" }
85
+ ],
86
+ internalType: "struct OfferItem[]",
87
+ name: "offer",
88
+ type: "tuple[]"
89
+ },
90
+ {
91
+ components: [
92
+ { internalType: "enum ItemType", name: "itemType", type: "uint8" },
93
+ { internalType: "address", name: "token", type: "address" },
94
+ { internalType: "uint256", name: "identifierOrCriteria", type: "uint256" },
95
+ { internalType: "uint256", name: "startAmount", type: "uint256" },
96
+ { internalType: "uint256", name: "endAmount", type: "uint256" },
97
+ { internalType: "address payable", name: "recipient", type: "address" }
98
+ ],
99
+ internalType: "struct ConsiderationItem[]",
100
+ name: "consideration",
101
+ type: "tuple[]"
102
+ },
103
+ { internalType: "enum OrderType", name: "orderType", type: "uint8" },
104
+ { internalType: "uint256", name: "startTime", type: "uint256" },
105
+ { internalType: "uint256", name: "endTime", type: "uint256" },
106
+ { internalType: "bytes32", name: "zoneHash", type: "bytes32" },
107
+ { internalType: "uint256", name: "salt", type: "uint256" },
108
+ { internalType: "bytes32", name: "conduitKey", type: "bytes32" },
109
+ { internalType: "uint256", name: "counter", type: "uint256" }
110
+ ],
111
+ internalType: "struct OrderComponents[]",
112
+ name: "orders",
113
+ type: "tuple[]"
114
+ }
115
+ ],
116
+ name: "cancel",
117
+ outputs: [{ internalType: "bool", name: "cancelled", type: "bool" }],
118
+ stateMutability: "nonpayable",
119
+ type: "function"
120
+ }
121
+ ];
122
+
123
+ // src/abis/index.ts
124
+ var BAZAAR_SUBMISSION_ABI = [
125
+ {
126
+ name: "submission",
127
+ type: "tuple",
128
+ internalType: "struct BazaarV2.Submission",
129
+ components: [
130
+ {
131
+ name: "parameters",
132
+ type: "tuple",
133
+ internalType: "struct OrderParameters",
134
+ components: [
135
+ { name: "offerer", type: "address", internalType: "address" },
136
+ { name: "zone", type: "address", internalType: "address" },
137
+ {
138
+ name: "offer",
139
+ type: "tuple[]",
140
+ internalType: "struct OfferItem[]",
141
+ components: [
142
+ { name: "itemType", type: "uint8", internalType: "enum ItemType" },
143
+ { name: "token", type: "address", internalType: "address" },
144
+ { name: "identifierOrCriteria", type: "uint256", internalType: "uint256" },
145
+ { name: "startAmount", type: "uint256", internalType: "uint256" },
146
+ { name: "endAmount", type: "uint256", internalType: "uint256" }
147
+ ]
148
+ },
149
+ {
150
+ name: "consideration",
151
+ type: "tuple[]",
152
+ internalType: "struct ConsiderationItem[]",
153
+ components: [
154
+ { name: "itemType", type: "uint8", internalType: "enum ItemType" },
155
+ { name: "token", type: "address", internalType: "address" },
156
+ { name: "identifierOrCriteria", type: "uint256", internalType: "uint256" },
157
+ { name: "startAmount", type: "uint256", internalType: "uint256" },
158
+ { name: "endAmount", type: "uint256", internalType: "uint256" },
159
+ { name: "recipient", type: "address", internalType: "address payable" }
160
+ ]
161
+ },
162
+ { name: "orderType", type: "uint8", internalType: "enum OrderType" },
163
+ { name: "startTime", type: "uint256", internalType: "uint256" },
164
+ { name: "endTime", type: "uint256", internalType: "uint256" },
165
+ { name: "zoneHash", type: "bytes32", internalType: "bytes32" },
166
+ { name: "salt", type: "uint256", internalType: "uint256" },
167
+ { name: "conduitKey", type: "bytes32", internalType: "bytes32" },
168
+ { name: "totalOriginalConsiderationItems", type: "uint256", internalType: "uint256" }
169
+ ]
170
+ },
171
+ { name: "counter", type: "uint256", internalType: "uint256" },
172
+ { name: "signature", type: "bytes", internalType: "bytes" }
173
+ ]
174
+ }
175
+ ];
176
+
177
+ // src/chainConfig.ts
178
+ var DEFAULT_SEAPORT_ADDRESS = "0x0000000000000068F116a894984e2DB1123eB395";
179
+ var DEFAULT_BAZAAR_ADDRESS = "0x00000000E3dA5fC031282A39759bDDA78ae7fAE5";
180
+ var DEFAULT_COLLECTION_OFFERS_ADDRESS = "0x0000000D43423E0A12CecB307a74591999b32B32";
181
+ var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5";
182
+ var DEFAULT_NFT_FEE_BPS = 500;
183
+ var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
184
+ var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
185
+ var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000b50a9f2923f2db931391824f6d1278f712";
186
+ var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
187
+ var BAZAAR_CHAIN_CONFIGS = {
188
+ // Base Mainnet
189
+ 8453: {
190
+ bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
191
+ collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
192
+ erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
193
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
194
+ feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
195
+ nftFeeBps: 0,
196
+ // 0% on Base
197
+ wrappedNativeCurrency: {
198
+ address: "0x4200000000000000000000000000000000000006",
199
+ name: "Wrapped Ether",
200
+ symbol: "WETH"
201
+ },
202
+ currencySymbol: "eth"
203
+ },
204
+ // Base Sepolia (Testnet)
205
+ 84532: {
206
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
207
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
208
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
209
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
210
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
211
+ wrappedNativeCurrency: {
212
+ address: "0x4200000000000000000000000000000000000006",
213
+ name: "Wrapped Ether",
214
+ symbol: "WETH"
215
+ },
216
+ currencySymbol: "eth"
217
+ },
218
+ // Degen
219
+ 666666666: {
220
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
221
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
222
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
223
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
224
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
225
+ wrappedNativeCurrency: {
226
+ address: "0xEb54dACB4C2ccb64F8074eceEa33b5eBb38E5387",
227
+ name: "Wrapped Degen",
228
+ symbol: "WDEGEN"
229
+ },
230
+ currencySymbol: "degen"
231
+ },
232
+ // Ham Chain
233
+ 5112: {
234
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
235
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
236
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
237
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
238
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
239
+ wrappedNativeCurrency: {
240
+ address: "0x4200000000000000000000000000000000000006",
241
+ name: "Wrapped Ether",
242
+ symbol: "WETH"
243
+ },
244
+ highEthAddress: "0x4200000000000000000000000000000000000006",
245
+ currencySymbol: "eth"
246
+ },
247
+ // Ink Chain
248
+ 57073: {
249
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
250
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
251
+ // Custom Seaport address for Ink (no create2 factory)
252
+ seaportAddress: "0xD00C96804e9fF35f10C7D2a92239C351Ff3F94e5",
253
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
254
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
255
+ wrappedNativeCurrency: {
256
+ address: "0x4200000000000000000000000000000000000006",
257
+ name: "Wrapped ETH",
258
+ symbol: "WETH"
259
+ },
260
+ highEthAddress: "0x4200000000000000000000000000000000000006",
261
+ currencySymbol: "eth"
262
+ },
263
+ // Unichain
264
+ 130: {
265
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
266
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
267
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
268
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
269
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
270
+ wrappedNativeCurrency: {
271
+ address: "0x4200000000000000000000000000000000000006",
272
+ name: "Wrapped Ether",
273
+ symbol: "WETH"
274
+ },
275
+ currencySymbol: "eth"
276
+ },
277
+ // HyperEVM (Hyperliquid)
278
+ 999: {
279
+ bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
280
+ collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
281
+ erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
282
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
283
+ feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
284
+ nftFeeBps: 0,
285
+ // 0% on HyperEVM
286
+ wrappedNativeCurrency: {
287
+ address: "0x5555555555555555555555555555555555555555",
288
+ name: "Wrapped Hype",
289
+ symbol: "WHYPE"
290
+ },
291
+ currencySymbol: "hype"
292
+ },
293
+ // Plasma
294
+ 9745: {
295
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
296
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
297
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
298
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
299
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
300
+ wrappedNativeCurrency: {
301
+ address: "0x6100e367285b01f48d07953803a2d8dca5d19873",
302
+ name: "Wrapped XPL",
303
+ symbol: "WXPL"
304
+ },
305
+ currencySymbol: "xpl"
306
+ },
307
+ // Monad
308
+ 143: {
309
+ bazaarAddress: DEFAULT_BAZAAR_ADDRESS,
310
+ collectionOffersAddress: DEFAULT_COLLECTION_OFFERS_ADDRESS,
311
+ seaportAddress: DEFAULT_SEAPORT_ADDRESS,
312
+ feeCollectorAddress: DEFAULT_FEE_COLLECTOR_ADDRESS,
313
+ nftFeeBps: DEFAULT_NFT_FEE_BPS,
314
+ wrappedNativeCurrency: {
315
+ address: "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
316
+ name: "Wrapped Monad",
317
+ symbol: "WMONAD"
318
+ },
319
+ currencySymbol: "monad"
320
+ }
321
+ };
322
+ function getBazaarChainConfig(chainId) {
323
+ return BAZAAR_CHAIN_CONFIGS[chainId];
324
+ }
325
+ function isBazaarSupportedOnChain(chainId) {
326
+ return chainId in BAZAAR_CHAIN_CONFIGS;
327
+ }
328
+ function getBazaarAddress(chainId) {
329
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.bazaarAddress ?? DEFAULT_BAZAAR_ADDRESS;
330
+ }
331
+ function getCollectionOffersAddress(chainId) {
332
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.collectionOffersAddress ?? DEFAULT_COLLECTION_OFFERS_ADDRESS;
333
+ }
334
+ function getSeaportAddress(chainId) {
335
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.seaportAddress ?? DEFAULT_SEAPORT_ADDRESS;
336
+ }
337
+ function getWrappedNativeCurrency(chainId) {
338
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.wrappedNativeCurrency;
339
+ }
340
+ function getCurrencySymbol(chainId) {
341
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.currencySymbol ?? "eth";
342
+ }
343
+ function getHighEthAddress(chainId) {
344
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.highEthAddress;
345
+ }
346
+ function getErc20OffersAddress(chainId) {
347
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20OffersAddress;
348
+ }
349
+ function decodeSeaportSubmission(messageData) {
350
+ const [decoded] = viem.decodeAbiParameters(BAZAAR_SUBMISSION_ABI, messageData);
351
+ return {
352
+ parameters: {
353
+ offerer: decoded.parameters.offerer,
354
+ zone: decoded.parameters.zone,
355
+ offer: decoded.parameters.offer.map((item) => ({
356
+ itemType: item.itemType,
357
+ token: item.token,
358
+ identifierOrCriteria: BigInt(item.identifierOrCriteria),
359
+ startAmount: BigInt(item.startAmount),
360
+ endAmount: BigInt(item.endAmount)
361
+ })),
362
+ consideration: decoded.parameters.consideration.map((item) => ({
363
+ itemType: item.itemType,
364
+ token: item.token,
365
+ identifierOrCriteria: BigInt(item.identifierOrCriteria),
366
+ startAmount: BigInt(item.startAmount),
367
+ endAmount: BigInt(item.endAmount),
368
+ recipient: item.recipient
369
+ })),
370
+ orderType: decoded.parameters.orderType,
371
+ startTime: BigInt(decoded.parameters.startTime),
372
+ endTime: BigInt(decoded.parameters.endTime),
373
+ zoneHash: decoded.parameters.zoneHash,
374
+ salt: BigInt(decoded.parameters.salt),
375
+ conduitKey: decoded.parameters.conduitKey,
376
+ totalOriginalConsiderationItems: BigInt(decoded.parameters.totalOriginalConsiderationItems)
377
+ },
378
+ counter: BigInt(decoded.counter),
379
+ signature: decoded.signature
380
+ };
381
+ }
382
+ function getSeaportOrderFromMessageData(messageData) {
383
+ const submission = decodeSeaportSubmission(messageData);
384
+ return {
385
+ parameters: {
386
+ ...submission.parameters,
387
+ // Convert BigInts to strings for Seaport SDK compatibility
388
+ offer: submission.parameters.offer.map((item) => ({
389
+ ...item,
390
+ identifierOrCriteria: item.identifierOrCriteria.toString(),
391
+ startAmount: item.startAmount.toString(),
392
+ endAmount: item.endAmount.toString()
393
+ })),
394
+ consideration: submission.parameters.consideration.map((item) => ({
395
+ ...item,
396
+ identifierOrCriteria: item.identifierOrCriteria.toString(),
397
+ startAmount: item.startAmount.toString(),
398
+ endAmount: item.endAmount.toString()
399
+ })),
400
+ startTime: submission.parameters.startTime.toString(),
401
+ endTime: submission.parameters.endTime.toString(),
402
+ salt: submission.parameters.salt.toString(),
403
+ totalOriginalConsiderationItems: submission.parameters.totalOriginalConsiderationItems.toString(),
404
+ counter: submission.counter.toString()
405
+ },
406
+ signature: submission.signature,
407
+ counter: submission.counter
408
+ };
409
+ }
410
+ function createSeaportInstance(chainId, rpcUrl) {
411
+ const provider = new ethers.ethers.JsonRpcProvider(rpcUrl);
412
+ const signer = new ethers.ethers.Wallet(
413
+ // Random private key for read-only operations
414
+ "dc63e9af2088e2afd61499411cb6dd718d00a3d9e46e2cb5e33912c781bd77fe",
415
+ provider
416
+ );
417
+ const highEthAddress = getHighEthAddress(chainId);
418
+ const finalSigner = highEthAddress ? {
419
+ ...signer,
420
+ getAddress: () => highEthAddress,
421
+ address: highEthAddress
422
+ } : signer;
423
+ return new seaportJs.Seaport(finalSigner, {
424
+ overrides: { contractAddress: getSeaportAddress(chainId) }
425
+ });
426
+ }
427
+ function computeOrderHash(seaport, orderParameters, counter) {
428
+ return seaport.getOrderHash({
429
+ ...orderParameters,
430
+ counter: counter.toString()
431
+ });
432
+ }
433
+ function getOrderStatusFromInfo(orderParameters, statusInfo) {
434
+ if (statusInfo.isCancelled) {
435
+ return 0 /* CANCELLED */;
436
+ }
437
+ if (statusInfo.totalFilled === statusInfo.totalSize && statusInfo.totalFilled > BigInt(0)) {
438
+ return 3 /* FILLED */;
439
+ }
440
+ const now = BigInt(Math.floor(Date.now() / 1e3));
441
+ if (orderParameters.endTime < now) {
442
+ return 1 /* EXPIRED */;
443
+ }
444
+ return 2 /* OPEN */;
445
+ }
446
+ function getTotalConsiderationAmount(parameters) {
447
+ return parameters.consideration.reduce(
448
+ (acc, item) => acc + item.startAmount,
449
+ BigInt(0)
450
+ );
451
+ }
452
+ function formatPrice(priceWei) {
453
+ return parseFloat(viem.formatEther(priceWei));
454
+ }
455
+ async function bulkFetchOrderStatuses(client, chainId, orderHashes) {
456
+ if (orderHashes.length === 0) {
457
+ return [];
458
+ }
459
+ const seaportAddress = getSeaportAddress(chainId);
460
+ const results = await actions.readContract(client, {
461
+ address: BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS,
462
+ abi: BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI,
463
+ functionName: "getOrderStatuses",
464
+ args: [seaportAddress, orderHashes]
465
+ });
466
+ return results.map((r) => ({
467
+ isValidated: r.isValidated,
468
+ isCancelled: r.isCancelled,
469
+ totalFilled: BigInt(r.totalFilled),
470
+ totalSize: BigInt(r.totalSize)
471
+ }));
472
+ }
473
+ async function bulkFetchNftOwners(client, nftAddress, tokenIds) {
474
+ if (tokenIds.length === 0) {
475
+ return [];
476
+ }
477
+ try {
478
+ const owners = await actions.readContract(client, {
479
+ address: ERC721_OWNER_OF_HELPER_ADDRESS,
480
+ abi: ERC721_OWNER_OF_HELPER_ABI,
481
+ functionName: "getTokenOwners",
482
+ args: [nftAddress, tokenIds.map((id) => BigInt(id))]
483
+ });
484
+ return owners.map(
485
+ (owner) => owner === "0x0000000000000000000000000000000000000000" ? null : owner
486
+ );
487
+ } catch {
488
+ return tokenIds.map(() => null);
489
+ }
490
+ }
491
+ async function bulkFetchErc20Balances(client, tokenAddress, addresses) {
492
+ if (addresses.length === 0) {
493
+ return [];
494
+ }
495
+ try {
496
+ const balances = await actions.readContract(client, {
497
+ address: ERC20_BULK_BALANCE_CHECKER_ADDRESS,
498
+ abi: ERC20_BULK_BALANCE_CHECKER_ABI,
499
+ functionName: "getBalances",
500
+ args: [tokenAddress, addresses]
501
+ });
502
+ return balances.map((b) => BigInt(b));
503
+ } catch {
504
+ return addresses.map(() => BigInt(0));
505
+ }
506
+ }
507
+ function isListingValid(orderStatus, expirationDate, sellerAddress, currentOwner) {
508
+ if (orderStatus !== 2 /* OPEN */) {
509
+ return false;
510
+ }
511
+ const now = Math.floor(Date.now() / 1e3);
512
+ if (expirationDate <= now) {
513
+ return false;
514
+ }
515
+ if (!currentOwner || currentOwner.toLowerCase() !== sellerAddress.toLowerCase()) {
516
+ return false;
517
+ }
518
+ return true;
519
+ }
520
+ function isCollectionOfferValid(orderStatus, expirationDate, priceWei, buyerBalance) {
521
+ if (orderStatus !== 2 /* OPEN */) {
522
+ return false;
523
+ }
524
+ const now = Math.floor(Date.now() / 1e3);
525
+ if (expirationDate <= now) {
526
+ return false;
527
+ }
528
+ if (buyerBalance < priceWei) {
529
+ return false;
530
+ }
531
+ return true;
532
+ }
533
+ function isErc20OfferValid(orderStatus, expirationDate, priceWei, buyerWethBalance) {
534
+ if (orderStatus !== 2 /* OPEN */) {
535
+ return false;
536
+ }
537
+ const now = Math.floor(Date.now() / 1e3);
538
+ if (expirationDate <= now) {
539
+ return false;
540
+ }
541
+ if (buyerWethBalance < priceWei) {
542
+ return false;
543
+ }
544
+ return true;
545
+ }
546
+
547
+ // src/utils/parsing.ts
548
+ function parseListingFromMessage(message, chainId) {
549
+ try {
550
+ const submission = decodeSeaportSubmission(message.data);
551
+ const { parameters } = submission;
552
+ const offerItem = parameters.offer[0];
553
+ if (!offerItem) {
554
+ return null;
555
+ }
556
+ if (offerItem.itemType !== 2 /* ERC721 */ && offerItem.itemType !== 3 /* ERC1155 */) {
557
+ return null;
558
+ }
559
+ const priceWei = getTotalConsiderationAmount(parameters);
560
+ const tokenId = offerItem.identifierOrCriteria.toString();
561
+ return {
562
+ maker: parameters.offerer,
563
+ nftAddress: offerItem.token,
564
+ tokenId,
565
+ priceWei,
566
+ price: formatPrice(priceWei),
567
+ currency: getCurrencySymbol(chainId),
568
+ expirationDate: Number(parameters.endTime),
569
+ orderHash: "",
570
+ // Will be computed later
571
+ orderStatus: 2 /* OPEN */,
572
+ // Will be validated later
573
+ messageData: message.data,
574
+ orderComponents: {
575
+ ...parameters,
576
+ counter: submission.counter
577
+ }
578
+ };
579
+ } catch {
580
+ return null;
581
+ }
582
+ }
583
+ function parseCollectionOfferFromMessage(message, chainId) {
584
+ try {
585
+ const submission = decodeSeaportSubmission(message.data);
586
+ const { parameters } = submission;
587
+ if (parameters.zone.toLowerCase() !== NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS.toLowerCase()) {
588
+ return null;
589
+ }
590
+ const offerItem = parameters.offer[0];
591
+ if (!offerItem || offerItem.itemType !== 1 /* ERC20 */) {
592
+ return null;
593
+ }
594
+ const nftConsideration = parameters.consideration.find(
595
+ (item) => item.itemType === 4 /* ERC721_WITH_CRITERIA */ || item.itemType === 5 /* ERC1155_WITH_CRITERIA */
596
+ );
597
+ if (!nftConsideration) {
598
+ return null;
599
+ }
600
+ if (nftConsideration.startAmount !== BigInt(1)) {
601
+ return null;
602
+ }
603
+ const priceWei = offerItem.startAmount;
604
+ return {
605
+ maker: parameters.offerer,
606
+ nftAddress: nftConsideration.token,
607
+ priceWei,
608
+ price: formatPrice(priceWei),
609
+ currency: getCurrencySymbol(chainId),
610
+ expirationDate: Number(parameters.endTime),
611
+ orderHash: "",
612
+ // Will be computed later
613
+ orderStatus: 2 /* OPEN */,
614
+ // Will be validated later
615
+ messageData: message.data,
616
+ orderComponents: {
617
+ ...parameters,
618
+ counter: submission.counter
619
+ }
620
+ };
621
+ } catch {
622
+ return null;
623
+ }
624
+ }
625
+ function getBestListingPerToken(listings) {
626
+ const tokenMap = /* @__PURE__ */ new Map();
627
+ for (const listing of listings) {
628
+ const key = `${listing.nftAddress.toLowerCase()}-${listing.tokenId}`;
629
+ const existing = tokenMap.get(key);
630
+ if (!existing || listing.priceWei < existing.priceWei) {
631
+ tokenMap.set(key, listing);
632
+ }
633
+ }
634
+ return Array.from(tokenMap.values());
635
+ }
636
+ function sortListingsByPrice(listings) {
637
+ return [...listings].sort((a, b) => {
638
+ const diff = a.priceWei - b.priceWei;
639
+ if (diff < BigInt(0)) return -1;
640
+ if (diff > BigInt(0)) return 1;
641
+ return 0;
642
+ });
643
+ }
644
+ function sortOffersByPrice(offers) {
645
+ return [...offers].sort((a, b) => {
646
+ const diff = b.priceWei - a.priceWei;
647
+ if (diff < BigInt(0)) return -1;
648
+ if (diff > BigInt(0)) return 1;
649
+ return 0;
650
+ });
651
+ }
652
+ function parseErc20OfferFromMessage(message, chainId) {
653
+ try {
654
+ const submission = decodeSeaportSubmission(message.data);
655
+ const { parameters } = submission;
656
+ if (parameters.zone.toLowerCase() !== NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS.toLowerCase()) {
657
+ return null;
658
+ }
659
+ const offerItem = parameters.offer[0];
660
+ if (!offerItem || offerItem.itemType !== 1 /* ERC20 */) {
661
+ return null;
662
+ }
663
+ const erc20Consideration = parameters.consideration.find(
664
+ (item) => item.itemType === 1 /* ERC20 */
665
+ );
666
+ if (!erc20Consideration) {
667
+ return null;
668
+ }
669
+ const tokenAmount = erc20Consideration.startAmount;
670
+ if (tokenAmount === BigInt(0)) {
671
+ return null;
672
+ }
673
+ const priceWei = offerItem.startAmount;
674
+ const pricePerTokenWei = priceWei / tokenAmount;
675
+ return {
676
+ maker: parameters.offerer,
677
+ tokenAddress: erc20Consideration.token,
678
+ tokenAmount,
679
+ priceWei,
680
+ pricePerTokenWei,
681
+ price: formatPrice(priceWei),
682
+ pricePerToken: formatPrice(pricePerTokenWei),
683
+ currency: getCurrencySymbol(chainId),
684
+ expirationDate: Number(parameters.endTime),
685
+ orderHash: "0x",
686
+ // Will be computed later
687
+ orderStatus: 2 /* OPEN */,
688
+ // Will be validated later
689
+ messageData: message.data,
690
+ orderComponents: {
691
+ ...parameters,
692
+ counter: submission.counter
693
+ }
694
+ };
695
+ } catch {
696
+ return null;
697
+ }
698
+ }
699
+ function sortErc20OffersByPricePerToken(offers) {
700
+ return [...offers].sort((a, b) => {
701
+ const diff = b.pricePerTokenWei - a.pricePerTokenWei;
702
+ if (diff < BigInt(0)) return -1;
703
+ if (diff > BigInt(0)) return 1;
704
+ return 0;
705
+ });
706
+ }
707
+
708
+ // src/client/BazaarClient.ts
709
+ var CHAIN_RPC_URLS = {
710
+ 8453: ["https://base-mainnet.public.blastapi.io", "https://mainnet.base.org"],
711
+ 84532: ["https://sepolia.base.org"],
712
+ 666666666: ["https://rpc.degen.tips"],
713
+ 5112: ["https://rpc.ham.fun"],
714
+ 57073: ["https://rpc-qnd.inkonchain.com"],
715
+ 130: ["https://mainnet.unichain.org"],
716
+ 999: ["https://rpc.hyperliquid.xyz/evm"],
717
+ 9745: ["https://rpc.plasma.to"],
718
+ 143: ["https://rpc3.monad.xyz"]
719
+ };
720
+ var BazaarClient = class {
721
+ constructor(params) {
722
+ if (!isBazaarSupportedOnChain(params.chainId)) {
723
+ throw new Error(`Bazaar is not supported on chain ${params.chainId}`);
724
+ }
725
+ this.chainId = params.chainId;
726
+ this.rpcUrl = params.rpcUrl || CHAIN_RPC_URLS[params.chainId]?.[0] || "";
727
+ if (!this.rpcUrl) {
728
+ throw new Error(`No RPC URL available for chain ${params.chainId}`);
729
+ }
730
+ const config = getBazaarChainConfig(params.chainId);
731
+ this.client = viem.createPublicClient({
732
+ chain: viem.defineChain({
733
+ id: params.chainId,
734
+ name: `Chain ${params.chainId}`,
735
+ nativeCurrency: {
736
+ name: config.wrappedNativeCurrency.name.replace("Wrapped ", ""),
737
+ symbol: config.currencySymbol.toUpperCase(),
738
+ decimals: 18
739
+ },
740
+ rpcUrls: {
741
+ default: { http: [this.rpcUrl] }
742
+ }
743
+ }),
744
+ transport: viem.http(this.rpcUrl),
745
+ batch: { multicall: true }
746
+ });
747
+ this.netClient = new core.NetClient({
748
+ chainId: params.chainId,
749
+ overrides: params.rpcUrl ? { rpcUrls: [params.rpcUrl] } : void 0
750
+ });
751
+ }
752
+ /**
753
+ * Get valid NFT listings for a collection
754
+ *
755
+ * Returns listings that are:
756
+ * - OPEN status (not filled, cancelled, or expired)
757
+ * - Not expired
758
+ * - Seller still owns the NFT
759
+ *
760
+ * Results are deduplicated (one per token) and sorted by price (lowest first)
761
+ */
762
+ async getListings(options) {
763
+ const { nftAddress, excludeMaker, maxMessages = 200 } = options;
764
+ const bazaarAddress = getBazaarAddress(this.chainId);
765
+ const count = await this.netClient.getMessageCount({
766
+ filter: {
767
+ appAddress: bazaarAddress,
768
+ topic: nftAddress.toLowerCase()
769
+ }
770
+ });
771
+ if (count === 0) {
772
+ return [];
773
+ }
774
+ const startIndex = Math.max(0, count - maxMessages);
775
+ const messages = await this.netClient.getMessages({
776
+ filter: {
777
+ appAddress: bazaarAddress,
778
+ topic: nftAddress.toLowerCase()
779
+ },
780
+ startIndex,
781
+ endIndex: count
782
+ });
783
+ let listings = [];
784
+ for (const message of messages) {
785
+ const listing = parseListingFromMessage(message, this.chainId);
786
+ if (!listing) continue;
787
+ if (excludeMaker && listing.maker.toLowerCase() === excludeMaker.toLowerCase()) {
788
+ continue;
789
+ }
790
+ listings.push(listing);
791
+ }
792
+ if (listings.length === 0) {
793
+ return [];
794
+ }
795
+ const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
796
+ for (const listing of listings) {
797
+ const order = getSeaportOrderFromMessageData(listing.messageData);
798
+ listing.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
799
+ }
800
+ const orderHashes = listings.map((l) => l.orderHash);
801
+ const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
802
+ listings.forEach((listing, index) => {
803
+ const statusInfo = statusInfos[index];
804
+ listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
805
+ });
806
+ listings = listings.filter(
807
+ (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
808
+ );
809
+ if (listings.length === 0) {
810
+ return [];
811
+ }
812
+ const tokenIds = listings.map((l) => l.tokenId);
813
+ const owners = await bulkFetchNftOwners(this.client, nftAddress, tokenIds);
814
+ listings = listings.filter((listing, index) => {
815
+ const owner = owners[index];
816
+ return isListingValid(
817
+ listing.orderStatus,
818
+ listing.expirationDate,
819
+ listing.maker,
820
+ owner
821
+ );
822
+ });
823
+ return sortListingsByPrice(getBestListingPerToken(listings));
824
+ }
825
+ /**
826
+ * Get valid collection offers for a collection
827
+ *
828
+ * Returns offers that are:
829
+ * - OPEN status (not filled, cancelled, or expired)
830
+ * - Not expired
831
+ * - Buyer has sufficient WETH balance
832
+ *
833
+ * Results are sorted by price (highest first)
834
+ */
835
+ async getCollectionOffers(options) {
836
+ const { nftAddress, excludeMaker, maxMessages = 100 } = options;
837
+ const collectionOffersAddress = getCollectionOffersAddress(this.chainId);
838
+ const weth = getWrappedNativeCurrency(this.chainId);
839
+ if (!weth) {
840
+ return [];
841
+ }
842
+ const count = await this.netClient.getMessageCount({
843
+ filter: {
844
+ appAddress: collectionOffersAddress,
845
+ topic: nftAddress.toLowerCase()
846
+ }
847
+ });
848
+ if (count === 0) {
849
+ return [];
850
+ }
851
+ const startIndex = Math.max(0, count - maxMessages);
852
+ const messages = await this.netClient.getMessages({
853
+ filter: {
854
+ appAddress: collectionOffersAddress,
855
+ topic: nftAddress.toLowerCase()
856
+ },
857
+ startIndex,
858
+ endIndex: count
859
+ });
860
+ let offers = [];
861
+ for (const message of messages) {
862
+ const offer = parseCollectionOfferFromMessage(message, this.chainId);
863
+ if (!offer) continue;
864
+ const order = getSeaportOrderFromMessageData(offer.messageData);
865
+ const offerToken = order.parameters.offer?.[0]?.token?.toLowerCase();
866
+ if (offerToken !== weth.address.toLowerCase()) {
867
+ continue;
868
+ }
869
+ if (excludeMaker && offer.maker.toLowerCase() === excludeMaker.toLowerCase()) {
870
+ continue;
871
+ }
872
+ offers.push(offer);
873
+ }
874
+ if (offers.length === 0) {
875
+ return [];
876
+ }
877
+ const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
878
+ for (const offer of offers) {
879
+ const order = getSeaportOrderFromMessageData(offer.messageData);
880
+ offer.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
881
+ }
882
+ const orderHashes = offers.map((o) => o.orderHash);
883
+ const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
884
+ offers.forEach((offer, index) => {
885
+ const statusInfo = statusInfos[index];
886
+ offer.orderStatus = getOrderStatusFromInfo(offer.orderComponents, statusInfo);
887
+ });
888
+ offers = offers.filter(
889
+ (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > Math.floor(Date.now() / 1e3)
890
+ );
891
+ if (offers.length === 0) {
892
+ return [];
893
+ }
894
+ const uniqueMakers = [...new Set(offers.map((o) => o.maker))];
895
+ const balances = await bulkFetchErc20Balances(this.client, weth.address, uniqueMakers);
896
+ const balanceMap = /* @__PURE__ */ new Map();
897
+ uniqueMakers.forEach((maker, index) => {
898
+ balanceMap.set(maker.toLowerCase(), balances[index]);
899
+ });
900
+ offers = offers.filter((offer) => {
901
+ const balance = balanceMap.get(offer.maker.toLowerCase()) || BigInt(0);
902
+ return isCollectionOfferValid(
903
+ offer.orderStatus,
904
+ offer.expirationDate,
905
+ offer.priceWei,
906
+ balance
907
+ );
908
+ });
909
+ return sortOffersByPrice(offers);
910
+ }
911
+ /**
912
+ * Get valid ERC20 offers for a token
913
+ *
914
+ * ERC20 offers are only available on Base (8453) and HyperEVM (999).
915
+ *
916
+ * Returns offers that are:
917
+ * - OPEN status (not filled, cancelled, or expired)
918
+ * - Not expired
919
+ * - Buyer has sufficient WETH balance
920
+ *
921
+ * Results are sorted by price per token (highest first)
922
+ */
923
+ async getErc20Offers(options) {
924
+ const { tokenAddress, excludeMaker, maxMessages = 200 } = options;
925
+ const erc20OffersAddress = getErc20OffersAddress(this.chainId);
926
+ const weth = getWrappedNativeCurrency(this.chainId);
927
+ if (!erc20OffersAddress || !weth) {
928
+ return [];
929
+ }
930
+ const count = await this.netClient.getMessageCount({
931
+ filter: {
932
+ appAddress: erc20OffersAddress,
933
+ topic: tokenAddress.toLowerCase()
934
+ }
935
+ });
936
+ if (count === 0) {
937
+ return [];
938
+ }
939
+ const startIndex = Math.max(0, count - maxMessages);
940
+ const messages = await this.netClient.getMessages({
941
+ filter: {
942
+ appAddress: erc20OffersAddress,
943
+ topic: tokenAddress.toLowerCase()
944
+ },
945
+ startIndex,
946
+ endIndex: count
947
+ });
948
+ let offers = [];
949
+ for (const message of messages) {
950
+ const offer = parseErc20OfferFromMessage(message, this.chainId);
951
+ if (!offer) continue;
952
+ const order = getSeaportOrderFromMessageData(offer.messageData);
953
+ const offerToken = order.parameters.offer?.[0]?.token?.toLowerCase();
954
+ if (offerToken !== weth.address.toLowerCase()) {
955
+ continue;
956
+ }
957
+ if (offer.tokenAddress.toLowerCase() !== tokenAddress.toLowerCase()) {
958
+ continue;
959
+ }
960
+ if (excludeMaker && offer.maker.toLowerCase() === excludeMaker.toLowerCase()) {
961
+ continue;
962
+ }
963
+ offers.push(offer);
964
+ }
965
+ if (offers.length === 0) {
966
+ return [];
967
+ }
968
+ const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
969
+ for (const offer of offers) {
970
+ const order = getSeaportOrderFromMessageData(offer.messageData);
971
+ offer.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
972
+ }
973
+ const orderHashes = offers.map((o) => o.orderHash);
974
+ const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
975
+ offers.forEach((offer, index) => {
976
+ const statusInfo = statusInfos[index];
977
+ offer.orderStatus = getOrderStatusFromInfo(offer.orderComponents, statusInfo);
978
+ });
979
+ offers = offers.filter(
980
+ (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > Math.floor(Date.now() / 1e3)
981
+ );
982
+ if (offers.length === 0) {
983
+ return [];
984
+ }
985
+ const uniqueMakers = [...new Set(offers.map((o) => o.maker))];
986
+ const balances = await bulkFetchErc20Balances(this.client, weth.address, uniqueMakers);
987
+ const balanceMap = /* @__PURE__ */ new Map();
988
+ uniqueMakers.forEach((maker, index) => {
989
+ balanceMap.set(maker.toLowerCase(), balances[index]);
990
+ });
991
+ offers = offers.filter((offer) => {
992
+ const balance = balanceMap.get(offer.maker.toLowerCase()) || BigInt(0);
993
+ return isErc20OfferValid(
994
+ offer.orderStatus,
995
+ offer.expirationDate,
996
+ offer.priceWei,
997
+ balance
998
+ );
999
+ });
1000
+ return sortErc20OffersByPricePerToken(offers);
1001
+ }
1002
+ /**
1003
+ * Get the chain ID this client is configured for
1004
+ */
1005
+ getChainId() {
1006
+ return this.chainId;
1007
+ }
1008
+ /**
1009
+ * Get the bazaar contract address for this chain
1010
+ */
1011
+ getBazaarAddress() {
1012
+ return getBazaarAddress(this.chainId);
1013
+ }
1014
+ /**
1015
+ * Get the collection offers contract address for this chain
1016
+ */
1017
+ getCollectionOffersAddress() {
1018
+ return getCollectionOffersAddress(this.chainId);
1019
+ }
1020
+ /**
1021
+ * Get the ERC20 offers contract address for this chain
1022
+ * Only available on Base (8453) and HyperEVM (999)
1023
+ */
1024
+ getErc20OffersAddress() {
1025
+ return getErc20OffersAddress(this.chainId);
1026
+ }
1027
+ /**
1028
+ * Get the Seaport contract address for this chain
1029
+ */
1030
+ getSeaportAddress() {
1031
+ return getSeaportAddress(this.chainId);
1032
+ }
1033
+ /**
1034
+ * Prepare a transaction to cancel a listing
1035
+ *
1036
+ * The listing must have been created by the caller.
1037
+ * Use the orderComponents from the Listing object returned by getListings().
1038
+ */
1039
+ prepareCancelListing(listing) {
1040
+ if (!listing.orderComponents) {
1041
+ throw new Error("Listing does not have order components");
1042
+ }
1043
+ return this.prepareCancelOrder(listing.orderComponents);
1044
+ }
1045
+ /**
1046
+ * Prepare a transaction to cancel a collection offer
1047
+ *
1048
+ * The offer must have been created by the caller.
1049
+ * Use the orderComponents from the CollectionOffer object returned by getCollectionOffers().
1050
+ */
1051
+ prepareCancelCollectionOffer(offer) {
1052
+ if (!offer.orderComponents) {
1053
+ throw new Error("Offer does not have order components");
1054
+ }
1055
+ return this.prepareCancelOrder(offer.orderComponents);
1056
+ }
1057
+ /**
1058
+ * Prepare a transaction to cancel a Seaport order
1059
+ *
1060
+ * This is a low-level method. Prefer prepareCancelListing or prepareCancelCollectionOffer.
1061
+ */
1062
+ prepareCancelOrder(orderComponents) {
1063
+ const seaportAddress = getSeaportAddress(this.chainId);
1064
+ const orderForCancel = {
1065
+ offerer: orderComponents.offerer,
1066
+ zone: orderComponents.zone,
1067
+ offer: orderComponents.offer.map((item) => ({
1068
+ itemType: item.itemType,
1069
+ token: item.token,
1070
+ identifierOrCriteria: item.identifierOrCriteria,
1071
+ startAmount: item.startAmount,
1072
+ endAmount: item.endAmount
1073
+ })),
1074
+ consideration: orderComponents.consideration.map((item) => ({
1075
+ itemType: item.itemType,
1076
+ token: item.token,
1077
+ identifierOrCriteria: item.identifierOrCriteria,
1078
+ startAmount: item.startAmount,
1079
+ endAmount: item.endAmount,
1080
+ recipient: item.recipient
1081
+ })),
1082
+ orderType: orderComponents.orderType,
1083
+ startTime: orderComponents.startTime,
1084
+ endTime: orderComponents.endTime,
1085
+ zoneHash: orderComponents.zoneHash,
1086
+ salt: orderComponents.salt,
1087
+ conduitKey: orderComponents.conduitKey,
1088
+ counter: orderComponents.counter
1089
+ };
1090
+ return {
1091
+ to: seaportAddress,
1092
+ functionName: "cancel",
1093
+ args: [[orderForCancel]],
1094
+ abi: SEAPORT_CANCEL_ABI
1095
+ };
1096
+ }
1097
+ };
1098
+
1099
+ // src/hooks/useBazaarListings.ts
1100
+ function useBazaarListings({
1101
+ chainId,
1102
+ nftAddress,
1103
+ excludeMaker,
1104
+ maxMessages = 200,
1105
+ enabled = true
1106
+ }) {
1107
+ const [listings, setListings] = react.useState([]);
1108
+ const [isProcessing, setIsProcessing] = react.useState(false);
1109
+ const [processingError, setProcessingError] = react.useState();
1110
+ const [refetchTrigger, setRefetchTrigger] = react.useState(0);
1111
+ const isSupported = react.useMemo(
1112
+ () => isBazaarSupportedOnChain(chainId),
1113
+ [chainId]
1114
+ );
1115
+ const bazaarAddress = react.useMemo(
1116
+ () => isSupported ? getBazaarAddress(chainId) : void 0,
1117
+ [chainId, isSupported]
1118
+ );
1119
+ const filter = react.useMemo(
1120
+ () => ({
1121
+ appAddress: bazaarAddress,
1122
+ topic: nftAddress.toLowerCase()
1123
+ }),
1124
+ [bazaarAddress, nftAddress]
1125
+ );
1126
+ const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
1127
+ chainId,
1128
+ filter,
1129
+ enabled: enabled && isSupported
1130
+ });
1131
+ const startIndex = react.useMemo(
1132
+ () => Math.max(0, totalCount - maxMessages),
1133
+ [totalCount, maxMessages]
1134
+ );
1135
+ const {
1136
+ messages,
1137
+ isLoading: isLoadingMessages,
1138
+ error: messagesError,
1139
+ refetch: refetchMessages
1140
+ } = react$1.useNetMessages({
1141
+ chainId,
1142
+ filter,
1143
+ startIndex,
1144
+ endIndex: totalCount,
1145
+ enabled: enabled && isSupported && totalCount > 0
1146
+ });
1147
+ react.useEffect(() => {
1148
+ if (!isSupported || !enabled) {
1149
+ setListings([]);
1150
+ return;
1151
+ }
1152
+ if (!messages || messages.length === 0) {
1153
+ setListings([]);
1154
+ return;
1155
+ }
1156
+ let cancelled = false;
1157
+ async function processListings() {
1158
+ setIsProcessing(true);
1159
+ setProcessingError(void 0);
1160
+ try {
1161
+ const client = new BazaarClient({ chainId });
1162
+ const validListings = await client.getListings({
1163
+ nftAddress,
1164
+ excludeMaker,
1165
+ maxMessages
1166
+ });
1167
+ if (!cancelled) {
1168
+ setListings(validListings);
1169
+ }
1170
+ } catch (err) {
1171
+ if (!cancelled) {
1172
+ setProcessingError(err instanceof Error ? err : new Error(String(err)));
1173
+ setListings([]);
1174
+ }
1175
+ } finally {
1176
+ if (!cancelled) {
1177
+ setIsProcessing(false);
1178
+ }
1179
+ }
1180
+ }
1181
+ processListings();
1182
+ return () => {
1183
+ cancelled = true;
1184
+ };
1185
+ }, [chainId, nftAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
1186
+ const refetch = () => {
1187
+ refetchMessages();
1188
+ setRefetchTrigger((t) => t + 1);
1189
+ };
1190
+ return {
1191
+ listings,
1192
+ isLoading: isLoadingCount || isLoadingMessages || isProcessing,
1193
+ error: messagesError || processingError,
1194
+ refetch
1195
+ };
1196
+ }
1197
+ function useBazaarCollectionOffers({
1198
+ chainId,
1199
+ nftAddress,
1200
+ excludeMaker,
1201
+ maxMessages = 100,
1202
+ enabled = true
1203
+ }) {
1204
+ const [offers, setOffers] = react.useState([]);
1205
+ const [isProcessing, setIsProcessing] = react.useState(false);
1206
+ const [processingError, setProcessingError] = react.useState();
1207
+ const [refetchTrigger, setRefetchTrigger] = react.useState(0);
1208
+ const isSupported = react.useMemo(
1209
+ () => isBazaarSupportedOnChain(chainId),
1210
+ [chainId]
1211
+ );
1212
+ const collectionOffersAddress = react.useMemo(
1213
+ () => isSupported ? getCollectionOffersAddress(chainId) : void 0,
1214
+ [chainId, isSupported]
1215
+ );
1216
+ const filter = react.useMemo(
1217
+ () => ({
1218
+ appAddress: collectionOffersAddress,
1219
+ topic: nftAddress.toLowerCase()
1220
+ }),
1221
+ [collectionOffersAddress, nftAddress]
1222
+ );
1223
+ const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
1224
+ chainId,
1225
+ filter,
1226
+ enabled: enabled && isSupported
1227
+ });
1228
+ const startIndex = react.useMemo(
1229
+ () => Math.max(0, totalCount - maxMessages),
1230
+ [totalCount, maxMessages]
1231
+ );
1232
+ const {
1233
+ messages,
1234
+ isLoading: isLoadingMessages,
1235
+ error: messagesError,
1236
+ refetch: refetchMessages
1237
+ } = react$1.useNetMessages({
1238
+ chainId,
1239
+ filter,
1240
+ startIndex,
1241
+ endIndex: totalCount,
1242
+ enabled: enabled && isSupported && totalCount > 0
1243
+ });
1244
+ react.useEffect(() => {
1245
+ if (!isSupported || !enabled) {
1246
+ setOffers([]);
1247
+ return;
1248
+ }
1249
+ if (!messages || messages.length === 0) {
1250
+ setOffers([]);
1251
+ return;
1252
+ }
1253
+ let cancelled = false;
1254
+ async function processOffers() {
1255
+ setIsProcessing(true);
1256
+ setProcessingError(void 0);
1257
+ try {
1258
+ const client = new BazaarClient({ chainId });
1259
+ const validOffers = await client.getCollectionOffers({
1260
+ nftAddress,
1261
+ excludeMaker,
1262
+ maxMessages
1263
+ });
1264
+ if (!cancelled) {
1265
+ setOffers(validOffers);
1266
+ }
1267
+ } catch (err) {
1268
+ if (!cancelled) {
1269
+ setProcessingError(err instanceof Error ? err : new Error(String(err)));
1270
+ setOffers([]);
1271
+ }
1272
+ } finally {
1273
+ if (!cancelled) {
1274
+ setIsProcessing(false);
1275
+ }
1276
+ }
1277
+ }
1278
+ processOffers();
1279
+ return () => {
1280
+ cancelled = true;
1281
+ };
1282
+ }, [chainId, nftAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
1283
+ const refetch = () => {
1284
+ refetchMessages();
1285
+ setRefetchTrigger((t) => t + 1);
1286
+ };
1287
+ return {
1288
+ offers,
1289
+ isLoading: isLoadingCount || isLoadingMessages || isProcessing,
1290
+ error: messagesError || processingError,
1291
+ refetch
1292
+ };
1293
+ }
1294
+ function useBazaarErc20Offers({
1295
+ chainId,
1296
+ tokenAddress,
1297
+ excludeMaker,
1298
+ maxMessages = 200,
1299
+ enabled = true
1300
+ }) {
1301
+ const [offers, setOffers] = react.useState([]);
1302
+ const [isProcessing, setIsProcessing] = react.useState(false);
1303
+ const [processingError, setProcessingError] = react.useState();
1304
+ const [refetchTrigger, setRefetchTrigger] = react.useState(0);
1305
+ const isSupported = react.useMemo(
1306
+ () => isBazaarSupportedOnChain(chainId),
1307
+ [chainId]
1308
+ );
1309
+ const erc20OffersAddress = react.useMemo(
1310
+ () => isSupported ? getErc20OffersAddress(chainId) : void 0,
1311
+ [chainId, isSupported]
1312
+ );
1313
+ const hasErc20Offers = Boolean(erc20OffersAddress);
1314
+ const filter = react.useMemo(
1315
+ () => ({
1316
+ appAddress: erc20OffersAddress,
1317
+ topic: tokenAddress.toLowerCase()
1318
+ }),
1319
+ [erc20OffersAddress, tokenAddress]
1320
+ );
1321
+ const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
1322
+ chainId,
1323
+ filter,
1324
+ enabled: enabled && hasErc20Offers
1325
+ });
1326
+ const startIndex = react.useMemo(
1327
+ () => Math.max(0, totalCount - maxMessages),
1328
+ [totalCount, maxMessages]
1329
+ );
1330
+ const {
1331
+ messages,
1332
+ isLoading: isLoadingMessages,
1333
+ error: messagesError,
1334
+ refetch: refetchMessages
1335
+ } = react$1.useNetMessages({
1336
+ chainId,
1337
+ filter,
1338
+ startIndex,
1339
+ endIndex: totalCount,
1340
+ enabled: enabled && hasErc20Offers && totalCount > 0
1341
+ });
1342
+ react.useEffect(() => {
1343
+ if (!hasErc20Offers || !enabled) {
1344
+ setOffers([]);
1345
+ return;
1346
+ }
1347
+ if (!messages || messages.length === 0) {
1348
+ setOffers([]);
1349
+ return;
1350
+ }
1351
+ let cancelled = false;
1352
+ async function processOffers() {
1353
+ setIsProcessing(true);
1354
+ setProcessingError(void 0);
1355
+ try {
1356
+ const client = new BazaarClient({ chainId });
1357
+ const validOffers = await client.getErc20Offers({
1358
+ tokenAddress,
1359
+ excludeMaker,
1360
+ maxMessages
1361
+ });
1362
+ if (!cancelled) {
1363
+ setOffers(validOffers);
1364
+ }
1365
+ } catch (err) {
1366
+ if (!cancelled) {
1367
+ setProcessingError(err instanceof Error ? err : new Error(String(err)));
1368
+ setOffers([]);
1369
+ }
1370
+ } finally {
1371
+ if (!cancelled) {
1372
+ setIsProcessing(false);
1373
+ }
1374
+ }
1375
+ }
1376
+ processOffers();
1377
+ return () => {
1378
+ cancelled = true;
1379
+ };
1380
+ }, [chainId, tokenAddress, excludeMaker, maxMessages, messages, hasErc20Offers, enabled, refetchTrigger]);
1381
+ const refetch = () => {
1382
+ refetchMessages();
1383
+ setRefetchTrigger((t) => t + 1);
1384
+ };
1385
+ return {
1386
+ offers,
1387
+ isLoading: isLoadingCount || isLoadingMessages || isProcessing,
1388
+ error: messagesError || processingError,
1389
+ refetch
1390
+ };
1391
+ }
1392
+
1393
+ exports.useBazaarCollectionOffers = useBazaarCollectionOffers;
1394
+ exports.useBazaarErc20Offers = useBazaarErc20Offers;
1395
+ exports.useBazaarListings = useBazaarListings;
1396
+ //# sourceMappingURL=react.js.map
1397
+ //# sourceMappingURL=react.js.map