@net-protocol/bazaar 0.1.0 → 0.1.2

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.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { L as Listing, C as CollectionOffer, E as Erc20Offer } from './types-CY-6M9Ta.mjs';
1
+ import { L as Listing, C as CollectionOffer, E as Erc20Offer, d as Erc20Listing } from './types-KQgBECzI.mjs';
2
2
 
3
3
  /**
4
4
  * React hook for fetching NFT listings from Bazaar
@@ -11,8 +11,14 @@ interface UseBazaarListingsOptions {
11
11
  nftAddress: `0x${string}`;
12
12
  /** Exclude listings from this address */
13
13
  excludeMaker?: `0x${string}`;
14
+ /** Only include listings from this address */
15
+ maker?: `0x${string}`;
14
16
  /** Maximum number of messages to fetch (default: 200) */
15
17
  maxMessages?: number;
18
+ /** Override start index for message range */
19
+ startIndex?: number;
20
+ /** Override end index for message range */
21
+ endIndex?: number;
16
22
  /** Whether the query is enabled (default: true) */
17
23
  enabled?: boolean;
18
24
  }
@@ -58,7 +64,7 @@ interface UseBazaarListingsResult {
58
64
  * );
59
65
  * ```
60
66
  */
61
- declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maxMessages, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
67
+ declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
62
68
 
63
69
  /**
64
70
  * React hook for fetching collection offers from Bazaar
@@ -175,4 +181,71 @@ interface UseBazaarErc20OffersResult {
175
181
  */
176
182
  declare function useBazaarErc20Offers({ chainId, tokenAddress, excludeMaker, maxMessages, enabled, }: UseBazaarErc20OffersOptions): UseBazaarErc20OffersResult;
177
183
 
178
- export { type UseBazaarCollectionOffersOptions, type UseBazaarCollectionOffersResult, type UseBazaarErc20OffersOptions, type UseBazaarErc20OffersResult, type UseBazaarListingsOptions, type UseBazaarListingsResult, useBazaarCollectionOffers, useBazaarErc20Offers, useBazaarListings };
184
+ /**
185
+ * React hook for fetching ERC20 listings from Bazaar
186
+ */
187
+
188
+ interface UseBazaarErc20ListingsOptions {
189
+ /** Chain ID to query */
190
+ chainId: number;
191
+ /** ERC20 token address */
192
+ tokenAddress: `0x${string}`;
193
+ /** Exclude listings from this address */
194
+ excludeMaker?: `0x${string}`;
195
+ /** Only include listings from this address */
196
+ maker?: `0x${string}`;
197
+ /** Maximum number of messages to fetch (default: 200) */
198
+ maxMessages?: number;
199
+ /** Override start index for message range */
200
+ startIndex?: number;
201
+ /** Override end index for message range */
202
+ endIndex?: number;
203
+ /** Whether the query is enabled (default: true) */
204
+ enabled?: boolean;
205
+ }
206
+ interface UseBazaarErc20ListingsResult {
207
+ /** Valid ERC20 listings (sorted by price per token, lowest first) */
208
+ listings: Erc20Listing[];
209
+ /** Whether the data is loading */
210
+ isLoading: boolean;
211
+ /** Error if any */
212
+ error: Error | undefined;
213
+ /** Refetch function */
214
+ refetch: () => void;
215
+ }
216
+ /**
217
+ * React hook for fetching valid ERC20 listings from Bazaar
218
+ *
219
+ * ERC20 listings are available on all supported chains.
220
+ *
221
+ * Returns listings that are:
222
+ * - OPEN status (not filled, cancelled, or expired)
223
+ * - Not expired
224
+ * - Seller has sufficient ERC20 token balance
225
+ *
226
+ * Results are sorted by price per token (lowest first)
227
+ *
228
+ * @example
229
+ * ```tsx
230
+ * const { listings, isLoading, error } = useBazaarErc20Listings({
231
+ * chainId: 8453,
232
+ * tokenAddress: "0x...",
233
+ * });
234
+ *
235
+ * if (isLoading) return <div>Loading...</div>;
236
+ * if (error) return <div>Error: {error.message}</div>;
237
+ *
238
+ * const bestListing = listings[0];
239
+ * if (bestListing) {
240
+ * return (
241
+ * <div>
242
+ * Best listing: {bestListing.pricePerToken} {bestListing.currency} per token
243
+ * (total: {bestListing.price} {bestListing.currency} for {bestListing.tokenAmount.toString()} tokens)
244
+ * </div>
245
+ * );
246
+ * }
247
+ * ```
248
+ */
249
+ declare function useBazaarErc20Listings({ chainId, tokenAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarErc20ListingsOptions): UseBazaarErc20ListingsResult;
250
+
251
+ export { type UseBazaarCollectionOffersOptions, type UseBazaarCollectionOffersResult, type UseBazaarErc20ListingsOptions, type UseBazaarErc20ListingsResult, type UseBazaarErc20OffersOptions, type UseBazaarErc20OffersResult, type UseBazaarListingsOptions, type UseBazaarListingsResult, useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings };
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { L as Listing, C as CollectionOffer, E as Erc20Offer } from './types-CY-6M9Ta.js';
1
+ import { L as Listing, C as CollectionOffer, E as Erc20Offer, d as Erc20Listing } from './types-KQgBECzI.js';
2
2
 
3
3
  /**
4
4
  * React hook for fetching NFT listings from Bazaar
@@ -11,8 +11,14 @@ interface UseBazaarListingsOptions {
11
11
  nftAddress: `0x${string}`;
12
12
  /** Exclude listings from this address */
13
13
  excludeMaker?: `0x${string}`;
14
+ /** Only include listings from this address */
15
+ maker?: `0x${string}`;
14
16
  /** Maximum number of messages to fetch (default: 200) */
15
17
  maxMessages?: number;
18
+ /** Override start index for message range */
19
+ startIndex?: number;
20
+ /** Override end index for message range */
21
+ endIndex?: number;
16
22
  /** Whether the query is enabled (default: true) */
17
23
  enabled?: boolean;
18
24
  }
@@ -58,7 +64,7 @@ interface UseBazaarListingsResult {
58
64
  * );
59
65
  * ```
60
66
  */
61
- declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maxMessages, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
67
+ declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
62
68
 
63
69
  /**
64
70
  * React hook for fetching collection offers from Bazaar
@@ -175,4 +181,71 @@ interface UseBazaarErc20OffersResult {
175
181
  */
176
182
  declare function useBazaarErc20Offers({ chainId, tokenAddress, excludeMaker, maxMessages, enabled, }: UseBazaarErc20OffersOptions): UseBazaarErc20OffersResult;
177
183
 
178
- export { type UseBazaarCollectionOffersOptions, type UseBazaarCollectionOffersResult, type UseBazaarErc20OffersOptions, type UseBazaarErc20OffersResult, type UseBazaarListingsOptions, type UseBazaarListingsResult, useBazaarCollectionOffers, useBazaarErc20Offers, useBazaarListings };
184
+ /**
185
+ * React hook for fetching ERC20 listings from Bazaar
186
+ */
187
+
188
+ interface UseBazaarErc20ListingsOptions {
189
+ /** Chain ID to query */
190
+ chainId: number;
191
+ /** ERC20 token address */
192
+ tokenAddress: `0x${string}`;
193
+ /** Exclude listings from this address */
194
+ excludeMaker?: `0x${string}`;
195
+ /** Only include listings from this address */
196
+ maker?: `0x${string}`;
197
+ /** Maximum number of messages to fetch (default: 200) */
198
+ maxMessages?: number;
199
+ /** Override start index for message range */
200
+ startIndex?: number;
201
+ /** Override end index for message range */
202
+ endIndex?: number;
203
+ /** Whether the query is enabled (default: true) */
204
+ enabled?: boolean;
205
+ }
206
+ interface UseBazaarErc20ListingsResult {
207
+ /** Valid ERC20 listings (sorted by price per token, lowest first) */
208
+ listings: Erc20Listing[];
209
+ /** Whether the data is loading */
210
+ isLoading: boolean;
211
+ /** Error if any */
212
+ error: Error | undefined;
213
+ /** Refetch function */
214
+ refetch: () => void;
215
+ }
216
+ /**
217
+ * React hook for fetching valid ERC20 listings from Bazaar
218
+ *
219
+ * ERC20 listings are available on all supported chains.
220
+ *
221
+ * Returns listings that are:
222
+ * - OPEN status (not filled, cancelled, or expired)
223
+ * - Not expired
224
+ * - Seller has sufficient ERC20 token balance
225
+ *
226
+ * Results are sorted by price per token (lowest first)
227
+ *
228
+ * @example
229
+ * ```tsx
230
+ * const { listings, isLoading, error } = useBazaarErc20Listings({
231
+ * chainId: 8453,
232
+ * tokenAddress: "0x...",
233
+ * });
234
+ *
235
+ * if (isLoading) return <div>Loading...</div>;
236
+ * if (error) return <div>Error: {error.message}</div>;
237
+ *
238
+ * const bestListing = listings[0];
239
+ * if (bestListing) {
240
+ * return (
241
+ * <div>
242
+ * Best listing: {bestListing.pricePerToken} {bestListing.currency} per token
243
+ * (total: {bestListing.price} {bestListing.currency} for {bestListing.tokenAmount.toString()} tokens)
244
+ * </div>
245
+ * );
246
+ * }
247
+ * ```
248
+ */
249
+ declare function useBazaarErc20Listings({ chainId, tokenAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarErc20ListingsOptions): UseBazaarErc20ListingsResult;
250
+
251
+ export { type UseBazaarCollectionOffersOptions, type UseBazaarCollectionOffersResult, type UseBazaarErc20ListingsOptions, type UseBazaarErc20ListingsResult, type UseBazaarErc20OffersOptions, type UseBazaarErc20OffersResult, type UseBazaarListingsOptions, type UseBazaarListingsResult, useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings };
package/dist/react.js CHANGED
@@ -179,17 +179,20 @@ var DEFAULT_SEAPORT_ADDRESS = "0x0000000000000068F116a894984e2DB1123eB395";
179
179
  var DEFAULT_BAZAAR_ADDRESS = "0x00000000E3dA5fC031282A39759bDDA78ae7fAE5";
180
180
  var DEFAULT_COLLECTION_OFFERS_ADDRESS = "0x0000000D43423E0A12CecB307a74591999b32B32";
181
181
  var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5";
182
+ var DEFAULT_ERC20_BAZAAR_ADDRESS = "0x00000000a2d173a4610c85c7471a25b6bc216a70";
182
183
  var DEFAULT_NFT_FEE_BPS = 500;
183
184
  var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
184
185
  var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
185
186
  var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000b50a9f2923f2db931391824f6d1278f712";
186
187
  var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
188
+ var NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = "0x000000bC63761cbb05305632212e2f3AE2BE7a9B";
187
189
  var BAZAAR_CHAIN_CONFIGS = {
188
190
  // Base Mainnet
189
191
  8453: {
190
192
  bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
191
193
  collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
192
194
  erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
195
+ erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
193
196
  seaportAddress: DEFAULT_SEAPORT_ADDRESS,
194
197
  feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
195
198
  nftFeeBps: 0,
@@ -279,6 +282,7 @@ var BAZAAR_CHAIN_CONFIGS = {
279
282
  bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
280
283
  collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
281
284
  erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
285
+ erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
282
286
  seaportAddress: DEFAULT_SEAPORT_ADDRESS,
283
287
  feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
284
288
  nftFeeBps: 0,
@@ -346,6 +350,9 @@ function getHighEthAddress(chainId) {
346
350
  function getErc20OffersAddress(chainId) {
347
351
  return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20OffersAddress;
348
352
  }
353
+ function getErc20BazaarAddress(chainId) {
354
+ return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20BazaarAddress ?? DEFAULT_ERC20_BAZAAR_ADDRESS;
355
+ }
349
356
  function decodeSeaportSubmission(messageData) {
350
357
  const [decoded] = viem.decodeAbiParameters(BAZAAR_SUBMISSION_ABI, messageData);
351
358
  return {
@@ -543,6 +550,19 @@ function isErc20OfferValid(orderStatus, expirationDate, priceWei, buyerWethBalan
543
550
  }
544
551
  return true;
545
552
  }
553
+ function isErc20ListingValid(orderStatus, expirationDate, tokenAmount, sellerTokenBalance) {
554
+ if (orderStatus !== 2 /* OPEN */) {
555
+ return false;
556
+ }
557
+ const now = Math.floor(Date.now() / 1e3);
558
+ if (expirationDate <= now) {
559
+ return false;
560
+ }
561
+ if (sellerTokenBalance < tokenAmount) {
562
+ return false;
563
+ }
564
+ return true;
565
+ }
546
566
 
547
567
  // src/utils/parsing.ts
548
568
  function parseListingFromMessage(message, chainId) {
@@ -558,6 +578,7 @@ function parseListingFromMessage(message, chainId) {
558
578
  }
559
579
  const priceWei = getTotalConsiderationAmount(parameters);
560
580
  const tokenId = offerItem.identifierOrCriteria.toString();
581
+ const targetFulfiller = parameters.zone.toLowerCase() === NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS.toLowerCase() && parameters.zoneHash !== "0x0000000000000000000000000000000000000000000000000000000000000000" ? parameters.zoneHash : void 0;
561
582
  return {
562
583
  maker: parameters.offerer,
563
584
  nftAddress: offerItem.token,
@@ -574,7 +595,8 @@ function parseListingFromMessage(message, chainId) {
574
595
  orderComponents: {
575
596
  ...parameters,
576
597
  counter: submission.counter
577
- }
598
+ },
599
+ targetFulfiller
578
600
  };
579
601
  } catch {
580
602
  return null;
@@ -704,6 +726,58 @@ function sortErc20OffersByPricePerToken(offers) {
704
726
  return 0;
705
727
  });
706
728
  }
729
+ function parseErc20ListingFromMessage(message, chainId) {
730
+ try {
731
+ const submission = decodeSeaportSubmission(message.data);
732
+ const { parameters } = submission;
733
+ if (parameters.zone.toLowerCase() === NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS.toLowerCase()) {
734
+ return null;
735
+ }
736
+ const offerItem = parameters.offer[0];
737
+ if (!offerItem || offerItem.itemType !== 1 /* ERC20 */) {
738
+ return null;
739
+ }
740
+ const tokenAmount = offerItem.startAmount;
741
+ if (tokenAmount === BigInt(0)) {
742
+ return null;
743
+ }
744
+ const priceWei = getTotalConsiderationAmount(parameters);
745
+ if (priceWei === BigInt(0)) {
746
+ return null;
747
+ }
748
+ const pricePerTokenWei = priceWei / tokenAmount;
749
+ return {
750
+ maker: parameters.offerer,
751
+ tokenAddress: offerItem.token,
752
+ tokenAmount,
753
+ priceWei,
754
+ pricePerTokenWei,
755
+ price: formatPrice(priceWei),
756
+ pricePerToken: formatPrice(pricePerTokenWei),
757
+ currency: getCurrencySymbol(chainId),
758
+ expirationDate: Number(parameters.endTime),
759
+ orderHash: "0x",
760
+ // Will be computed later
761
+ orderStatus: 2 /* OPEN */,
762
+ // Will be validated later
763
+ messageData: message.data,
764
+ orderComponents: {
765
+ ...parameters,
766
+ counter: submission.counter
767
+ }
768
+ };
769
+ } catch {
770
+ return null;
771
+ }
772
+ }
773
+ function sortErc20ListingsByPricePerToken(listings) {
774
+ return [...listings].sort((a, b) => {
775
+ const diff = a.pricePerTokenWei - b.pricePerTokenWei;
776
+ if (diff < BigInt(0)) return -1;
777
+ if (diff > BigInt(0)) return 1;
778
+ return 0;
779
+ });
780
+ }
707
781
 
708
782
  // src/client/BazaarClient.ts
709
783
  var CHAIN_RPC_URLS = {
@@ -760,25 +834,30 @@ var BazaarClient = class {
760
834
  * Results are deduplicated (one per token) and sorted by price (lowest first)
761
835
  */
762
836
  async getListings(options) {
763
- const { nftAddress, excludeMaker, maxMessages = 200 } = options;
837
+ const { nftAddress, excludeMaker, maker, maxMessages = 200 } = options;
764
838
  const bazaarAddress = getBazaarAddress(this.chainId);
765
- const count = await this.netClient.getMessageCount({
766
- filter: {
767
- appAddress: bazaarAddress,
768
- topic: nftAddress.toLowerCase()
839
+ const filter = {
840
+ appAddress: bazaarAddress,
841
+ topic: nftAddress.toLowerCase(),
842
+ maker
843
+ };
844
+ let startIndex;
845
+ let endIndex;
846
+ if (options.startIndex != null && options.endIndex != null) {
847
+ startIndex = options.startIndex;
848
+ endIndex = options.endIndex;
849
+ } else {
850
+ const count = await this.netClient.getMessageCount({ filter });
851
+ if (count === 0) {
852
+ return [];
769
853
  }
770
- });
771
- if (count === 0) {
772
- return [];
854
+ startIndex = Math.max(0, count - maxMessages);
855
+ endIndex = count;
773
856
  }
774
- const startIndex = Math.max(0, count - maxMessages);
775
857
  const messages = await this.netClient.getMessages({
776
- filter: {
777
- appAddress: bazaarAddress,
778
- topic: nftAddress.toLowerCase()
779
- },
858
+ filter,
780
859
  startIndex,
781
- endIndex: count
860
+ endIndex
782
861
  });
783
862
  let listings = [];
784
863
  for (const message of messages) {
@@ -999,6 +1078,92 @@ var BazaarClient = class {
999
1078
  });
1000
1079
  return sortErc20OffersByPricePerToken(offers);
1001
1080
  }
1081
+ /**
1082
+ * Get valid ERC20 listings for a token
1083
+ *
1084
+ * Returns listings that are:
1085
+ * - OPEN status (not filled, cancelled, or expired)
1086
+ * - Not expired
1087
+ * - Seller has sufficient ERC20 token balance
1088
+ *
1089
+ * Results are sorted by price per token (lowest first). No deduplication —
1090
+ * all valid listings are returned (grouped by maker in the UI).
1091
+ */
1092
+ async getErc20Listings(options) {
1093
+ const { tokenAddress, excludeMaker, maker, maxMessages = 200 } = options;
1094
+ const erc20BazaarAddress = getErc20BazaarAddress(this.chainId);
1095
+ const filter = {
1096
+ appAddress: erc20BazaarAddress,
1097
+ topic: tokenAddress.toLowerCase(),
1098
+ maker
1099
+ };
1100
+ let startIndex;
1101
+ let endIndex;
1102
+ if (options.startIndex != null && options.endIndex != null) {
1103
+ startIndex = options.startIndex;
1104
+ endIndex = options.endIndex;
1105
+ } else {
1106
+ const count = await this.netClient.getMessageCount({ filter });
1107
+ if (count === 0) {
1108
+ return [];
1109
+ }
1110
+ startIndex = Math.max(0, count - maxMessages);
1111
+ endIndex = count;
1112
+ }
1113
+ const messages = await this.netClient.getMessages({
1114
+ filter,
1115
+ startIndex,
1116
+ endIndex
1117
+ });
1118
+ let listings = [];
1119
+ for (const message of messages) {
1120
+ const listing = parseErc20ListingFromMessage(message, this.chainId);
1121
+ if (!listing) continue;
1122
+ if (listing.tokenAddress.toLowerCase() !== tokenAddress.toLowerCase()) {
1123
+ continue;
1124
+ }
1125
+ if (excludeMaker && listing.maker.toLowerCase() === excludeMaker.toLowerCase()) {
1126
+ continue;
1127
+ }
1128
+ listings.push(listing);
1129
+ }
1130
+ if (listings.length === 0) {
1131
+ return [];
1132
+ }
1133
+ const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
1134
+ for (const listing of listings) {
1135
+ const order = getSeaportOrderFromMessageData(listing.messageData);
1136
+ listing.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
1137
+ }
1138
+ const orderHashes = listings.map((l) => l.orderHash);
1139
+ const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
1140
+ listings.forEach((listing, index) => {
1141
+ const statusInfo = statusInfos[index];
1142
+ listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
1143
+ });
1144
+ listings = listings.filter(
1145
+ (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
1146
+ );
1147
+ if (listings.length === 0) {
1148
+ return [];
1149
+ }
1150
+ const uniqueMakers = [...new Set(listings.map((l) => l.maker))];
1151
+ const balances = await bulkFetchErc20Balances(this.client, tokenAddress, uniqueMakers);
1152
+ const balanceMap = /* @__PURE__ */ new Map();
1153
+ uniqueMakers.forEach((maker2, index) => {
1154
+ balanceMap.set(maker2.toLowerCase(), balances[index]);
1155
+ });
1156
+ listings = listings.filter((listing) => {
1157
+ const balance = balanceMap.get(listing.maker.toLowerCase()) || BigInt(0);
1158
+ return isErc20ListingValid(
1159
+ listing.orderStatus,
1160
+ listing.expirationDate,
1161
+ listing.tokenAmount,
1162
+ balance
1163
+ );
1164
+ });
1165
+ return sortErc20ListingsByPricePerToken(listings);
1166
+ }
1002
1167
  /**
1003
1168
  * Get the chain ID this client is configured for
1004
1169
  */
@@ -1024,6 +1189,12 @@ var BazaarClient = class {
1024
1189
  getErc20OffersAddress() {
1025
1190
  return getErc20OffersAddress(this.chainId);
1026
1191
  }
1192
+ /**
1193
+ * Get the ERC20 bazaar (listings) contract address for this chain
1194
+ */
1195
+ getErc20BazaarAddress() {
1196
+ return getErc20BazaarAddress(this.chainId);
1197
+ }
1027
1198
  /**
1028
1199
  * Get the Seaport contract address for this chain
1029
1200
  */
@@ -1054,6 +1225,18 @@ var BazaarClient = class {
1054
1225
  }
1055
1226
  return this.prepareCancelOrder(offer.orderComponents);
1056
1227
  }
1228
+ /**
1229
+ * Prepare a transaction to cancel an ERC20 listing
1230
+ *
1231
+ * The listing must have been created by the caller.
1232
+ * Use the orderComponents from the Erc20Listing object returned by getErc20Listings().
1233
+ */
1234
+ prepareCancelErc20Listing(listing) {
1235
+ if (!listing.orderComponents) {
1236
+ throw new Error("Listing does not have order components");
1237
+ }
1238
+ return this.prepareCancelOrder(listing.orderComponents);
1239
+ }
1057
1240
  /**
1058
1241
  * Prepare a transaction to cancel a Seaport order
1059
1242
  *
@@ -1101,13 +1284,17 @@ function useBazaarListings({
1101
1284
  chainId,
1102
1285
  nftAddress,
1103
1286
  excludeMaker,
1287
+ maker,
1104
1288
  maxMessages = 200,
1289
+ startIndex: startIndexOverride,
1290
+ endIndex: endIndexOverride,
1105
1291
  enabled = true
1106
1292
  }) {
1107
1293
  const [listings, setListings] = react.useState([]);
1108
1294
  const [isProcessing, setIsProcessing] = react.useState(false);
1109
1295
  const [processingError, setProcessingError] = react.useState();
1110
1296
  const [refetchTrigger, setRefetchTrigger] = react.useState(0);
1297
+ const hasRangeOverride = startIndexOverride != null && endIndexOverride != null;
1111
1298
  const isSupported = react.useMemo(
1112
1299
  () => isBazaarSupportedOnChain(chainId),
1113
1300
  [chainId]
@@ -1119,19 +1306,18 @@ function useBazaarListings({
1119
1306
  const filter = react.useMemo(
1120
1307
  () => ({
1121
1308
  appAddress: bazaarAddress,
1122
- topic: nftAddress.toLowerCase()
1309
+ topic: nftAddress.toLowerCase(),
1310
+ maker
1123
1311
  }),
1124
- [bazaarAddress, nftAddress]
1312
+ [bazaarAddress, nftAddress, maker]
1125
1313
  );
1126
1314
  const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
1127
1315
  chainId,
1128
1316
  filter,
1129
- enabled: enabled && isSupported
1317
+ enabled: enabled && isSupported && !hasRangeOverride
1130
1318
  });
1131
- const startIndex = react.useMemo(
1132
- () => Math.max(0, totalCount - maxMessages),
1133
- [totalCount, maxMessages]
1134
- );
1319
+ const startIndex = hasRangeOverride ? startIndexOverride : Math.max(0, totalCount - maxMessages);
1320
+ const endIndex = hasRangeOverride ? endIndexOverride : totalCount;
1135
1321
  const {
1136
1322
  messages,
1137
1323
  isLoading: isLoadingMessages,
@@ -1141,8 +1327,8 @@ function useBazaarListings({
1141
1327
  chainId,
1142
1328
  filter,
1143
1329
  startIndex,
1144
- endIndex: totalCount,
1145
- enabled: enabled && isSupported && totalCount > 0
1330
+ endIndex,
1331
+ enabled: enabled && isSupported && (hasRangeOverride || totalCount > 0)
1146
1332
  });
1147
1333
  react.useEffect(() => {
1148
1334
  if (!isSupported || !enabled) {
@@ -1162,7 +1348,10 @@ function useBazaarListings({
1162
1348
  const validListings = await client.getListings({
1163
1349
  nftAddress,
1164
1350
  excludeMaker,
1165
- maxMessages
1351
+ maker,
1352
+ maxMessages,
1353
+ startIndex: hasRangeOverride ? startIndexOverride : void 0,
1354
+ endIndex: hasRangeOverride ? endIndexOverride : void 0
1166
1355
  });
1167
1356
  if (!cancelled) {
1168
1357
  setListings(validListings);
@@ -1182,14 +1371,14 @@ function useBazaarListings({
1182
1371
  return () => {
1183
1372
  cancelled = true;
1184
1373
  };
1185
- }, [chainId, nftAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
1374
+ }, [chainId, nftAddress, excludeMaker, maker, maxMessages, startIndexOverride, endIndexOverride, hasRangeOverride, messages, isSupported, enabled, refetchTrigger]);
1186
1375
  const refetch = () => {
1187
1376
  refetchMessages();
1188
1377
  setRefetchTrigger((t) => t + 1);
1189
1378
  };
1190
1379
  return {
1191
1380
  listings,
1192
- isLoading: isLoadingCount || isLoadingMessages || isProcessing,
1381
+ isLoading: (hasRangeOverride ? false : isLoadingCount) || isLoadingMessages || isProcessing,
1193
1382
  error: messagesError || processingError,
1194
1383
  refetch
1195
1384
  };
@@ -1389,8 +1578,112 @@ function useBazaarErc20Offers({
1389
1578
  refetch
1390
1579
  };
1391
1580
  }
1581
+ function useBazaarErc20Listings({
1582
+ chainId,
1583
+ tokenAddress,
1584
+ excludeMaker,
1585
+ maker,
1586
+ maxMessages = 200,
1587
+ startIndex: startIndexOverride,
1588
+ endIndex: endIndexOverride,
1589
+ enabled = true
1590
+ }) {
1591
+ const [listings, setListings] = react.useState([]);
1592
+ const [isProcessing, setIsProcessing] = react.useState(false);
1593
+ const [processingError, setProcessingError] = react.useState();
1594
+ const [refetchTrigger, setRefetchTrigger] = react.useState(0);
1595
+ const hasRangeOverride = startIndexOverride != null && endIndexOverride != null;
1596
+ const isSupported = react.useMemo(
1597
+ () => isBazaarSupportedOnChain(chainId),
1598
+ [chainId]
1599
+ );
1600
+ const erc20BazaarAddress = react.useMemo(
1601
+ () => isSupported ? getErc20BazaarAddress(chainId) : void 0,
1602
+ [chainId, isSupported]
1603
+ );
1604
+ const filter = react.useMemo(
1605
+ () => ({
1606
+ appAddress: erc20BazaarAddress,
1607
+ topic: tokenAddress.toLowerCase(),
1608
+ maker
1609
+ }),
1610
+ [erc20BazaarAddress, tokenAddress, maker]
1611
+ );
1612
+ const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
1613
+ chainId,
1614
+ filter,
1615
+ enabled: enabled && isSupported && !hasRangeOverride
1616
+ });
1617
+ const startIndex = hasRangeOverride ? startIndexOverride : Math.max(0, totalCount - maxMessages);
1618
+ const endIndex = hasRangeOverride ? endIndexOverride : totalCount;
1619
+ const {
1620
+ messages,
1621
+ isLoading: isLoadingMessages,
1622
+ error: messagesError,
1623
+ refetch: refetchMessages
1624
+ } = react$1.useNetMessages({
1625
+ chainId,
1626
+ filter,
1627
+ startIndex,
1628
+ endIndex,
1629
+ enabled: enabled && isSupported && (hasRangeOverride || totalCount > 0)
1630
+ });
1631
+ react.useEffect(() => {
1632
+ if (!isSupported || !enabled) {
1633
+ setListings([]);
1634
+ return;
1635
+ }
1636
+ if (!messages || messages.length === 0) {
1637
+ setListings([]);
1638
+ return;
1639
+ }
1640
+ let cancelled = false;
1641
+ async function processListings() {
1642
+ setIsProcessing(true);
1643
+ setProcessingError(void 0);
1644
+ try {
1645
+ const client = new BazaarClient({ chainId });
1646
+ const validListings = await client.getErc20Listings({
1647
+ tokenAddress,
1648
+ excludeMaker,
1649
+ maker,
1650
+ maxMessages,
1651
+ startIndex: hasRangeOverride ? startIndexOverride : void 0,
1652
+ endIndex: hasRangeOverride ? endIndexOverride : void 0
1653
+ });
1654
+ if (!cancelled) {
1655
+ setListings(validListings);
1656
+ }
1657
+ } catch (err) {
1658
+ if (!cancelled) {
1659
+ setProcessingError(err instanceof Error ? err : new Error(String(err)));
1660
+ setListings([]);
1661
+ }
1662
+ } finally {
1663
+ if (!cancelled) {
1664
+ setIsProcessing(false);
1665
+ }
1666
+ }
1667
+ }
1668
+ processListings();
1669
+ return () => {
1670
+ cancelled = true;
1671
+ };
1672
+ }, [chainId, tokenAddress, excludeMaker, maker, maxMessages, startIndexOverride, endIndexOverride, hasRangeOverride, messages, isSupported, enabled, refetchTrigger]);
1673
+ const refetch = () => {
1674
+ refetchMessages();
1675
+ setRefetchTrigger((t) => t + 1);
1676
+ };
1677
+ return {
1678
+ listings,
1679
+ isLoading: (hasRangeOverride ? false : isLoadingCount) || isLoadingMessages || isProcessing,
1680
+ error: messagesError || processingError,
1681
+ refetch
1682
+ };
1683
+ }
1392
1684
 
1393
1685
  exports.useBazaarCollectionOffers = useBazaarCollectionOffers;
1686
+ exports.useBazaarErc20Listings = useBazaarErc20Listings;
1394
1687
  exports.useBazaarErc20Offers = useBazaarErc20Offers;
1395
1688
  exports.useBazaarListings = useBazaarListings;
1396
1689
  //# sourceMappingURL=react.js.map