@net-protocol/bazaar 0.1.1 → 0.1.3

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.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { useState, useMemo, useEffect } from 'react';
2
+ import { usePublicClient } from 'wagmi';
2
3
  import { useNetMessageCount, useNetMessages } from '@net-protocol/core/react';
3
4
  import { createPublicClient, http, defineChain, decodeAbiParameters, formatEther } from 'viem';
4
5
  import { NetClient } from '@net-protocol/core';
@@ -180,9 +181,10 @@ var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5"
180
181
  var DEFAULT_ERC20_BAZAAR_ADDRESS = "0x00000000a2d173a4610c85c7471a25b6bc216a70";
181
182
  var DEFAULT_NFT_FEE_BPS = 500;
182
183
  var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
183
- var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
184
- var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000b50a9f2923f2db931391824f6d1278f712";
184
+ var ERC721_OWNER_OF_HELPER_ADDRESS = "0x00000012E3eb0700925947fAF9cd1440319b4F37";
185
+ var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000B50A9f2923F2DB931391824F6D1278f712";
185
186
  var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
187
+ var NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = "0x000000bC63761cbb05305632212e2f3AE2BE7a9B";
186
188
  var BAZAAR_CHAIN_CONFIGS = {
187
189
  // Base Mainnet
188
190
  8453: {
@@ -461,34 +463,47 @@ async function bulkFetchOrderStatuses(client, chainId, orderHashes) {
461
463
  return [];
462
464
  }
463
465
  const seaportAddress = getSeaportAddress(chainId);
464
- const results = await readContract(client, {
465
- address: BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS,
466
- abi: BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI,
467
- functionName: "getOrderStatuses",
468
- args: [seaportAddress, orderHashes]
469
- });
470
- return results.map((r) => ({
471
- isValidated: r.isValidated,
472
- isCancelled: r.isCancelled,
473
- totalFilled: BigInt(r.totalFilled),
474
- totalSize: BigInt(r.totalSize)
475
- }));
466
+ try {
467
+ console.log(`[bulkFetchOrderStatuses] fetching ${orderHashes.length} statuses via ${BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS}`);
468
+ const results = await readContract(client, {
469
+ address: BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS,
470
+ abi: BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI,
471
+ functionName: "getOrderStatuses",
472
+ args: [seaportAddress, orderHashes]
473
+ });
474
+ const statuses = results.map((r) => ({
475
+ isValidated: r.isValidated,
476
+ isCancelled: r.isCancelled,
477
+ totalFilled: BigInt(r.totalFilled),
478
+ totalSize: BigInt(r.totalSize)
479
+ }));
480
+ console.log(`[bulkFetchOrderStatuses] success: ${statuses.length} statuses`);
481
+ return statuses;
482
+ } catch (err) {
483
+ console.error(`[bulkFetchOrderStatuses] FAILED for ${orderHashes.length} hashes:`, err);
484
+ throw err;
485
+ }
476
486
  }
477
487
  async function bulkFetchNftOwners(client, nftAddress, tokenIds) {
478
488
  if (tokenIds.length === 0) {
479
489
  return [];
480
490
  }
481
491
  try {
492
+ console.log(`[bulkFetchNftOwners] fetching ${tokenIds.length} owners for ${nftAddress.slice(0, 10)} via ${ERC721_OWNER_OF_HELPER_ADDRESS}`);
482
493
  const owners = await readContract(client, {
483
494
  address: ERC721_OWNER_OF_HELPER_ADDRESS,
484
495
  abi: ERC721_OWNER_OF_HELPER_ABI,
485
496
  functionName: "getTokenOwners",
486
497
  args: [nftAddress, tokenIds.map((id) => BigInt(id))]
487
498
  });
488
- return owners.map(
499
+ const result = owners.map(
489
500
  (owner) => owner === "0x0000000000000000000000000000000000000000" ? null : owner
490
501
  );
491
- } catch {
502
+ const validCount = result.filter((o) => o !== null).length;
503
+ console.log(`[bulkFetchNftOwners] success: ${validCount}/${tokenIds.length} have owners`);
504
+ return result;
505
+ } catch (err) {
506
+ console.error(`[bulkFetchNftOwners] FAILED for ${tokenIds.length} tokens \u2014 returning all null:`, err);
492
507
  return tokenIds.map(() => null);
493
508
  }
494
509
  }
@@ -497,14 +512,18 @@ async function bulkFetchErc20Balances(client, tokenAddress, addresses) {
497
512
  return [];
498
513
  }
499
514
  try {
515
+ console.log(`[bulkFetchErc20Balances] fetching ${addresses.length} balances for ${tokenAddress.slice(0, 10)}`);
500
516
  const balances = await readContract(client, {
501
517
  address: ERC20_BULK_BALANCE_CHECKER_ADDRESS,
502
518
  abi: ERC20_BULK_BALANCE_CHECKER_ABI,
503
519
  functionName: "getBalances",
504
520
  args: [tokenAddress, addresses]
505
521
  });
506
- return balances.map((b) => BigInt(b));
507
- } catch {
522
+ const result = balances.map((b) => BigInt(b));
523
+ console.log(`[bulkFetchErc20Balances] success: ${result.length} balances`);
524
+ return result;
525
+ } catch (err) {
526
+ console.error(`[bulkFetchErc20Balances] FAILED for ${addresses.length} addresses \u2014 returning all zero:`, err);
508
527
  return addresses.map(() => BigInt(0));
509
528
  }
510
529
  }
@@ -575,6 +594,7 @@ function parseListingFromMessage(message, chainId) {
575
594
  }
576
595
  const priceWei = getTotalConsiderationAmount(parameters);
577
596
  const tokenId = offerItem.identifierOrCriteria.toString();
597
+ const targetFulfiller = parameters.zone.toLowerCase() === NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS.toLowerCase() && parameters.zoneHash !== "0x0000000000000000000000000000000000000000000000000000000000000000" ? parameters.zoneHash : void 0;
578
598
  return {
579
599
  maker: parameters.offerer,
580
600
  nftAddress: offerItem.token,
@@ -591,7 +611,8 @@ function parseListingFromMessage(message, chainId) {
591
611
  orderComponents: {
592
612
  ...parameters,
593
613
  counter: submission.counter
594
- }
614
+ },
615
+ targetFulfiller
595
616
  };
596
617
  } catch {
597
618
  return null;
@@ -793,26 +814,30 @@ var BazaarClient = class {
793
814
  }
794
815
  this.chainId = params.chainId;
795
816
  this.rpcUrl = params.rpcUrl || CHAIN_RPC_URLS[params.chainId]?.[0] || "";
796
- if (!this.rpcUrl) {
797
- throw new Error(`No RPC URL available for chain ${params.chainId}`);
817
+ if (params.publicClient) {
818
+ this.client = params.publicClient;
819
+ } else {
820
+ if (!this.rpcUrl) {
821
+ throw new Error(`No RPC URL available for chain ${params.chainId}`);
822
+ }
823
+ const config = getBazaarChainConfig(params.chainId);
824
+ this.client = createPublicClient({
825
+ chain: defineChain({
826
+ id: params.chainId,
827
+ name: `Chain ${params.chainId}`,
828
+ nativeCurrency: {
829
+ name: config.wrappedNativeCurrency.name.replace("Wrapped ", ""),
830
+ symbol: config.currencySymbol.toUpperCase(),
831
+ decimals: 18
832
+ },
833
+ rpcUrls: {
834
+ default: { http: [this.rpcUrl] }
835
+ }
836
+ }),
837
+ transport: http(this.rpcUrl),
838
+ batch: { multicall: true }
839
+ });
798
840
  }
799
- const config = getBazaarChainConfig(params.chainId);
800
- this.client = createPublicClient({
801
- chain: defineChain({
802
- id: params.chainId,
803
- name: `Chain ${params.chainId}`,
804
- nativeCurrency: {
805
- name: config.wrappedNativeCurrency.name.replace("Wrapped ", ""),
806
- symbol: config.currencySymbol.toUpperCase(),
807
- decimals: 18
808
- },
809
- rpcUrls: {
810
- default: { http: [this.rpcUrl] }
811
- }
812
- }),
813
- transport: http(this.rpcUrl),
814
- batch: { multicall: true }
815
- });
816
841
  this.netClient = new NetClient({
817
842
  chainId: params.chainId,
818
843
  overrides: params.rpcUrl ? { rpcUrls: [params.rpcUrl] } : void 0
@@ -829,26 +854,42 @@ var BazaarClient = class {
829
854
  * Results are deduplicated (one per token) and sorted by price (lowest first)
830
855
  */
831
856
  async getListings(options) {
832
- const { nftAddress, excludeMaker, maxMessages = 200 } = options;
857
+ const { nftAddress, excludeMaker, maker, maxMessages = 200 } = options;
833
858
  const bazaarAddress = getBazaarAddress(this.chainId);
834
- const count = await this.netClient.getMessageCount({
835
- filter: {
836
- appAddress: bazaarAddress,
837
- topic: nftAddress.toLowerCase()
859
+ const filter = {
860
+ appAddress: bazaarAddress,
861
+ topic: nftAddress.toLowerCase(),
862
+ maker
863
+ };
864
+ let startIndex;
865
+ let endIndex;
866
+ if (options.startIndex != null && options.endIndex != null) {
867
+ startIndex = options.startIndex;
868
+ endIndex = options.endIndex;
869
+ } else {
870
+ const count = await this.netClient.getMessageCount({ filter });
871
+ if (count === 0) {
872
+ return [];
838
873
  }
839
- });
840
- if (count === 0) {
841
- return [];
874
+ startIndex = Math.max(0, count - maxMessages);
875
+ endIndex = count;
842
876
  }
843
- const startIndex = Math.max(0, count - maxMessages);
844
877
  const messages = await this.netClient.getMessages({
845
- filter: {
846
- appAddress: bazaarAddress,
847
- topic: nftAddress.toLowerCase()
848
- },
878
+ filter,
849
879
  startIndex,
850
- endIndex: count
880
+ endIndex
851
881
  });
882
+ return this.processListingsFromMessages(messages, options);
883
+ }
884
+ /**
885
+ * Process pre-fetched messages into valid NFT listings.
886
+ *
887
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
888
+ * to avoid redundant RPC calls.
889
+ */
890
+ async processListingsFromMessages(messages, options) {
891
+ const { nftAddress, excludeMaker, includeExpired = false } = options;
892
+ const tag = `[BazaarClient.processListings chain=${this.chainId}]`;
852
893
  let listings = [];
853
894
  for (const message of messages) {
854
895
  const listing = parseListingFromMessage(message, this.chainId);
@@ -858,6 +899,7 @@ var BazaarClient = class {
858
899
  }
859
900
  listings.push(listing);
860
901
  }
902
+ console.log(tag, `parsed ${listings.length}/${messages.length} messages into listings`);
861
903
  if (listings.length === 0) {
862
904
  return [];
863
905
  }
@@ -872,15 +914,27 @@ var BazaarClient = class {
872
914
  const statusInfo = statusInfos[index];
873
915
  listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
874
916
  });
917
+ const statusCounts = {};
918
+ const now = Math.floor(Date.now() / 1e3);
919
+ let expiredCount = 0;
920
+ for (const l of listings) {
921
+ statusCounts[l.orderStatus] = (statusCounts[l.orderStatus] || 0) + 1;
922
+ if (l.expirationDate <= now) expiredCount++;
923
+ }
924
+ console.log(tag, `order statuses:`, statusCounts, `expired: ${expiredCount}`);
875
925
  listings = listings.filter(
876
- (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
926
+ (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > now || includeExpired && l.orderStatus === 1 /* EXPIRED */
877
927
  );
928
+ console.log(tag, `after status filter: ${listings.length} (OPEN${includeExpired ? " + EXPIRED" : ""})`);
878
929
  if (listings.length === 0) {
879
930
  return [];
880
931
  }
881
- const tokenIds = listings.map((l) => l.tokenId);
932
+ const openListings = listings.filter((l) => l.orderStatus === 2 /* OPEN */);
933
+ const expiredListings = includeExpired ? listings.filter((l) => l.orderStatus === 1 /* EXPIRED */) : [];
934
+ const tokenIds = openListings.map((l) => l.tokenId);
882
935
  const owners = await bulkFetchNftOwners(this.client, nftAddress, tokenIds);
883
- listings = listings.filter((listing, index) => {
936
+ const beforeOwnership = openListings.length;
937
+ const validOpenListings = openListings.filter((listing, index) => {
884
938
  const owner = owners[index];
885
939
  return isListingValid(
886
940
  listing.orderStatus,
@@ -889,7 +943,16 @@ var BazaarClient = class {
889
943
  owner
890
944
  );
891
945
  });
892
- return sortListingsByPrice(getBestListingPerToken(listings));
946
+ console.log(tag, `after ownership filter: ${validOpenListings.length}/${beforeOwnership} (${beforeOwnership - validOpenListings.length} dropped)`);
947
+ const dedupedOpen = sortListingsByPrice(getBestListingPerToken(validOpenListings));
948
+ const activeTokenKeys = new Set(dedupedOpen.map((l) => `${l.nftAddress.toLowerCase()}-${l.tokenId}`));
949
+ const uniqueExpired = getBestListingPerToken(
950
+ expiredListings.filter((l) => !activeTokenKeys.has(`${l.nftAddress.toLowerCase()}-${l.tokenId}`))
951
+ );
952
+ const sortedExpired = sortListingsByPrice(uniqueExpired);
953
+ const result = [...dedupedOpen, ...sortedExpired];
954
+ console.log(tag, `final: ${result.length} listings (${dedupedOpen.length} open, ${sortedExpired.length} expired)`);
955
+ return result;
893
956
  }
894
957
  /**
895
958
  * Get valid collection offers for a collection
@@ -904,10 +967,6 @@ var BazaarClient = class {
904
967
  async getCollectionOffers(options) {
905
968
  const { nftAddress, excludeMaker, maxMessages = 100 } = options;
906
969
  const collectionOffersAddress = getCollectionOffersAddress(this.chainId);
907
- const weth = getWrappedNativeCurrency(this.chainId);
908
- if (!weth) {
909
- return [];
910
- }
911
970
  const count = await this.netClient.getMessageCount({
912
971
  filter: {
913
972
  appAddress: collectionOffersAddress,
@@ -926,6 +985,21 @@ var BazaarClient = class {
926
985
  startIndex,
927
986
  endIndex: count
928
987
  });
988
+ return this.processCollectionOffersFromMessages(messages, options);
989
+ }
990
+ /**
991
+ * Process pre-fetched messages into valid collection offers.
992
+ *
993
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
994
+ * to avoid redundant RPC calls.
995
+ */
996
+ async processCollectionOffersFromMessages(messages, options) {
997
+ const { nftAddress, excludeMaker } = options;
998
+ const tag = `[BazaarClient.processCollectionOffers chain=${this.chainId}]`;
999
+ const weth = getWrappedNativeCurrency(this.chainId);
1000
+ if (!weth) {
1001
+ return [];
1002
+ }
929
1003
  let offers = [];
930
1004
  for (const message of messages) {
931
1005
  const offer = parseCollectionOfferFromMessage(message, this.chainId);
@@ -940,6 +1014,7 @@ var BazaarClient = class {
940
1014
  }
941
1015
  offers.push(offer);
942
1016
  }
1017
+ console.log(tag, `parsed ${offers.length}/${messages.length} messages into offers`);
943
1018
  if (offers.length === 0) {
944
1019
  return [];
945
1020
  }
@@ -954,9 +1029,11 @@ var BazaarClient = class {
954
1029
  const statusInfo = statusInfos[index];
955
1030
  offer.orderStatus = getOrderStatusFromInfo(offer.orderComponents, statusInfo);
956
1031
  });
1032
+ const now = Math.floor(Date.now() / 1e3);
957
1033
  offers = offers.filter(
958
- (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > Math.floor(Date.now() / 1e3)
1034
+ (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > now
959
1035
  );
1036
+ console.log(tag, `after status filter: ${offers.length} OPEN & not expired`);
960
1037
  if (offers.length === 0) {
961
1038
  return [];
962
1039
  }
@@ -966,6 +1043,7 @@ var BazaarClient = class {
966
1043
  uniqueMakers.forEach((maker, index) => {
967
1044
  balanceMap.set(maker.toLowerCase(), balances[index]);
968
1045
  });
1046
+ const beforeBalance = offers.length;
969
1047
  offers = offers.filter((offer) => {
970
1048
  const balance = balanceMap.get(offer.maker.toLowerCase()) || BigInt(0);
971
1049
  return isCollectionOfferValid(
@@ -975,6 +1053,7 @@ var BazaarClient = class {
975
1053
  balance
976
1054
  );
977
1055
  });
1056
+ console.log(tag, `after balance filter: ${offers.length}/${beforeBalance} (${beforeBalance - offers.length} dropped)`);
978
1057
  return sortOffersByPrice(offers);
979
1058
  }
980
1059
  /**
@@ -992,8 +1071,7 @@ var BazaarClient = class {
992
1071
  async getErc20Offers(options) {
993
1072
  const { tokenAddress, excludeMaker, maxMessages = 200 } = options;
994
1073
  const erc20OffersAddress = getErc20OffersAddress(this.chainId);
995
- const weth = getWrappedNativeCurrency(this.chainId);
996
- if (!erc20OffersAddress || !weth) {
1074
+ if (!erc20OffersAddress) {
997
1075
  return [];
998
1076
  }
999
1077
  const count = await this.netClient.getMessageCount({
@@ -1014,6 +1092,21 @@ var BazaarClient = class {
1014
1092
  startIndex,
1015
1093
  endIndex: count
1016
1094
  });
1095
+ return this.processErc20OffersFromMessages(messages, options);
1096
+ }
1097
+ /**
1098
+ * Process pre-fetched messages into valid ERC20 offers.
1099
+ *
1100
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
1101
+ * to avoid redundant RPC calls.
1102
+ */
1103
+ async processErc20OffersFromMessages(messages, options) {
1104
+ const { tokenAddress, excludeMaker } = options;
1105
+ const tag = `[BazaarClient.processErc20Offers chain=${this.chainId}]`;
1106
+ const weth = getWrappedNativeCurrency(this.chainId);
1107
+ if (!weth) {
1108
+ return [];
1109
+ }
1017
1110
  let offers = [];
1018
1111
  for (const message of messages) {
1019
1112
  const offer = parseErc20OfferFromMessage(message, this.chainId);
@@ -1031,6 +1124,7 @@ var BazaarClient = class {
1031
1124
  }
1032
1125
  offers.push(offer);
1033
1126
  }
1127
+ console.log(tag, `parsed ${offers.length}/${messages.length} messages into offers`);
1034
1128
  if (offers.length === 0) {
1035
1129
  return [];
1036
1130
  }
@@ -1045,9 +1139,11 @@ var BazaarClient = class {
1045
1139
  const statusInfo = statusInfos[index];
1046
1140
  offer.orderStatus = getOrderStatusFromInfo(offer.orderComponents, statusInfo);
1047
1141
  });
1142
+ const now = Math.floor(Date.now() / 1e3);
1048
1143
  offers = offers.filter(
1049
- (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > Math.floor(Date.now() / 1e3)
1144
+ (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > now
1050
1145
  );
1146
+ console.log(tag, `after status filter: ${offers.length} OPEN & not expired`);
1051
1147
  if (offers.length === 0) {
1052
1148
  return [];
1053
1149
  }
@@ -1057,6 +1153,7 @@ var BazaarClient = class {
1057
1153
  uniqueMakers.forEach((maker, index) => {
1058
1154
  balanceMap.set(maker.toLowerCase(), balances[index]);
1059
1155
  });
1156
+ const beforeBalance = offers.length;
1060
1157
  offers = offers.filter((offer) => {
1061
1158
  const balance = balanceMap.get(offer.maker.toLowerCase()) || BigInt(0);
1062
1159
  return isErc20OfferValid(
@@ -1066,6 +1163,7 @@ var BazaarClient = class {
1066
1163
  balance
1067
1164
  );
1068
1165
  });
1166
+ console.log(tag, `after balance filter: ${offers.length}/${beforeBalance} (${beforeBalance - offers.length} dropped)`);
1069
1167
  return sortErc20OffersByPricePerToken(offers);
1070
1168
  }
1071
1169
  /**
@@ -1080,26 +1178,42 @@ var BazaarClient = class {
1080
1178
  * all valid listings are returned (grouped by maker in the UI).
1081
1179
  */
1082
1180
  async getErc20Listings(options) {
1083
- const { tokenAddress, excludeMaker, maxMessages = 200 } = options;
1181
+ const { tokenAddress, excludeMaker, maker, maxMessages = 200 } = options;
1084
1182
  const erc20BazaarAddress = getErc20BazaarAddress(this.chainId);
1085
- const count = await this.netClient.getMessageCount({
1086
- filter: {
1087
- appAddress: erc20BazaarAddress,
1088
- topic: tokenAddress.toLowerCase()
1183
+ const filter = {
1184
+ appAddress: erc20BazaarAddress,
1185
+ topic: tokenAddress.toLowerCase(),
1186
+ maker
1187
+ };
1188
+ let startIndex;
1189
+ let endIndex;
1190
+ if (options.startIndex != null && options.endIndex != null) {
1191
+ startIndex = options.startIndex;
1192
+ endIndex = options.endIndex;
1193
+ } else {
1194
+ const count = await this.netClient.getMessageCount({ filter });
1195
+ if (count === 0) {
1196
+ return [];
1089
1197
  }
1090
- });
1091
- if (count === 0) {
1092
- return [];
1198
+ startIndex = Math.max(0, count - maxMessages);
1199
+ endIndex = count;
1093
1200
  }
1094
- const startIndex = Math.max(0, count - maxMessages);
1095
1201
  const messages = await this.netClient.getMessages({
1096
- filter: {
1097
- appAddress: erc20BazaarAddress,
1098
- topic: tokenAddress.toLowerCase()
1099
- },
1202
+ filter,
1100
1203
  startIndex,
1101
- endIndex: count
1204
+ endIndex
1102
1205
  });
1206
+ return this.processErc20ListingsFromMessages(messages, options);
1207
+ }
1208
+ /**
1209
+ * Process pre-fetched messages into valid ERC20 listings.
1210
+ *
1211
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
1212
+ * to avoid redundant RPC calls.
1213
+ */
1214
+ async processErc20ListingsFromMessages(messages, options) {
1215
+ const { tokenAddress, excludeMaker } = options;
1216
+ const tag = `[BazaarClient.processErc20Listings chain=${this.chainId}]`;
1103
1217
  let listings = [];
1104
1218
  for (const message of messages) {
1105
1219
  const listing = parseErc20ListingFromMessage(message, this.chainId);
@@ -1112,6 +1226,7 @@ var BazaarClient = class {
1112
1226
  }
1113
1227
  listings.push(listing);
1114
1228
  }
1229
+ console.log(tag, `parsed ${listings.length}/${messages.length} messages into listings`);
1115
1230
  if (listings.length === 0) {
1116
1231
  return [];
1117
1232
  }
@@ -1126,9 +1241,18 @@ var BazaarClient = class {
1126
1241
  const statusInfo = statusInfos[index];
1127
1242
  listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
1128
1243
  });
1244
+ const statusCounts = {};
1245
+ const now = Math.floor(Date.now() / 1e3);
1246
+ let expiredCount = 0;
1247
+ for (const l of listings) {
1248
+ statusCounts[l.orderStatus] = (statusCounts[l.orderStatus] || 0) + 1;
1249
+ if (l.expirationDate <= now) expiredCount++;
1250
+ }
1251
+ console.log(tag, `order statuses:`, statusCounts, `expired: ${expiredCount}`);
1129
1252
  listings = listings.filter(
1130
- (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
1253
+ (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > now
1131
1254
  );
1255
+ console.log(tag, `after status filter: ${listings.length} OPEN & not expired`);
1132
1256
  if (listings.length === 0) {
1133
1257
  return [];
1134
1258
  }
@@ -1138,6 +1262,7 @@ var BazaarClient = class {
1138
1262
  uniqueMakers.forEach((maker, index) => {
1139
1263
  balanceMap.set(maker.toLowerCase(), balances[index]);
1140
1264
  });
1265
+ const beforeBalance = listings.length;
1141
1266
  listings = listings.filter((listing) => {
1142
1267
  const balance = balanceMap.get(listing.maker.toLowerCase()) || BigInt(0);
1143
1268
  return isErc20ListingValid(
@@ -1147,6 +1272,7 @@ var BazaarClient = class {
1147
1272
  balance
1148
1273
  );
1149
1274
  });
1275
+ console.log(tag, `after balance filter: ${listings.length}/${beforeBalance} (${beforeBalance - listings.length} dropped)`);
1150
1276
  return sortErc20ListingsByPricePerToken(listings);
1151
1277
  }
1152
1278
  /**
@@ -1269,13 +1395,21 @@ function useBazaarListings({
1269
1395
  chainId,
1270
1396
  nftAddress,
1271
1397
  excludeMaker,
1398
+ maker,
1272
1399
  maxMessages = 200,
1273
- enabled = true
1400
+ startIndex: startIndexOverride,
1401
+ endIndex: endIndexOverride,
1402
+ includeExpired = false,
1403
+ enabled = true,
1404
+ publicClient
1274
1405
  }) {
1406
+ const wagmiClient = usePublicClient({ chainId });
1407
+ const resolvedClient = publicClient ?? wagmiClient;
1275
1408
  const [listings, setListings] = useState([]);
1276
1409
  const [isProcessing, setIsProcessing] = useState(false);
1277
1410
  const [processingError, setProcessingError] = useState();
1278
1411
  const [refetchTrigger, setRefetchTrigger] = useState(0);
1412
+ const hasRangeOverride = startIndexOverride != null && endIndexOverride != null;
1279
1413
  const isSupported = useMemo(
1280
1414
  () => isBazaarSupportedOnChain(chainId),
1281
1415
  [chainId]
@@ -1287,19 +1421,18 @@ function useBazaarListings({
1287
1421
  const filter = useMemo(
1288
1422
  () => ({
1289
1423
  appAddress: bazaarAddress,
1290
- topic: nftAddress.toLowerCase()
1424
+ topic: nftAddress.toLowerCase(),
1425
+ maker
1291
1426
  }),
1292
- [bazaarAddress, nftAddress]
1427
+ [bazaarAddress, nftAddress, maker]
1293
1428
  );
1294
1429
  const { count: totalCount, isLoading: isLoadingCount } = useNetMessageCount({
1295
1430
  chainId,
1296
1431
  filter,
1297
- enabled: enabled && isSupported
1432
+ enabled: enabled && isSupported && !hasRangeOverride
1298
1433
  });
1299
- const startIndex = useMemo(
1300
- () => Math.max(0, totalCount - maxMessages),
1301
- [totalCount, maxMessages]
1302
- );
1434
+ const startIndex = hasRangeOverride ? startIndexOverride : Math.max(0, totalCount - maxMessages);
1435
+ const endIndex = hasRangeOverride ? endIndexOverride : totalCount;
1303
1436
  const {
1304
1437
  messages,
1305
1438
  isLoading: isLoadingMessages,
@@ -1309,9 +1442,24 @@ function useBazaarListings({
1309
1442
  chainId,
1310
1443
  filter,
1311
1444
  startIndex,
1312
- endIndex: totalCount,
1313
- enabled: enabled && isSupported && totalCount > 0
1445
+ endIndex,
1446
+ enabled: enabled && isSupported && (hasRangeOverride || totalCount > 0)
1314
1447
  });
1448
+ const TAG = `[useBazaarListings chain=${chainId} nft=${nftAddress.slice(0, 10)}]`;
1449
+ useEffect(() => {
1450
+ console.log(TAG, {
1451
+ enabled,
1452
+ isSupported,
1453
+ hasRangeOverride,
1454
+ totalCount,
1455
+ isLoadingCount,
1456
+ startIndex,
1457
+ endIndex,
1458
+ messagesLength: messages?.length ?? 0,
1459
+ isLoadingMessages,
1460
+ messagesError: messagesError?.message
1461
+ });
1462
+ }, [enabled, isSupported, hasRangeOverride, totalCount, isLoadingCount, startIndex, endIndex, messages?.length, isLoadingMessages, messagesError]);
1315
1463
  useEffect(() => {
1316
1464
  if (!isSupported || !enabled) {
1317
1465
  setListings([]);
@@ -1325,17 +1473,19 @@ function useBazaarListings({
1325
1473
  async function processListings() {
1326
1474
  setIsProcessing(true);
1327
1475
  setProcessingError(void 0);
1476
+ console.log(TAG, `processing ${messages.length} messages...`);
1328
1477
  try {
1329
- const client = new BazaarClient({ chainId });
1330
- const validListings = await client.getListings({
1331
- nftAddress,
1332
- excludeMaker,
1333
- maxMessages
1334
- });
1478
+ const client = new BazaarClient({ chainId, publicClient: resolvedClient });
1479
+ const validListings = await client.processListingsFromMessages(
1480
+ messages,
1481
+ { nftAddress, excludeMaker, includeExpired }
1482
+ );
1483
+ console.log(TAG, `processed \u2192 ${validListings.length} valid listings`);
1335
1484
  if (!cancelled) {
1336
1485
  setListings(validListings);
1337
1486
  }
1338
1487
  } catch (err) {
1488
+ console.error(TAG, "processing error:", err);
1339
1489
  if (!cancelled) {
1340
1490
  setProcessingError(err instanceof Error ? err : new Error(String(err)));
1341
1491
  setListings([]);
@@ -1350,14 +1500,14 @@ function useBazaarListings({
1350
1500
  return () => {
1351
1501
  cancelled = true;
1352
1502
  };
1353
- }, [chainId, nftAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
1503
+ }, [chainId, nftAddress, excludeMaker, includeExpired, messages, isSupported, enabled, refetchTrigger]);
1354
1504
  const refetch = () => {
1355
1505
  refetchMessages();
1356
1506
  setRefetchTrigger((t) => t + 1);
1357
1507
  };
1358
1508
  return {
1359
1509
  listings,
1360
- isLoading: isLoadingCount || isLoadingMessages || isProcessing,
1510
+ isLoading: (hasRangeOverride ? false : isLoadingCount) || isLoadingMessages || isProcessing,
1361
1511
  error: messagesError || processingError,
1362
1512
  refetch
1363
1513
  };
@@ -1369,6 +1519,7 @@ function useBazaarCollectionOffers({
1369
1519
  maxMessages = 100,
1370
1520
  enabled = true
1371
1521
  }) {
1522
+ const wagmiClient = usePublicClient({ chainId });
1372
1523
  const [offers, setOffers] = useState([]);
1373
1524
  const [isProcessing, setIsProcessing] = useState(false);
1374
1525
  const [processingError, setProcessingError] = useState();
@@ -1409,6 +1560,20 @@ function useBazaarCollectionOffers({
1409
1560
  endIndex: totalCount,
1410
1561
  enabled: enabled && isSupported && totalCount > 0
1411
1562
  });
1563
+ const TAG = `[useBazaarCollectionOffers chain=${chainId} nft=${nftAddress.slice(0, 10)}]`;
1564
+ useEffect(() => {
1565
+ console.log(TAG, {
1566
+ enabled,
1567
+ isSupported,
1568
+ totalCount,
1569
+ isLoadingCount,
1570
+ startIndex,
1571
+ endIndex: totalCount,
1572
+ messagesLength: messages?.length ?? 0,
1573
+ isLoadingMessages,
1574
+ messagesError: messagesError?.message
1575
+ });
1576
+ }, [enabled, isSupported, totalCount, isLoadingCount, startIndex, messages?.length, isLoadingMessages, messagesError]);
1412
1577
  useEffect(() => {
1413
1578
  if (!isSupported || !enabled) {
1414
1579
  setOffers([]);
@@ -1422,17 +1587,19 @@ function useBazaarCollectionOffers({
1422
1587
  async function processOffers() {
1423
1588
  setIsProcessing(true);
1424
1589
  setProcessingError(void 0);
1590
+ console.log(TAG, `processing ${messages.length} messages...`);
1425
1591
  try {
1426
- const client = new BazaarClient({ chainId });
1427
- const validOffers = await client.getCollectionOffers({
1428
- nftAddress,
1429
- excludeMaker,
1430
- maxMessages
1431
- });
1592
+ const client = new BazaarClient({ chainId, publicClient: wagmiClient });
1593
+ const validOffers = await client.processCollectionOffersFromMessages(
1594
+ messages,
1595
+ { nftAddress, excludeMaker }
1596
+ );
1597
+ console.log(TAG, `processed \u2192 ${validOffers.length} valid offers`);
1432
1598
  if (!cancelled) {
1433
1599
  setOffers(validOffers);
1434
1600
  }
1435
1601
  } catch (err) {
1602
+ console.error(TAG, "processing error:", err);
1436
1603
  if (!cancelled) {
1437
1604
  setProcessingError(err instanceof Error ? err : new Error(String(err)));
1438
1605
  setOffers([]);
@@ -1447,7 +1614,7 @@ function useBazaarCollectionOffers({
1447
1614
  return () => {
1448
1615
  cancelled = true;
1449
1616
  };
1450
- }, [chainId, nftAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
1617
+ }, [chainId, nftAddress, excludeMaker, messages, isSupported, enabled, refetchTrigger]);
1451
1618
  const refetch = () => {
1452
1619
  refetchMessages();
1453
1620
  setRefetchTrigger((t) => t + 1);
@@ -1466,6 +1633,7 @@ function useBazaarErc20Offers({
1466
1633
  maxMessages = 200,
1467
1634
  enabled = true
1468
1635
  }) {
1636
+ const wagmiClient = usePublicClient({ chainId });
1469
1637
  const [offers, setOffers] = useState([]);
1470
1638
  const [isProcessing, setIsProcessing] = useState(false);
1471
1639
  const [processingError, setProcessingError] = useState();
@@ -1507,6 +1675,20 @@ function useBazaarErc20Offers({
1507
1675
  endIndex: totalCount,
1508
1676
  enabled: enabled && hasErc20Offers && totalCount > 0
1509
1677
  });
1678
+ const TAG = `[useBazaarErc20Offers chain=${chainId} token=${tokenAddress.slice(0, 10)}]`;
1679
+ useEffect(() => {
1680
+ console.log(TAG, {
1681
+ enabled,
1682
+ hasErc20Offers,
1683
+ totalCount,
1684
+ isLoadingCount,
1685
+ startIndex,
1686
+ endIndex: totalCount,
1687
+ messagesLength: messages?.length ?? 0,
1688
+ isLoadingMessages,
1689
+ messagesError: messagesError?.message
1690
+ });
1691
+ }, [enabled, hasErc20Offers, totalCount, isLoadingCount, startIndex, messages?.length, isLoadingMessages, messagesError]);
1510
1692
  useEffect(() => {
1511
1693
  if (!hasErc20Offers || !enabled) {
1512
1694
  setOffers([]);
@@ -1520,17 +1702,19 @@ function useBazaarErc20Offers({
1520
1702
  async function processOffers() {
1521
1703
  setIsProcessing(true);
1522
1704
  setProcessingError(void 0);
1705
+ console.log(TAG, `processing ${messages.length} messages...`);
1523
1706
  try {
1524
- const client = new BazaarClient({ chainId });
1525
- const validOffers = await client.getErc20Offers({
1526
- tokenAddress,
1527
- excludeMaker,
1528
- maxMessages
1529
- });
1707
+ const client = new BazaarClient({ chainId, publicClient: wagmiClient });
1708
+ const validOffers = await client.processErc20OffersFromMessages(
1709
+ messages,
1710
+ { tokenAddress, excludeMaker }
1711
+ );
1712
+ console.log(TAG, `processed \u2192 ${validOffers.length} valid offers`);
1530
1713
  if (!cancelled) {
1531
1714
  setOffers(validOffers);
1532
1715
  }
1533
1716
  } catch (err) {
1717
+ console.error(TAG, "processing error:", err);
1534
1718
  if (!cancelled) {
1535
1719
  setProcessingError(err instanceof Error ? err : new Error(String(err)));
1536
1720
  setOffers([]);
@@ -1545,7 +1729,7 @@ function useBazaarErc20Offers({
1545
1729
  return () => {
1546
1730
  cancelled = true;
1547
1731
  };
1548
- }, [chainId, tokenAddress, excludeMaker, maxMessages, messages, hasErc20Offers, enabled, refetchTrigger]);
1732
+ }, [chainId, tokenAddress, excludeMaker, messages, hasErc20Offers, enabled, refetchTrigger]);
1549
1733
  const refetch = () => {
1550
1734
  refetchMessages();
1551
1735
  setRefetchTrigger((t) => t + 1);
@@ -1561,13 +1745,20 @@ function useBazaarErc20Listings({
1561
1745
  chainId,
1562
1746
  tokenAddress,
1563
1747
  excludeMaker,
1748
+ maker,
1564
1749
  maxMessages = 200,
1565
- enabled = true
1750
+ startIndex: startIndexOverride,
1751
+ endIndex: endIndexOverride,
1752
+ enabled = true,
1753
+ publicClient
1566
1754
  }) {
1755
+ const wagmiClient = usePublicClient({ chainId });
1756
+ const resolvedClient = publicClient ?? wagmiClient;
1567
1757
  const [listings, setListings] = useState([]);
1568
1758
  const [isProcessing, setIsProcessing] = useState(false);
1569
1759
  const [processingError, setProcessingError] = useState();
1570
1760
  const [refetchTrigger, setRefetchTrigger] = useState(0);
1761
+ const hasRangeOverride = startIndexOverride != null && endIndexOverride != null;
1571
1762
  const isSupported = useMemo(
1572
1763
  () => isBazaarSupportedOnChain(chainId),
1573
1764
  [chainId]
@@ -1579,19 +1770,18 @@ function useBazaarErc20Listings({
1579
1770
  const filter = useMemo(
1580
1771
  () => ({
1581
1772
  appAddress: erc20BazaarAddress,
1582
- topic: tokenAddress.toLowerCase()
1773
+ topic: tokenAddress.toLowerCase(),
1774
+ maker
1583
1775
  }),
1584
- [erc20BazaarAddress, tokenAddress]
1776
+ [erc20BazaarAddress, tokenAddress, maker]
1585
1777
  );
1586
1778
  const { count: totalCount, isLoading: isLoadingCount } = useNetMessageCount({
1587
1779
  chainId,
1588
1780
  filter,
1589
- enabled: enabled && isSupported
1781
+ enabled: enabled && isSupported && !hasRangeOverride
1590
1782
  });
1591
- const startIndex = useMemo(
1592
- () => Math.max(0, totalCount - maxMessages),
1593
- [totalCount, maxMessages]
1594
- );
1783
+ const startIndex = hasRangeOverride ? startIndexOverride : Math.max(0, totalCount - maxMessages);
1784
+ const endIndex = hasRangeOverride ? endIndexOverride : totalCount;
1595
1785
  const {
1596
1786
  messages,
1597
1787
  isLoading: isLoadingMessages,
@@ -1601,9 +1791,24 @@ function useBazaarErc20Listings({
1601
1791
  chainId,
1602
1792
  filter,
1603
1793
  startIndex,
1604
- endIndex: totalCount,
1605
- enabled: enabled && isSupported && totalCount > 0
1794
+ endIndex,
1795
+ enabled: enabled && isSupported && (hasRangeOverride || totalCount > 0)
1606
1796
  });
1797
+ const TAG = `[useBazaarErc20Listings chain=${chainId} token=${tokenAddress.slice(0, 10)}]`;
1798
+ useEffect(() => {
1799
+ console.log(TAG, {
1800
+ enabled,
1801
+ isSupported,
1802
+ hasRangeOverride,
1803
+ totalCount,
1804
+ isLoadingCount,
1805
+ startIndex,
1806
+ endIndex,
1807
+ messagesLength: messages?.length ?? 0,
1808
+ isLoadingMessages,
1809
+ messagesError: messagesError?.message
1810
+ });
1811
+ }, [enabled, isSupported, hasRangeOverride, totalCount, isLoadingCount, startIndex, endIndex, messages?.length, isLoadingMessages, messagesError]);
1607
1812
  useEffect(() => {
1608
1813
  if (!isSupported || !enabled) {
1609
1814
  setListings([]);
@@ -1617,17 +1822,19 @@ function useBazaarErc20Listings({
1617
1822
  async function processListings() {
1618
1823
  setIsProcessing(true);
1619
1824
  setProcessingError(void 0);
1825
+ console.log(TAG, `processing ${messages.length} messages...`);
1620
1826
  try {
1621
- const client = new BazaarClient({ chainId });
1622
- const validListings = await client.getErc20Listings({
1623
- tokenAddress,
1624
- excludeMaker,
1625
- maxMessages
1626
- });
1827
+ const client = new BazaarClient({ chainId, publicClient: resolvedClient });
1828
+ const validListings = await client.processErc20ListingsFromMessages(
1829
+ messages,
1830
+ { tokenAddress, excludeMaker }
1831
+ );
1832
+ console.log(TAG, `processed \u2192 ${validListings.length} valid listings`);
1627
1833
  if (!cancelled) {
1628
1834
  setListings(validListings);
1629
1835
  }
1630
1836
  } catch (err) {
1837
+ console.error(TAG, "processing error:", err);
1631
1838
  if (!cancelled) {
1632
1839
  setProcessingError(err instanceof Error ? err : new Error(String(err)));
1633
1840
  setListings([]);
@@ -1642,14 +1849,14 @@ function useBazaarErc20Listings({
1642
1849
  return () => {
1643
1850
  cancelled = true;
1644
1851
  };
1645
- }, [chainId, tokenAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
1852
+ }, [chainId, tokenAddress, excludeMaker, messages, isSupported, enabled, refetchTrigger]);
1646
1853
  const refetch = () => {
1647
1854
  refetchMessages();
1648
1855
  setRefetchTrigger((t) => t + 1);
1649
1856
  };
1650
1857
  return {
1651
1858
  listings,
1652
- isLoading: isLoadingCount || isLoadingMessages || isProcessing,
1859
+ isLoading: (hasRangeOverride ? false : isLoadingCount) || isLoadingMessages || isProcessing,
1653
1860
  error: messagesError || processingError,
1654
1861
  refetch
1655
1862
  };