@net-protocol/bazaar 0.1.5 → 0.1.7
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.d.mts +30 -3
- package/dist/index.d.ts +30 -3
- package/dist/index.js +198 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +197 -16
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +63 -5
- package/dist/react.d.ts +63 -5
- package/dist/react.js +306 -17
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +306 -18
- package/dist/react.mjs.map +1 -1
- package/dist/{types-CfGfQTJL.d.mts → types-5kMf461x.d.mts} +39 -3
- package/dist/{types-CfGfQTJL.d.ts → types-5kMf461x.d.ts} +39 -3
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { NetClient } from '@net-protocol/core';
|
|
|
3
3
|
import { Seaport } from '@opensea/seaport-js';
|
|
4
4
|
import { ethers } from 'ethers';
|
|
5
5
|
import { readContract } from 'viem/actions';
|
|
6
|
+
import { STORAGE_CONTRACT } from '@net-protocol/storage';
|
|
6
7
|
|
|
7
8
|
// src/client/BazaarClient.ts
|
|
8
9
|
|
|
@@ -789,8 +790,6 @@ function isErc20ListingValid(orderStatus, expirationDate, tokenAmount, sellerTok
|
|
|
789
790
|
}
|
|
790
791
|
return true;
|
|
791
792
|
}
|
|
792
|
-
|
|
793
|
-
// src/utils/parsing.ts
|
|
794
793
|
function parseListingFromMessage(message, chainId) {
|
|
795
794
|
try {
|
|
796
795
|
const submission = decodeSeaportSubmission(message.data);
|
|
@@ -1012,8 +1011,85 @@ function sortErc20ListingsByPricePerToken(listings) {
|
|
|
1012
1011
|
return 0;
|
|
1013
1012
|
});
|
|
1014
1013
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1014
|
+
var ZONE_STORED_SALE_ABI = [
|
|
1015
|
+
{ type: "uint256" },
|
|
1016
|
+
// timestamp
|
|
1017
|
+
{ type: "uint256" },
|
|
1018
|
+
// netTotalMessageLength
|
|
1019
|
+
{ type: "uint256" },
|
|
1020
|
+
// netTotalMessageForAppTopicLength
|
|
1021
|
+
{
|
|
1022
|
+
name: "zoneParameters",
|
|
1023
|
+
type: "tuple",
|
|
1024
|
+
internalType: "struct ZoneParameters",
|
|
1025
|
+
components: [
|
|
1026
|
+
{ name: "orderHash", type: "bytes32", internalType: "bytes32" },
|
|
1027
|
+
{ name: "fulfiller", type: "address", internalType: "address" },
|
|
1028
|
+
{ name: "offerer", type: "address", internalType: "address" },
|
|
1029
|
+
{
|
|
1030
|
+
name: "offer",
|
|
1031
|
+
type: "tuple[]",
|
|
1032
|
+
internalType: "struct SpentItem[]",
|
|
1033
|
+
components: [
|
|
1034
|
+
{ name: "itemType", type: "uint8", internalType: "enum ItemType" },
|
|
1035
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
1036
|
+
{ name: "identifier", type: "uint256", internalType: "uint256" },
|
|
1037
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
1038
|
+
]
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
name: "consideration",
|
|
1042
|
+
type: "tuple[]",
|
|
1043
|
+
internalType: "struct ReceivedItem[]",
|
|
1044
|
+
components: [
|
|
1045
|
+
{ name: "itemType", type: "uint8", internalType: "enum ItemType" },
|
|
1046
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
1047
|
+
{ name: "identifier", type: "uint256", internalType: "uint256" },
|
|
1048
|
+
{ name: "amount", type: "uint256", internalType: "uint256" },
|
|
1049
|
+
{ name: "recipient", type: "address", internalType: "address payable" }
|
|
1050
|
+
]
|
|
1051
|
+
},
|
|
1052
|
+
{ name: "extraData", type: "bytes", internalType: "bytes" },
|
|
1053
|
+
{ name: "orderHashes", type: "bytes32[]", internalType: "bytes32[]" },
|
|
1054
|
+
{ name: "startTime", type: "uint256", internalType: "uint256" },
|
|
1055
|
+
{ name: "endTime", type: "uint256", internalType: "uint256" },
|
|
1056
|
+
{ name: "zoneHash", type: "bytes32", internalType: "bytes32" }
|
|
1057
|
+
]
|
|
1058
|
+
}
|
|
1059
|
+
];
|
|
1060
|
+
function parseSaleFromStoredData(storedData, chainId) {
|
|
1061
|
+
try {
|
|
1062
|
+
const cleanedData = "0x" + (storedData.startsWith("0x") ? storedData.slice(2) : storedData);
|
|
1063
|
+
const [timestamp, , , zoneParameters] = decodeAbiParameters(
|
|
1064
|
+
ZONE_STORED_SALE_ABI,
|
|
1065
|
+
cleanedData
|
|
1066
|
+
);
|
|
1067
|
+
const offerItem = zoneParameters.offer[0];
|
|
1068
|
+
if (!offerItem) return null;
|
|
1069
|
+
const totalConsideration = zoneParameters.consideration.reduce(
|
|
1070
|
+
(acc, item) => acc + item.amount,
|
|
1071
|
+
BigInt(0)
|
|
1072
|
+
);
|
|
1073
|
+
return {
|
|
1074
|
+
seller: zoneParameters.offerer,
|
|
1075
|
+
buyer: zoneParameters.fulfiller,
|
|
1076
|
+
tokenAddress: offerItem.token,
|
|
1077
|
+
tokenId: offerItem.identifier.toString(),
|
|
1078
|
+
amount: offerItem.amount,
|
|
1079
|
+
itemType: offerItem.itemType,
|
|
1080
|
+
priceWei: totalConsideration,
|
|
1081
|
+
price: parseFloat(formatEther(totalConsideration)),
|
|
1082
|
+
currency: getCurrencySymbol(chainId),
|
|
1083
|
+
timestamp: Number(timestamp),
|
|
1084
|
+
orderHash: zoneParameters.orderHash
|
|
1085
|
+
};
|
|
1086
|
+
} catch {
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
function sortSalesByTimestamp(sales) {
|
|
1091
|
+
return [...sales].sort((a, b) => b.timestamp - a.timestamp);
|
|
1092
|
+
}
|
|
1017
1093
|
var CHAIN_RPC_URLS = {
|
|
1018
1094
|
8453: ["https://base-mainnet.public.blastapi.io", "https://mainnet.base.org"],
|
|
1019
1095
|
84532: ["https://sepolia.base.org"],
|
|
@@ -1076,7 +1152,7 @@ var BazaarClient = class {
|
|
|
1076
1152
|
const bazaarAddress = getBazaarAddress(this.chainId);
|
|
1077
1153
|
const filter = {
|
|
1078
1154
|
appAddress: bazaarAddress,
|
|
1079
|
-
topic: nftAddress
|
|
1155
|
+
topic: nftAddress?.toLowerCase(),
|
|
1080
1156
|
maker
|
|
1081
1157
|
};
|
|
1082
1158
|
let startIndex;
|
|
@@ -1149,18 +1225,57 @@ var BazaarClient = class {
|
|
|
1149
1225
|
}
|
|
1150
1226
|
const openListings = listings.filter((l) => l.orderStatus === 2 /* OPEN */);
|
|
1151
1227
|
const expiredListings = includeExpired ? listings.filter((l) => l.orderStatus === 1 /* EXPIRED */) : [];
|
|
1152
|
-
|
|
1153
|
-
const owners = await bulkFetchNftOwners(this.client, nftAddress, tokenIds);
|
|
1228
|
+
let validOpenListings;
|
|
1154
1229
|
const beforeOwnership = openListings.length;
|
|
1155
|
-
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1230
|
+
if (nftAddress) {
|
|
1231
|
+
const tokenIds = openListings.map((l) => l.tokenId);
|
|
1232
|
+
const owners = await bulkFetchNftOwners(this.client, nftAddress, tokenIds);
|
|
1233
|
+
validOpenListings = openListings.filter((listing, index) => {
|
|
1234
|
+
const owner = owners[index];
|
|
1235
|
+
return isListingValid(
|
|
1236
|
+
listing.orderStatus,
|
|
1237
|
+
listing.expirationDate,
|
|
1238
|
+
listing.maker,
|
|
1239
|
+
owner
|
|
1240
|
+
);
|
|
1241
|
+
});
|
|
1242
|
+
} else {
|
|
1243
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1244
|
+
for (const listing of openListings) {
|
|
1245
|
+
const key = listing.nftAddress.toLowerCase();
|
|
1246
|
+
const group = groups.get(key);
|
|
1247
|
+
if (group) {
|
|
1248
|
+
group.push(listing);
|
|
1249
|
+
} else {
|
|
1250
|
+
groups.set(key, [listing]);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
const groupEntries = Array.from(groups.entries());
|
|
1254
|
+
const ownerResults = await Promise.all(
|
|
1255
|
+
groupEntries.map(
|
|
1256
|
+
([addr, groupListings]) => bulkFetchNftOwners(
|
|
1257
|
+
this.client,
|
|
1258
|
+
addr,
|
|
1259
|
+
groupListings.map((l) => l.tokenId)
|
|
1260
|
+
)
|
|
1261
|
+
)
|
|
1162
1262
|
);
|
|
1163
|
-
|
|
1263
|
+
validOpenListings = [];
|
|
1264
|
+
groupEntries.forEach(([, groupListings], groupIndex) => {
|
|
1265
|
+
const owners = ownerResults[groupIndex];
|
|
1266
|
+
for (let i = 0; i < groupListings.length; i++) {
|
|
1267
|
+
const listing = groupListings[i];
|
|
1268
|
+
if (isListingValid(
|
|
1269
|
+
listing.orderStatus,
|
|
1270
|
+
listing.expirationDate,
|
|
1271
|
+
listing.maker,
|
|
1272
|
+
owners[i]
|
|
1273
|
+
)) {
|
|
1274
|
+
validOpenListings.push(listing);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1164
1279
|
console.log(tag, `after ownership filter: ${validOpenListings.length}/${beforeOwnership} (${beforeOwnership - validOpenListings.length} dropped)`);
|
|
1165
1280
|
const dedupedOpen = sortListingsByPrice(getBestListingPerToken(validOpenListings));
|
|
1166
1281
|
const activeTokenKeys = new Set(dedupedOpen.map((l) => `${l.nftAddress.toLowerCase()}-${l.tokenId}`));
|
|
@@ -1493,6 +1608,72 @@ var BazaarClient = class {
|
|
|
1493
1608
|
console.log(tag, `after balance filter: ${listings.length}/${beforeBalance} (${beforeBalance - listings.length} dropped)`);
|
|
1494
1609
|
return sortErc20ListingsByPricePerToken(listings);
|
|
1495
1610
|
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Get recent sales for a collection
|
|
1613
|
+
*
|
|
1614
|
+
* Sales are stored differently from listings: Net messages contain order hashes,
|
|
1615
|
+
* and the actual sale data is fetched from the bulk storage contract.
|
|
1616
|
+
*
|
|
1617
|
+
* Results are sorted by timestamp (most recent first)
|
|
1618
|
+
*/
|
|
1619
|
+
async getSales(options) {
|
|
1620
|
+
const { nftAddress, maxMessages = 100 } = options;
|
|
1621
|
+
const filter = {
|
|
1622
|
+
appAddress: NET_SEAPORT_ZONE_ADDRESS,
|
|
1623
|
+
topic: nftAddress.toLowerCase()
|
|
1624
|
+
};
|
|
1625
|
+
const count = await this.netClient.getMessageCount({ filter });
|
|
1626
|
+
if (count === 0) {
|
|
1627
|
+
return [];
|
|
1628
|
+
}
|
|
1629
|
+
const startIndex = Math.max(0, count - maxMessages);
|
|
1630
|
+
const messages = await this.netClient.getMessages({
|
|
1631
|
+
filter,
|
|
1632
|
+
startIndex,
|
|
1633
|
+
endIndex: count
|
|
1634
|
+
});
|
|
1635
|
+
return this.processSalesFromMessages(messages, options);
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Process pre-fetched messages into sales.
|
|
1639
|
+
*
|
|
1640
|
+
* Each message's data field contains an order hash. The actual sale data
|
|
1641
|
+
* is fetched from the bulk storage contract using these order hashes.
|
|
1642
|
+
*/
|
|
1643
|
+
async processSalesFromMessages(messages, options) {
|
|
1644
|
+
const tag = `[BazaarClient.processSales chain=${this.chainId}]`;
|
|
1645
|
+
if (messages.length === 0) {
|
|
1646
|
+
return [];
|
|
1647
|
+
}
|
|
1648
|
+
const orderHashes = messages.map((m) => m.data);
|
|
1649
|
+
console.log(tag, `fetching ${orderHashes.length} sale details from storage...`);
|
|
1650
|
+
const bulkKeys = orderHashes.map((hash) => ({
|
|
1651
|
+
key: hash,
|
|
1652
|
+
operator: NET_SEAPORT_ZONE_ADDRESS
|
|
1653
|
+
}));
|
|
1654
|
+
let storedResults;
|
|
1655
|
+
try {
|
|
1656
|
+
storedResults = await this.client.readContract({
|
|
1657
|
+
abi: STORAGE_CONTRACT.abi,
|
|
1658
|
+
address: STORAGE_CONTRACT.address,
|
|
1659
|
+
functionName: "bulkGet",
|
|
1660
|
+
args: [bulkKeys]
|
|
1661
|
+
});
|
|
1662
|
+
} catch (err) {
|
|
1663
|
+
console.error(tag, "bulk storage fetch failed:", err);
|
|
1664
|
+
return [];
|
|
1665
|
+
}
|
|
1666
|
+
const sales = [];
|
|
1667
|
+
for (const result of storedResults) {
|
|
1668
|
+
if (!result.value || result.value === "0x") continue;
|
|
1669
|
+
const sale = parseSaleFromStoredData(result.value, this.chainId);
|
|
1670
|
+
if (sale) {
|
|
1671
|
+
sales.push(sale);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
console.log(tag, `parsed ${sales.length}/${storedResults.length} sales`);
|
|
1675
|
+
return sales;
|
|
1676
|
+
}
|
|
1496
1677
|
/**
|
|
1497
1678
|
* Get the chain ID this client is configured for
|
|
1498
1679
|
*/
|
|
@@ -1608,6 +1789,6 @@ var BazaarClient = class {
|
|
|
1608
1789
|
}
|
|
1609
1790
|
};
|
|
1610
1791
|
|
|
1611
|
-
export { BAZAAR_COLLECTION_OFFERS_ABI, BAZAAR_SUBMISSION_ABI, BAZAAR_V2_ABI, BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI, BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS, BazaarClient, ERC20_BULK_BALANCE_CHECKER_ABI, ERC20_BULK_BALANCE_CHECKER_ADDRESS, ERC721_OWNER_OF_HELPER_ABI, ERC721_OWNER_OF_HELPER_ADDRESS, ItemType, NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS, NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS, NET_SEAPORT_ZONE_ADDRESS, OrderType, SEAPORT_CANCEL_ABI, SeaportOrderStatus, bulkFetchErc20Balances, bulkFetchNftOwners, bulkFetchOrderStatuses, computeOrderHash, createBalanceMap, createOrderStatusMap, createOwnershipMap, createSeaportInstance, decodeSeaportSubmission, formatPrice, getBazaarAddress, getBazaarChainConfig, getBazaarSupportedChainIds, getBestCollectionOffer, getBestListingPerToken, getCollectionOffersAddress, getCurrencySymbol, getErc20BazaarAddress, getErc20OffersAddress, getFeeCollectorAddress, getHighEthAddress, getNftFeeBps, getOrderStatusFromInfo, getSeaportAddress, getSeaportOrderFromMessageData, getTotalConsiderationAmount, getWrappedNativeCurrency, isBazaarSupportedOnChain, isCollectionOfferValid, isErc20ListingValid, isErc20OfferValid, isListingValid, parseCollectionOfferFromMessage, parseErc20ListingFromMessage, parseErc20OfferFromMessage, parseListingFromMessage, sortErc20ListingsByPricePerToken, sortErc20OffersByPricePerToken, sortListingsByPrice, sortOffersByPrice };
|
|
1792
|
+
export { BAZAAR_COLLECTION_OFFERS_ABI, BAZAAR_SUBMISSION_ABI, BAZAAR_V2_ABI, BULK_SEAPORT_ORDER_STATUS_FETCHER_ABI, BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS, BazaarClient, ERC20_BULK_BALANCE_CHECKER_ABI, ERC20_BULK_BALANCE_CHECKER_ADDRESS, ERC721_OWNER_OF_HELPER_ABI, ERC721_OWNER_OF_HELPER_ADDRESS, ItemType, NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS, NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS, NET_SEAPORT_ZONE_ADDRESS, OrderType, SEAPORT_CANCEL_ABI, SeaportOrderStatus, bulkFetchErc20Balances, bulkFetchNftOwners, bulkFetchOrderStatuses, computeOrderHash, createBalanceMap, createOrderStatusMap, createOwnershipMap, createSeaportInstance, decodeSeaportSubmission, formatPrice, getBazaarAddress, getBazaarChainConfig, getBazaarSupportedChainIds, getBestCollectionOffer, getBestListingPerToken, getCollectionOffersAddress, getCurrencySymbol, getErc20BazaarAddress, getErc20OffersAddress, getFeeCollectorAddress, getHighEthAddress, getNftFeeBps, getOrderStatusFromInfo, getSeaportAddress, getSeaportOrderFromMessageData, getTotalConsiderationAmount, getWrappedNativeCurrency, isBazaarSupportedOnChain, isCollectionOfferValid, isErc20ListingValid, isErc20OfferValid, isListingValid, parseCollectionOfferFromMessage, parseErc20ListingFromMessage, parseErc20OfferFromMessage, parseListingFromMessage, parseSaleFromStoredData, sortErc20ListingsByPricePerToken, sortErc20OffersByPricePerToken, sortListingsByPrice, sortOffersByPrice, sortSalesByTimestamp };
|
|
1612
1793
|
//# sourceMappingURL=index.mjs.map
|
|
1613
1794
|
//# sourceMappingURL=index.mjs.map
|