@net-protocol/bazaar 0.1.4 → 0.1.6
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 +150 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +149 -7
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +61 -4
- package/dist/react.d.ts +61 -4
- package/dist/react.js +258 -8
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +258 -9
- package/dist/react.mjs.map +1 -1
- package/dist/{types-DDHh9yJB.d.mts → types-BwfAmxpu.d.mts} +39 -3
- package/dist/{types-DDHh9yJB.d.ts → types-BwfAmxpu.d.ts} +39 -3
- package/package.json +2 -1
package/dist/react.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { NetClient } from '@net-protocol/core';
|
|
|
6
6
|
import { Seaport } from '@opensea/seaport-js';
|
|
7
7
|
import { ethers } from 'ethers';
|
|
8
8
|
import { readContract } from 'viem/actions';
|
|
9
|
+
import { STORAGE_CONTRACT } from '@net-protocol/storage';
|
|
9
10
|
|
|
10
11
|
// src/hooks/useBazaarListings.ts
|
|
11
12
|
|
|
@@ -183,6 +184,7 @@ var DEFAULT_NFT_FEE_BPS = 500;
|
|
|
183
184
|
var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
|
|
184
185
|
var ERC721_OWNER_OF_HELPER_ADDRESS = "0x00000012E3eb0700925947fAF9cd1440319b4F37";
|
|
185
186
|
var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000B50A9f2923F2DB931391824F6D1278f712";
|
|
187
|
+
var NET_SEAPORT_ZONE_ADDRESS = "0x000000007F8c58fbf215bF91Bda7421A806cf3ae";
|
|
186
188
|
var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
|
|
187
189
|
var NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = "0x000000bC63761cbb05305632212e2f3AE2BE7a9B";
|
|
188
190
|
var BAZAAR_CHAIN_CONFIGS = {
|
|
@@ -579,8 +581,6 @@ function isErc20ListingValid(orderStatus, expirationDate, tokenAmount, sellerTok
|
|
|
579
581
|
}
|
|
580
582
|
return true;
|
|
581
583
|
}
|
|
582
|
-
|
|
583
|
-
// src/utils/parsing.ts
|
|
584
584
|
function parseListingFromMessage(message, chainId) {
|
|
585
585
|
try {
|
|
586
586
|
const submission = decodeSeaportSubmission(message.data);
|
|
@@ -794,8 +794,82 @@ function sortErc20ListingsByPricePerToken(listings) {
|
|
|
794
794
|
return 0;
|
|
795
795
|
});
|
|
796
796
|
}
|
|
797
|
-
|
|
798
|
-
|
|
797
|
+
var ZONE_STORED_SALE_ABI = [
|
|
798
|
+
{ type: "uint256" },
|
|
799
|
+
// timestamp
|
|
800
|
+
{ type: "uint256" },
|
|
801
|
+
// netTotalMessageLength
|
|
802
|
+
{ type: "uint256" },
|
|
803
|
+
// netTotalMessageForAppTopicLength
|
|
804
|
+
{
|
|
805
|
+
name: "zoneParameters",
|
|
806
|
+
type: "tuple",
|
|
807
|
+
internalType: "struct ZoneParameters",
|
|
808
|
+
components: [
|
|
809
|
+
{ name: "orderHash", type: "bytes32", internalType: "bytes32" },
|
|
810
|
+
{ name: "fulfiller", type: "address", internalType: "address" },
|
|
811
|
+
{ name: "offerer", type: "address", internalType: "address" },
|
|
812
|
+
{
|
|
813
|
+
name: "offer",
|
|
814
|
+
type: "tuple[]",
|
|
815
|
+
internalType: "struct SpentItem[]",
|
|
816
|
+
components: [
|
|
817
|
+
{ name: "itemType", type: "uint8", internalType: "enum ItemType" },
|
|
818
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
819
|
+
{ name: "identifier", type: "uint256", internalType: "uint256" },
|
|
820
|
+
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
821
|
+
]
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
name: "consideration",
|
|
825
|
+
type: "tuple[]",
|
|
826
|
+
internalType: "struct ReceivedItem[]",
|
|
827
|
+
components: [
|
|
828
|
+
{ name: "itemType", type: "uint8", internalType: "enum ItemType" },
|
|
829
|
+
{ name: "token", type: "address", internalType: "address" },
|
|
830
|
+
{ name: "identifier", type: "uint256", internalType: "uint256" },
|
|
831
|
+
{ name: "amount", type: "uint256", internalType: "uint256" },
|
|
832
|
+
{ name: "recipient", type: "address", internalType: "address payable" }
|
|
833
|
+
]
|
|
834
|
+
},
|
|
835
|
+
{ name: "extraData", type: "bytes", internalType: "bytes" },
|
|
836
|
+
{ name: "orderHashes", type: "bytes32[]", internalType: "bytes32[]" },
|
|
837
|
+
{ name: "startTime", type: "uint256", internalType: "uint256" },
|
|
838
|
+
{ name: "endTime", type: "uint256", internalType: "uint256" },
|
|
839
|
+
{ name: "zoneHash", type: "bytes32", internalType: "bytes32" }
|
|
840
|
+
]
|
|
841
|
+
}
|
|
842
|
+
];
|
|
843
|
+
function parseSaleFromStoredData(storedData, chainId) {
|
|
844
|
+
try {
|
|
845
|
+
const cleanedData = "0x" + (storedData.startsWith("0x") ? storedData.slice(2) : storedData);
|
|
846
|
+
const [timestamp, , , zoneParameters] = decodeAbiParameters(
|
|
847
|
+
ZONE_STORED_SALE_ABI,
|
|
848
|
+
cleanedData
|
|
849
|
+
);
|
|
850
|
+
const offerItem = zoneParameters.offer[0];
|
|
851
|
+
if (!offerItem) return null;
|
|
852
|
+
const totalConsideration = zoneParameters.consideration.reduce(
|
|
853
|
+
(acc, item) => acc + item.amount,
|
|
854
|
+
BigInt(0)
|
|
855
|
+
);
|
|
856
|
+
return {
|
|
857
|
+
seller: zoneParameters.offerer,
|
|
858
|
+
buyer: zoneParameters.fulfiller,
|
|
859
|
+
tokenAddress: offerItem.token,
|
|
860
|
+
tokenId: offerItem.identifier.toString(),
|
|
861
|
+
amount: offerItem.amount,
|
|
862
|
+
itemType: offerItem.itemType,
|
|
863
|
+
priceWei: totalConsideration,
|
|
864
|
+
price: parseFloat(formatEther(totalConsideration)),
|
|
865
|
+
currency: getCurrencySymbol(chainId),
|
|
866
|
+
timestamp: Number(timestamp),
|
|
867
|
+
orderHash: zoneParameters.orderHash
|
|
868
|
+
};
|
|
869
|
+
} catch {
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
799
873
|
var CHAIN_RPC_URLS = {
|
|
800
874
|
8453: ["https://base-mainnet.public.blastapi.io", "https://mainnet.base.org"],
|
|
801
875
|
84532: ["https://sepolia.base.org"],
|
|
@@ -970,7 +1044,7 @@ var BazaarClient = class {
|
|
|
970
1044
|
const count = await this.netClient.getMessageCount({
|
|
971
1045
|
filter: {
|
|
972
1046
|
appAddress: collectionOffersAddress,
|
|
973
|
-
topic: nftAddress
|
|
1047
|
+
topic: nftAddress?.toLowerCase()
|
|
974
1048
|
}
|
|
975
1049
|
});
|
|
976
1050
|
if (count === 0) {
|
|
@@ -980,7 +1054,7 @@ var BazaarClient = class {
|
|
|
980
1054
|
const messages = await this.netClient.getMessages({
|
|
981
1055
|
filter: {
|
|
982
1056
|
appAddress: collectionOffersAddress,
|
|
983
|
-
topic: nftAddress
|
|
1057
|
+
topic: nftAddress?.toLowerCase()
|
|
984
1058
|
},
|
|
985
1059
|
startIndex,
|
|
986
1060
|
endIndex: count
|
|
@@ -1275,6 +1349,72 @@ var BazaarClient = class {
|
|
|
1275
1349
|
console.log(tag, `after balance filter: ${listings.length}/${beforeBalance} (${beforeBalance - listings.length} dropped)`);
|
|
1276
1350
|
return sortErc20ListingsByPricePerToken(listings);
|
|
1277
1351
|
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Get recent sales for a collection
|
|
1354
|
+
*
|
|
1355
|
+
* Sales are stored differently from listings: Net messages contain order hashes,
|
|
1356
|
+
* and the actual sale data is fetched from the bulk storage contract.
|
|
1357
|
+
*
|
|
1358
|
+
* Results are sorted by timestamp (most recent first)
|
|
1359
|
+
*/
|
|
1360
|
+
async getSales(options) {
|
|
1361
|
+
const { nftAddress, maxMessages = 100 } = options;
|
|
1362
|
+
const filter = {
|
|
1363
|
+
appAddress: NET_SEAPORT_ZONE_ADDRESS,
|
|
1364
|
+
topic: nftAddress.toLowerCase()
|
|
1365
|
+
};
|
|
1366
|
+
const count = await this.netClient.getMessageCount({ filter });
|
|
1367
|
+
if (count === 0) {
|
|
1368
|
+
return [];
|
|
1369
|
+
}
|
|
1370
|
+
const startIndex = Math.max(0, count - maxMessages);
|
|
1371
|
+
const messages = await this.netClient.getMessages({
|
|
1372
|
+
filter,
|
|
1373
|
+
startIndex,
|
|
1374
|
+
endIndex: count
|
|
1375
|
+
});
|
|
1376
|
+
return this.processSalesFromMessages(messages, options);
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Process pre-fetched messages into sales.
|
|
1380
|
+
*
|
|
1381
|
+
* Each message's data field contains an order hash. The actual sale data
|
|
1382
|
+
* is fetched from the bulk storage contract using these order hashes.
|
|
1383
|
+
*/
|
|
1384
|
+
async processSalesFromMessages(messages, options) {
|
|
1385
|
+
const tag = `[BazaarClient.processSales chain=${this.chainId}]`;
|
|
1386
|
+
if (messages.length === 0) {
|
|
1387
|
+
return [];
|
|
1388
|
+
}
|
|
1389
|
+
const orderHashes = messages.map((m) => m.data);
|
|
1390
|
+
console.log(tag, `fetching ${orderHashes.length} sale details from storage...`);
|
|
1391
|
+
const bulkKeys = orderHashes.map((hash) => ({
|
|
1392
|
+
key: hash,
|
|
1393
|
+
operator: NET_SEAPORT_ZONE_ADDRESS
|
|
1394
|
+
}));
|
|
1395
|
+
let storedResults;
|
|
1396
|
+
try {
|
|
1397
|
+
storedResults = await this.client.readContract({
|
|
1398
|
+
abi: STORAGE_CONTRACT.abi,
|
|
1399
|
+
address: STORAGE_CONTRACT.address,
|
|
1400
|
+
functionName: "bulkGet",
|
|
1401
|
+
args: [bulkKeys]
|
|
1402
|
+
});
|
|
1403
|
+
} catch (err) {
|
|
1404
|
+
console.error(tag, "bulk storage fetch failed:", err);
|
|
1405
|
+
return [];
|
|
1406
|
+
}
|
|
1407
|
+
const sales = [];
|
|
1408
|
+
for (const result of storedResults) {
|
|
1409
|
+
if (!result.value || result.value === "0x") continue;
|
|
1410
|
+
const sale = parseSaleFromStoredData(result.value, this.chainId);
|
|
1411
|
+
if (sale) {
|
|
1412
|
+
sales.push(sale);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
console.log(tag, `parsed ${sales.length}/${storedResults.length} sales`);
|
|
1416
|
+
return sales;
|
|
1417
|
+
}
|
|
1278
1418
|
/**
|
|
1279
1419
|
* Get the chain ID this client is configured for
|
|
1280
1420
|
*/
|
|
@@ -1535,7 +1675,7 @@ function useBazaarCollectionOffers({
|
|
|
1535
1675
|
const filter = useMemo(
|
|
1536
1676
|
() => ({
|
|
1537
1677
|
appAddress: collectionOffersAddress,
|
|
1538
|
-
topic: nftAddress
|
|
1678
|
+
topic: nftAddress?.toLowerCase()
|
|
1539
1679
|
}),
|
|
1540
1680
|
[collectionOffersAddress, nftAddress]
|
|
1541
1681
|
);
|
|
@@ -1560,7 +1700,7 @@ function useBazaarCollectionOffers({
|
|
|
1560
1700
|
endIndex: totalCount,
|
|
1561
1701
|
enabled: enabled && isSupported && totalCount > 0
|
|
1562
1702
|
});
|
|
1563
|
-
const TAG = `[useBazaarCollectionOffers chain=${chainId} nft=${nftAddress.slice(0, 10)}]`;
|
|
1703
|
+
const TAG = `[useBazaarCollectionOffers chain=${chainId}${nftAddress ? ` nft=${nftAddress.slice(0, 10)}` : ""}]`;
|
|
1564
1704
|
useEffect(() => {
|
|
1565
1705
|
console.log(TAG, {
|
|
1566
1706
|
enabled,
|
|
@@ -1861,7 +2001,116 @@ function useBazaarErc20Listings({
|
|
|
1861
2001
|
refetch
|
|
1862
2002
|
};
|
|
1863
2003
|
}
|
|
2004
|
+
function useBazaarSales({
|
|
2005
|
+
chainId,
|
|
2006
|
+
nftAddress,
|
|
2007
|
+
maxMessages = 100,
|
|
2008
|
+
enabled = true
|
|
2009
|
+
}) {
|
|
2010
|
+
const wagmiClient = usePublicClient({ chainId });
|
|
2011
|
+
const [sales, setSales] = useState([]);
|
|
2012
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
2013
|
+
const [processingError, setProcessingError] = useState();
|
|
2014
|
+
const [refetchTrigger, setRefetchTrigger] = useState(0);
|
|
2015
|
+
const isSupported = useMemo(
|
|
2016
|
+
() => isBazaarSupportedOnChain(chainId),
|
|
2017
|
+
[chainId]
|
|
2018
|
+
);
|
|
2019
|
+
const filter = useMemo(
|
|
2020
|
+
() => ({
|
|
2021
|
+
appAddress: NET_SEAPORT_ZONE_ADDRESS,
|
|
2022
|
+
topic: nftAddress.toLowerCase()
|
|
2023
|
+
}),
|
|
2024
|
+
[nftAddress]
|
|
2025
|
+
);
|
|
2026
|
+
const { count: totalCount, isLoading: isLoadingCount } = useNetMessageCount({
|
|
2027
|
+
chainId,
|
|
2028
|
+
filter,
|
|
2029
|
+
enabled: enabled && isSupported
|
|
2030
|
+
});
|
|
2031
|
+
const startIndex = useMemo(
|
|
2032
|
+
() => Math.max(0, totalCount - maxMessages),
|
|
2033
|
+
[totalCount, maxMessages]
|
|
2034
|
+
);
|
|
2035
|
+
const {
|
|
2036
|
+
messages,
|
|
2037
|
+
isLoading: isLoadingMessages,
|
|
2038
|
+
error: messagesError,
|
|
2039
|
+
refetch: refetchMessages
|
|
2040
|
+
} = useNetMessages({
|
|
2041
|
+
chainId,
|
|
2042
|
+
filter,
|
|
2043
|
+
startIndex,
|
|
2044
|
+
endIndex: totalCount,
|
|
2045
|
+
enabled: enabled && isSupported && totalCount > 0
|
|
2046
|
+
});
|
|
2047
|
+
const TAG = `[useBazaarSales chain=${chainId} nft=${nftAddress.slice(0, 10)}]`;
|
|
2048
|
+
useEffect(() => {
|
|
2049
|
+
console.log(TAG, {
|
|
2050
|
+
enabled,
|
|
2051
|
+
isSupported,
|
|
2052
|
+
totalCount,
|
|
2053
|
+
isLoadingCount,
|
|
2054
|
+
startIndex,
|
|
2055
|
+
endIndex: totalCount,
|
|
2056
|
+
messagesLength: messages?.length ?? 0,
|
|
2057
|
+
isLoadingMessages,
|
|
2058
|
+
messagesError: messagesError?.message
|
|
2059
|
+
});
|
|
2060
|
+
}, [enabled, isSupported, totalCount, isLoadingCount, startIndex, messages?.length, isLoadingMessages, messagesError]);
|
|
2061
|
+
useEffect(() => {
|
|
2062
|
+
if (!isSupported || !enabled) {
|
|
2063
|
+
setSales([]);
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
if (!messages || messages.length === 0) {
|
|
2067
|
+
setSales([]);
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
let cancelled = false;
|
|
2071
|
+
async function processSales() {
|
|
2072
|
+
setIsProcessing(true);
|
|
2073
|
+
setProcessingError(void 0);
|
|
2074
|
+
console.log(TAG, `processing ${messages.length} messages...`);
|
|
2075
|
+
try {
|
|
2076
|
+
const client = new BazaarClient({ chainId, publicClient: wagmiClient });
|
|
2077
|
+
const parsedSales = await client.processSalesFromMessages(
|
|
2078
|
+
messages,
|
|
2079
|
+
{ nftAddress }
|
|
2080
|
+
);
|
|
2081
|
+
console.log(TAG, `processed \u2192 ${parsedSales.length} sales`);
|
|
2082
|
+
if (!cancelled) {
|
|
2083
|
+
setSales(parsedSales);
|
|
2084
|
+
}
|
|
2085
|
+
} catch (err) {
|
|
2086
|
+
console.error(TAG, "processing error:", err);
|
|
2087
|
+
if (!cancelled) {
|
|
2088
|
+
setProcessingError(err instanceof Error ? err : new Error(String(err)));
|
|
2089
|
+
setSales([]);
|
|
2090
|
+
}
|
|
2091
|
+
} finally {
|
|
2092
|
+
if (!cancelled) {
|
|
2093
|
+
setIsProcessing(false);
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
processSales();
|
|
2098
|
+
return () => {
|
|
2099
|
+
cancelled = true;
|
|
2100
|
+
};
|
|
2101
|
+
}, [chainId, nftAddress, messages, isSupported, enabled, refetchTrigger]);
|
|
2102
|
+
const refetch = () => {
|
|
2103
|
+
refetchMessages();
|
|
2104
|
+
setRefetchTrigger((t) => t + 1);
|
|
2105
|
+
};
|
|
2106
|
+
return {
|
|
2107
|
+
sales,
|
|
2108
|
+
isLoading: isLoadingCount || isLoadingMessages || isProcessing,
|
|
2109
|
+
error: messagesError || processingError,
|
|
2110
|
+
refetch
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
1864
2113
|
|
|
1865
|
-
export { useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings };
|
|
2114
|
+
export { useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings, useBazaarSales };
|
|
1866
2115
|
//# sourceMappingURL=react.mjs.map
|
|
1867
2116
|
//# sourceMappingURL=react.mjs.map
|