@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/index.js CHANGED
@@ -359,10 +359,11 @@ var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5"
359
359
  var DEFAULT_ERC20_BAZAAR_ADDRESS = "0x00000000a2d173a4610c85c7471a25b6bc216a70";
360
360
  var DEFAULT_NFT_FEE_BPS = 500;
361
361
  var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
362
- var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
363
- var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000b50a9f2923f2db931391824f6d1278f712";
362
+ var ERC721_OWNER_OF_HELPER_ADDRESS = "0x00000012E3eb0700925947fAF9cd1440319b4F37";
363
+ var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000B50A9f2923F2DB931391824F6D1278f712";
364
364
  var NET_SEAPORT_ZONE_ADDRESS = "0x000000007F8c58fbf215bF91Bda7421A806cf3ae";
365
365
  var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
366
+ var NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = "0x000000bC63761cbb05305632212e2f3AE2BE7a9B";
366
367
  var BAZAAR_CHAIN_CONFIGS = {
367
368
  // Base Mainnet
368
369
  8453: {
@@ -650,18 +651,26 @@ async function bulkFetchOrderStatuses(client, chainId, orderHashes) {
650
651
  return [];
651
652
  }
652
653
  const seaportAddress = getSeaportAddress(chainId);
653
- const results = await actions.readContract(client, {
654
- address: BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS,
655
- abi: BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI,
656
- functionName: "getOrderStatuses",
657
- args: [seaportAddress, orderHashes]
658
- });
659
- return results.map((r) => ({
660
- isValidated: r.isValidated,
661
- isCancelled: r.isCancelled,
662
- totalFilled: BigInt(r.totalFilled),
663
- totalSize: BigInt(r.totalSize)
664
- }));
654
+ try {
655
+ console.log(`[bulkFetchOrderStatuses] fetching ${orderHashes.length} statuses via ${BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS}`);
656
+ const results = await actions.readContract(client, {
657
+ address: BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS,
658
+ abi: BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI,
659
+ functionName: "getOrderStatuses",
660
+ args: [seaportAddress, orderHashes]
661
+ });
662
+ const statuses = results.map((r) => ({
663
+ isValidated: r.isValidated,
664
+ isCancelled: r.isCancelled,
665
+ totalFilled: BigInt(r.totalFilled),
666
+ totalSize: BigInt(r.totalSize)
667
+ }));
668
+ console.log(`[bulkFetchOrderStatuses] success: ${statuses.length} statuses`);
669
+ return statuses;
670
+ } catch (err) {
671
+ console.error(`[bulkFetchOrderStatuses] FAILED for ${orderHashes.length} hashes:`, err);
672
+ throw err;
673
+ }
665
674
  }
666
675
  async function createOrderStatusMap(client, chainId, orderHashes) {
667
676
  const statuses = await bulkFetchOrderStatuses(client, chainId, orderHashes);
@@ -676,16 +685,21 @@ async function bulkFetchNftOwners(client, nftAddress, tokenIds) {
676
685
  return [];
677
686
  }
678
687
  try {
688
+ console.log(`[bulkFetchNftOwners] fetching ${tokenIds.length} owners for ${nftAddress.slice(0, 10)} via ${ERC721_OWNER_OF_HELPER_ADDRESS}`);
679
689
  const owners = await actions.readContract(client, {
680
690
  address: ERC721_OWNER_OF_HELPER_ADDRESS,
681
691
  abi: ERC721_OWNER_OF_HELPER_ABI,
682
692
  functionName: "getTokenOwners",
683
693
  args: [nftAddress, tokenIds.map((id) => BigInt(id))]
684
694
  });
685
- return owners.map(
695
+ const result = owners.map(
686
696
  (owner) => owner === "0x0000000000000000000000000000000000000000" ? null : owner
687
697
  );
688
- } catch {
698
+ const validCount = result.filter((o) => o !== null).length;
699
+ console.log(`[bulkFetchNftOwners] success: ${validCount}/${tokenIds.length} have owners`);
700
+ return result;
701
+ } catch (err) {
702
+ console.error(`[bulkFetchNftOwners] FAILED for ${tokenIds.length} tokens \u2014 returning all null:`, err);
689
703
  return tokenIds.map(() => null);
690
704
  }
691
705
  }
@@ -702,14 +716,18 @@ async function bulkFetchErc20Balances(client, tokenAddress, addresses) {
702
716
  return [];
703
717
  }
704
718
  try {
719
+ console.log(`[bulkFetchErc20Balances] fetching ${addresses.length} balances for ${tokenAddress.slice(0, 10)}`);
705
720
  const balances = await actions.readContract(client, {
706
721
  address: ERC20_BULK_BALANCE_CHECKER_ADDRESS,
707
722
  abi: ERC20_BULK_BALANCE_CHECKER_ABI,
708
723
  functionName: "getBalances",
709
724
  args: [tokenAddress, addresses]
710
725
  });
711
- return balances.map((b) => BigInt(b));
712
- } catch {
726
+ const result = balances.map((b) => BigInt(b));
727
+ console.log(`[bulkFetchErc20Balances] success: ${result.length} balances`);
728
+ return result;
729
+ } catch (err) {
730
+ console.error(`[bulkFetchErc20Balances] FAILED for ${addresses.length} addresses \u2014 returning all zero:`, err);
713
731
  return addresses.map(() => BigInt(0));
714
732
  }
715
733
  }
@@ -788,6 +806,7 @@ function parseListingFromMessage(message, chainId) {
788
806
  }
789
807
  const priceWei = getTotalConsiderationAmount(parameters);
790
808
  const tokenId = offerItem.identifierOrCriteria.toString();
809
+ const targetFulfiller = parameters.zone.toLowerCase() === NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS.toLowerCase() && parameters.zoneHash !== "0x0000000000000000000000000000000000000000000000000000000000000000" ? parameters.zoneHash : void 0;
791
810
  return {
792
811
  maker: parameters.offerer,
793
812
  nftAddress: offerItem.token,
@@ -804,7 +823,8 @@ function parseListingFromMessage(message, chainId) {
804
823
  orderComponents: {
805
824
  ...parameters,
806
825
  counter: submission.counter
807
- }
826
+ },
827
+ targetFulfiller
808
828
  };
809
829
  } catch {
810
830
  return null;
@@ -1014,26 +1034,30 @@ var BazaarClient = class {
1014
1034
  }
1015
1035
  this.chainId = params.chainId;
1016
1036
  this.rpcUrl = params.rpcUrl || CHAIN_RPC_URLS[params.chainId]?.[0] || "";
1017
- if (!this.rpcUrl) {
1018
- throw new Error(`No RPC URL available for chain ${params.chainId}`);
1037
+ if (params.publicClient) {
1038
+ this.client = params.publicClient;
1039
+ } else {
1040
+ if (!this.rpcUrl) {
1041
+ throw new Error(`No RPC URL available for chain ${params.chainId}`);
1042
+ }
1043
+ const config = getBazaarChainConfig(params.chainId);
1044
+ this.client = viem.createPublicClient({
1045
+ chain: viem.defineChain({
1046
+ id: params.chainId,
1047
+ name: `Chain ${params.chainId}`,
1048
+ nativeCurrency: {
1049
+ name: config.wrappedNativeCurrency.name.replace("Wrapped ", ""),
1050
+ symbol: config.currencySymbol.toUpperCase(),
1051
+ decimals: 18
1052
+ },
1053
+ rpcUrls: {
1054
+ default: { http: [this.rpcUrl] }
1055
+ }
1056
+ }),
1057
+ transport: viem.http(this.rpcUrl),
1058
+ batch: { multicall: true }
1059
+ });
1019
1060
  }
1020
- const config = getBazaarChainConfig(params.chainId);
1021
- this.client = viem.createPublicClient({
1022
- chain: viem.defineChain({
1023
- id: params.chainId,
1024
- name: `Chain ${params.chainId}`,
1025
- nativeCurrency: {
1026
- name: config.wrappedNativeCurrency.name.replace("Wrapped ", ""),
1027
- symbol: config.currencySymbol.toUpperCase(),
1028
- decimals: 18
1029
- },
1030
- rpcUrls: {
1031
- default: { http: [this.rpcUrl] }
1032
- }
1033
- }),
1034
- transport: viem.http(this.rpcUrl),
1035
- batch: { multicall: true }
1036
- });
1037
1061
  this.netClient = new core.NetClient({
1038
1062
  chainId: params.chainId,
1039
1063
  overrides: params.rpcUrl ? { rpcUrls: [params.rpcUrl] } : void 0
@@ -1050,26 +1074,42 @@ var BazaarClient = class {
1050
1074
  * Results are deduplicated (one per token) and sorted by price (lowest first)
1051
1075
  */
1052
1076
  async getListings(options) {
1053
- const { nftAddress, excludeMaker, maxMessages = 200 } = options;
1077
+ const { nftAddress, excludeMaker, maker, maxMessages = 200 } = options;
1054
1078
  const bazaarAddress = getBazaarAddress(this.chainId);
1055
- const count = await this.netClient.getMessageCount({
1056
- filter: {
1057
- appAddress: bazaarAddress,
1058
- topic: nftAddress.toLowerCase()
1079
+ const filter = {
1080
+ appAddress: bazaarAddress,
1081
+ topic: nftAddress.toLowerCase(),
1082
+ maker
1083
+ };
1084
+ let startIndex;
1085
+ let endIndex;
1086
+ if (options.startIndex != null && options.endIndex != null) {
1087
+ startIndex = options.startIndex;
1088
+ endIndex = options.endIndex;
1089
+ } else {
1090
+ const count = await this.netClient.getMessageCount({ filter });
1091
+ if (count === 0) {
1092
+ return [];
1059
1093
  }
1060
- });
1061
- if (count === 0) {
1062
- return [];
1094
+ startIndex = Math.max(0, count - maxMessages);
1095
+ endIndex = count;
1063
1096
  }
1064
- const startIndex = Math.max(0, count - maxMessages);
1065
1097
  const messages = await this.netClient.getMessages({
1066
- filter: {
1067
- appAddress: bazaarAddress,
1068
- topic: nftAddress.toLowerCase()
1069
- },
1098
+ filter,
1070
1099
  startIndex,
1071
- endIndex: count
1100
+ endIndex
1072
1101
  });
1102
+ return this.processListingsFromMessages(messages, options);
1103
+ }
1104
+ /**
1105
+ * Process pre-fetched messages into valid NFT listings.
1106
+ *
1107
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
1108
+ * to avoid redundant RPC calls.
1109
+ */
1110
+ async processListingsFromMessages(messages, options) {
1111
+ const { nftAddress, excludeMaker, includeExpired = false } = options;
1112
+ const tag = `[BazaarClient.processListings chain=${this.chainId}]`;
1073
1113
  let listings = [];
1074
1114
  for (const message of messages) {
1075
1115
  const listing = parseListingFromMessage(message, this.chainId);
@@ -1079,6 +1119,7 @@ var BazaarClient = class {
1079
1119
  }
1080
1120
  listings.push(listing);
1081
1121
  }
1122
+ console.log(tag, `parsed ${listings.length}/${messages.length} messages into listings`);
1082
1123
  if (listings.length === 0) {
1083
1124
  return [];
1084
1125
  }
@@ -1093,15 +1134,27 @@ var BazaarClient = class {
1093
1134
  const statusInfo = statusInfos[index];
1094
1135
  listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
1095
1136
  });
1137
+ const statusCounts = {};
1138
+ const now = Math.floor(Date.now() / 1e3);
1139
+ let expiredCount = 0;
1140
+ for (const l of listings) {
1141
+ statusCounts[l.orderStatus] = (statusCounts[l.orderStatus] || 0) + 1;
1142
+ if (l.expirationDate <= now) expiredCount++;
1143
+ }
1144
+ console.log(tag, `order statuses:`, statusCounts, `expired: ${expiredCount}`);
1096
1145
  listings = listings.filter(
1097
- (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
1146
+ (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > now || includeExpired && l.orderStatus === 1 /* EXPIRED */
1098
1147
  );
1148
+ console.log(tag, `after status filter: ${listings.length} (OPEN${includeExpired ? " + EXPIRED" : ""})`);
1099
1149
  if (listings.length === 0) {
1100
1150
  return [];
1101
1151
  }
1102
- const tokenIds = listings.map((l) => l.tokenId);
1152
+ const openListings = listings.filter((l) => l.orderStatus === 2 /* OPEN */);
1153
+ const expiredListings = includeExpired ? listings.filter((l) => l.orderStatus === 1 /* EXPIRED */) : [];
1154
+ const tokenIds = openListings.map((l) => l.tokenId);
1103
1155
  const owners = await bulkFetchNftOwners(this.client, nftAddress, tokenIds);
1104
- listings = listings.filter((listing, index) => {
1156
+ const beforeOwnership = openListings.length;
1157
+ const validOpenListings = openListings.filter((listing, index) => {
1105
1158
  const owner = owners[index];
1106
1159
  return isListingValid(
1107
1160
  listing.orderStatus,
@@ -1110,7 +1163,16 @@ var BazaarClient = class {
1110
1163
  owner
1111
1164
  );
1112
1165
  });
1113
- return sortListingsByPrice(getBestListingPerToken(listings));
1166
+ console.log(tag, `after ownership filter: ${validOpenListings.length}/${beforeOwnership} (${beforeOwnership - validOpenListings.length} dropped)`);
1167
+ const dedupedOpen = sortListingsByPrice(getBestListingPerToken(validOpenListings));
1168
+ const activeTokenKeys = new Set(dedupedOpen.map((l) => `${l.nftAddress.toLowerCase()}-${l.tokenId}`));
1169
+ const uniqueExpired = getBestListingPerToken(
1170
+ expiredListings.filter((l) => !activeTokenKeys.has(`${l.nftAddress.toLowerCase()}-${l.tokenId}`))
1171
+ );
1172
+ const sortedExpired = sortListingsByPrice(uniqueExpired);
1173
+ const result = [...dedupedOpen, ...sortedExpired];
1174
+ console.log(tag, `final: ${result.length} listings (${dedupedOpen.length} open, ${sortedExpired.length} expired)`);
1175
+ return result;
1114
1176
  }
1115
1177
  /**
1116
1178
  * Get valid collection offers for a collection
@@ -1125,10 +1187,6 @@ var BazaarClient = class {
1125
1187
  async getCollectionOffers(options) {
1126
1188
  const { nftAddress, excludeMaker, maxMessages = 100 } = options;
1127
1189
  const collectionOffersAddress = getCollectionOffersAddress(this.chainId);
1128
- const weth = getWrappedNativeCurrency(this.chainId);
1129
- if (!weth) {
1130
- return [];
1131
- }
1132
1190
  const count = await this.netClient.getMessageCount({
1133
1191
  filter: {
1134
1192
  appAddress: collectionOffersAddress,
@@ -1147,6 +1205,21 @@ var BazaarClient = class {
1147
1205
  startIndex,
1148
1206
  endIndex: count
1149
1207
  });
1208
+ return this.processCollectionOffersFromMessages(messages, options);
1209
+ }
1210
+ /**
1211
+ * Process pre-fetched messages into valid collection offers.
1212
+ *
1213
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
1214
+ * to avoid redundant RPC calls.
1215
+ */
1216
+ async processCollectionOffersFromMessages(messages, options) {
1217
+ const { nftAddress, excludeMaker } = options;
1218
+ const tag = `[BazaarClient.processCollectionOffers chain=${this.chainId}]`;
1219
+ const weth = getWrappedNativeCurrency(this.chainId);
1220
+ if (!weth) {
1221
+ return [];
1222
+ }
1150
1223
  let offers = [];
1151
1224
  for (const message of messages) {
1152
1225
  const offer = parseCollectionOfferFromMessage(message, this.chainId);
@@ -1161,6 +1234,7 @@ var BazaarClient = class {
1161
1234
  }
1162
1235
  offers.push(offer);
1163
1236
  }
1237
+ console.log(tag, `parsed ${offers.length}/${messages.length} messages into offers`);
1164
1238
  if (offers.length === 0) {
1165
1239
  return [];
1166
1240
  }
@@ -1175,9 +1249,11 @@ var BazaarClient = class {
1175
1249
  const statusInfo = statusInfos[index];
1176
1250
  offer.orderStatus = getOrderStatusFromInfo(offer.orderComponents, statusInfo);
1177
1251
  });
1252
+ const now = Math.floor(Date.now() / 1e3);
1178
1253
  offers = offers.filter(
1179
- (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > Math.floor(Date.now() / 1e3)
1254
+ (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > now
1180
1255
  );
1256
+ console.log(tag, `after status filter: ${offers.length} OPEN & not expired`);
1181
1257
  if (offers.length === 0) {
1182
1258
  return [];
1183
1259
  }
@@ -1187,6 +1263,7 @@ var BazaarClient = class {
1187
1263
  uniqueMakers.forEach((maker, index) => {
1188
1264
  balanceMap.set(maker.toLowerCase(), balances[index]);
1189
1265
  });
1266
+ const beforeBalance = offers.length;
1190
1267
  offers = offers.filter((offer) => {
1191
1268
  const balance = balanceMap.get(offer.maker.toLowerCase()) || BigInt(0);
1192
1269
  return isCollectionOfferValid(
@@ -1196,6 +1273,7 @@ var BazaarClient = class {
1196
1273
  balance
1197
1274
  );
1198
1275
  });
1276
+ console.log(tag, `after balance filter: ${offers.length}/${beforeBalance} (${beforeBalance - offers.length} dropped)`);
1199
1277
  return sortOffersByPrice(offers);
1200
1278
  }
1201
1279
  /**
@@ -1213,8 +1291,7 @@ var BazaarClient = class {
1213
1291
  async getErc20Offers(options) {
1214
1292
  const { tokenAddress, excludeMaker, maxMessages = 200 } = options;
1215
1293
  const erc20OffersAddress = getErc20OffersAddress(this.chainId);
1216
- const weth = getWrappedNativeCurrency(this.chainId);
1217
- if (!erc20OffersAddress || !weth) {
1294
+ if (!erc20OffersAddress) {
1218
1295
  return [];
1219
1296
  }
1220
1297
  const count = await this.netClient.getMessageCount({
@@ -1235,6 +1312,21 @@ var BazaarClient = class {
1235
1312
  startIndex,
1236
1313
  endIndex: count
1237
1314
  });
1315
+ return this.processErc20OffersFromMessages(messages, options);
1316
+ }
1317
+ /**
1318
+ * Process pre-fetched messages into valid ERC20 offers.
1319
+ *
1320
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
1321
+ * to avoid redundant RPC calls.
1322
+ */
1323
+ async processErc20OffersFromMessages(messages, options) {
1324
+ const { tokenAddress, excludeMaker } = options;
1325
+ const tag = `[BazaarClient.processErc20Offers chain=${this.chainId}]`;
1326
+ const weth = getWrappedNativeCurrency(this.chainId);
1327
+ if (!weth) {
1328
+ return [];
1329
+ }
1238
1330
  let offers = [];
1239
1331
  for (const message of messages) {
1240
1332
  const offer = parseErc20OfferFromMessage(message, this.chainId);
@@ -1252,6 +1344,7 @@ var BazaarClient = class {
1252
1344
  }
1253
1345
  offers.push(offer);
1254
1346
  }
1347
+ console.log(tag, `parsed ${offers.length}/${messages.length} messages into offers`);
1255
1348
  if (offers.length === 0) {
1256
1349
  return [];
1257
1350
  }
@@ -1266,9 +1359,11 @@ var BazaarClient = class {
1266
1359
  const statusInfo = statusInfos[index];
1267
1360
  offer.orderStatus = getOrderStatusFromInfo(offer.orderComponents, statusInfo);
1268
1361
  });
1362
+ const now = Math.floor(Date.now() / 1e3);
1269
1363
  offers = offers.filter(
1270
- (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > Math.floor(Date.now() / 1e3)
1364
+ (o) => o.orderStatus === 2 /* OPEN */ && o.expirationDate > now
1271
1365
  );
1366
+ console.log(tag, `after status filter: ${offers.length} OPEN & not expired`);
1272
1367
  if (offers.length === 0) {
1273
1368
  return [];
1274
1369
  }
@@ -1278,6 +1373,7 @@ var BazaarClient = class {
1278
1373
  uniqueMakers.forEach((maker, index) => {
1279
1374
  balanceMap.set(maker.toLowerCase(), balances[index]);
1280
1375
  });
1376
+ const beforeBalance = offers.length;
1281
1377
  offers = offers.filter((offer) => {
1282
1378
  const balance = balanceMap.get(offer.maker.toLowerCase()) || BigInt(0);
1283
1379
  return isErc20OfferValid(
@@ -1287,6 +1383,7 @@ var BazaarClient = class {
1287
1383
  balance
1288
1384
  );
1289
1385
  });
1386
+ console.log(tag, `after balance filter: ${offers.length}/${beforeBalance} (${beforeBalance - offers.length} dropped)`);
1290
1387
  return sortErc20OffersByPricePerToken(offers);
1291
1388
  }
1292
1389
  /**
@@ -1301,26 +1398,42 @@ var BazaarClient = class {
1301
1398
  * all valid listings are returned (grouped by maker in the UI).
1302
1399
  */
1303
1400
  async getErc20Listings(options) {
1304
- const { tokenAddress, excludeMaker, maxMessages = 200 } = options;
1401
+ const { tokenAddress, excludeMaker, maker, maxMessages = 200 } = options;
1305
1402
  const erc20BazaarAddress = getErc20BazaarAddress(this.chainId);
1306
- const count = await this.netClient.getMessageCount({
1307
- filter: {
1308
- appAddress: erc20BazaarAddress,
1309
- topic: tokenAddress.toLowerCase()
1403
+ const filter = {
1404
+ appAddress: erc20BazaarAddress,
1405
+ topic: tokenAddress.toLowerCase(),
1406
+ maker
1407
+ };
1408
+ let startIndex;
1409
+ let endIndex;
1410
+ if (options.startIndex != null && options.endIndex != null) {
1411
+ startIndex = options.startIndex;
1412
+ endIndex = options.endIndex;
1413
+ } else {
1414
+ const count = await this.netClient.getMessageCount({ filter });
1415
+ if (count === 0) {
1416
+ return [];
1310
1417
  }
1311
- });
1312
- if (count === 0) {
1313
- return [];
1418
+ startIndex = Math.max(0, count - maxMessages);
1419
+ endIndex = count;
1314
1420
  }
1315
- const startIndex = Math.max(0, count - maxMessages);
1316
1421
  const messages = await this.netClient.getMessages({
1317
- filter: {
1318
- appAddress: erc20BazaarAddress,
1319
- topic: tokenAddress.toLowerCase()
1320
- },
1422
+ filter,
1321
1423
  startIndex,
1322
- endIndex: count
1424
+ endIndex
1323
1425
  });
1426
+ return this.processErc20ListingsFromMessages(messages, options);
1427
+ }
1428
+ /**
1429
+ * Process pre-fetched messages into valid ERC20 listings.
1430
+ *
1431
+ * Use this when messages have already been fetched (e.g. via useNetMessages)
1432
+ * to avoid redundant RPC calls.
1433
+ */
1434
+ async processErc20ListingsFromMessages(messages, options) {
1435
+ const { tokenAddress, excludeMaker } = options;
1436
+ const tag = `[BazaarClient.processErc20Listings chain=${this.chainId}]`;
1324
1437
  let listings = [];
1325
1438
  for (const message of messages) {
1326
1439
  const listing = parseErc20ListingFromMessage(message, this.chainId);
@@ -1333,6 +1446,7 @@ var BazaarClient = class {
1333
1446
  }
1334
1447
  listings.push(listing);
1335
1448
  }
1449
+ console.log(tag, `parsed ${listings.length}/${messages.length} messages into listings`);
1336
1450
  if (listings.length === 0) {
1337
1451
  return [];
1338
1452
  }
@@ -1347,9 +1461,18 @@ var BazaarClient = class {
1347
1461
  const statusInfo = statusInfos[index];
1348
1462
  listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
1349
1463
  });
1464
+ const statusCounts = {};
1465
+ const now = Math.floor(Date.now() / 1e3);
1466
+ let expiredCount = 0;
1467
+ for (const l of listings) {
1468
+ statusCounts[l.orderStatus] = (statusCounts[l.orderStatus] || 0) + 1;
1469
+ if (l.expirationDate <= now) expiredCount++;
1470
+ }
1471
+ console.log(tag, `order statuses:`, statusCounts, `expired: ${expiredCount}`);
1350
1472
  listings = listings.filter(
1351
- (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
1473
+ (l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > now
1352
1474
  );
1475
+ console.log(tag, `after status filter: ${listings.length} OPEN & not expired`);
1353
1476
  if (listings.length === 0) {
1354
1477
  return [];
1355
1478
  }
@@ -1359,6 +1482,7 @@ var BazaarClient = class {
1359
1482
  uniqueMakers.forEach((maker, index) => {
1360
1483
  balanceMap.set(maker.toLowerCase(), balances[index]);
1361
1484
  });
1485
+ const beforeBalance = listings.length;
1362
1486
  listings = listings.filter((listing) => {
1363
1487
  const balance = balanceMap.get(listing.maker.toLowerCase()) || BigInt(0);
1364
1488
  return isErc20ListingValid(
@@ -1368,6 +1492,7 @@ var BazaarClient = class {
1368
1492
  balance
1369
1493
  );
1370
1494
  });
1495
+ console.log(tag, `after balance filter: ${listings.length}/${beforeBalance} (${beforeBalance - listings.length} dropped)`);
1371
1496
  return sortErc20ListingsByPricePerToken(listings);
1372
1497
  }
1373
1498
  /**
@@ -1497,6 +1622,7 @@ exports.ERC721_OWNER_OF_HELPER_ABI = ERC721_OWNER_OF_HELPER_ABI;
1497
1622
  exports.ERC721_OWNER_OF_HELPER_ADDRESS = ERC721_OWNER_OF_HELPER_ADDRESS;
1498
1623
  exports.ItemType = ItemType;
1499
1624
  exports.NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS;
1625
+ exports.NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS;
1500
1626
  exports.NET_SEAPORT_ZONE_ADDRESS = NET_SEAPORT_ZONE_ADDRESS;
1501
1627
  exports.OrderType = OrderType;
1502
1628
  exports.SEAPORT_CANCEL_ABI = SEAPORT_CANCEL_ABI;