@net-protocol/bazaar 0.1.0 → 0.1.1
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 +51 -3
- package/dist/index.d.ts +51 -3
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +171 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +63 -2
- package/dist/react.d.ts +63 -2
- package/dist/react.js +268 -0
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +268 -1
- package/dist/react.mjs.map +1 -1
- package/dist/{types-CY-6M9Ta.d.mts → types--4_RIuQ5.d.mts} +43 -1
- package/dist/{types-CY-6M9Ta.d.ts → types--4_RIuQ5.d.ts} +43 -1
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -177,6 +177,7 @@ var DEFAULT_SEAPORT_ADDRESS = "0x0000000000000068F116a894984e2DB1123eB395";
|
|
|
177
177
|
var DEFAULT_BAZAAR_ADDRESS = "0x00000000E3dA5fC031282A39759bDDA78ae7fAE5";
|
|
178
178
|
var DEFAULT_COLLECTION_OFFERS_ADDRESS = "0x0000000D43423E0A12CecB307a74591999b32B32";
|
|
179
179
|
var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5";
|
|
180
|
+
var DEFAULT_ERC20_BAZAAR_ADDRESS = "0x00000000a2d173a4610c85c7471a25b6bc216a70";
|
|
180
181
|
var DEFAULT_NFT_FEE_BPS = 500;
|
|
181
182
|
var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
|
|
182
183
|
var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
|
|
@@ -188,6 +189,7 @@ var BAZAAR_CHAIN_CONFIGS = {
|
|
|
188
189
|
bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
|
|
189
190
|
collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
|
|
190
191
|
erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
|
|
192
|
+
erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
|
|
191
193
|
seaportAddress: DEFAULT_SEAPORT_ADDRESS,
|
|
192
194
|
feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
|
|
193
195
|
nftFeeBps: 0,
|
|
@@ -277,6 +279,7 @@ var BAZAAR_CHAIN_CONFIGS = {
|
|
|
277
279
|
bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
|
|
278
280
|
collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
|
|
279
281
|
erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
|
|
282
|
+
erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
|
|
280
283
|
seaportAddress: DEFAULT_SEAPORT_ADDRESS,
|
|
281
284
|
feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
|
|
282
285
|
nftFeeBps: 0,
|
|
@@ -344,6 +347,9 @@ function getHighEthAddress(chainId) {
|
|
|
344
347
|
function getErc20OffersAddress(chainId) {
|
|
345
348
|
return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20OffersAddress;
|
|
346
349
|
}
|
|
350
|
+
function getErc20BazaarAddress(chainId) {
|
|
351
|
+
return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20BazaarAddress ?? DEFAULT_ERC20_BAZAAR_ADDRESS;
|
|
352
|
+
}
|
|
347
353
|
function decodeSeaportSubmission(messageData) {
|
|
348
354
|
const [decoded] = decodeAbiParameters(BAZAAR_SUBMISSION_ABI, messageData);
|
|
349
355
|
return {
|
|
@@ -541,6 +547,19 @@ function isErc20OfferValid(orderStatus, expirationDate, priceWei, buyerWethBalan
|
|
|
541
547
|
}
|
|
542
548
|
return true;
|
|
543
549
|
}
|
|
550
|
+
function isErc20ListingValid(orderStatus, expirationDate, tokenAmount, sellerTokenBalance) {
|
|
551
|
+
if (orderStatus !== 2 /* OPEN */) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
555
|
+
if (expirationDate <= now) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
if (sellerTokenBalance < tokenAmount) {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
544
563
|
|
|
545
564
|
// src/utils/parsing.ts
|
|
546
565
|
function parseListingFromMessage(message, chainId) {
|
|
@@ -702,6 +721,58 @@ function sortErc20OffersByPricePerToken(offers) {
|
|
|
702
721
|
return 0;
|
|
703
722
|
});
|
|
704
723
|
}
|
|
724
|
+
function parseErc20ListingFromMessage(message, chainId) {
|
|
725
|
+
try {
|
|
726
|
+
const submission = decodeSeaportSubmission(message.data);
|
|
727
|
+
const { parameters } = submission;
|
|
728
|
+
if (parameters.zone.toLowerCase() === NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS.toLowerCase()) {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
const offerItem = parameters.offer[0];
|
|
732
|
+
if (!offerItem || offerItem.itemType !== 1 /* ERC20 */) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
const tokenAmount = offerItem.startAmount;
|
|
736
|
+
if (tokenAmount === BigInt(0)) {
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
const priceWei = getTotalConsiderationAmount(parameters);
|
|
740
|
+
if (priceWei === BigInt(0)) {
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
const pricePerTokenWei = priceWei / tokenAmount;
|
|
744
|
+
return {
|
|
745
|
+
maker: parameters.offerer,
|
|
746
|
+
tokenAddress: offerItem.token,
|
|
747
|
+
tokenAmount,
|
|
748
|
+
priceWei,
|
|
749
|
+
pricePerTokenWei,
|
|
750
|
+
price: formatPrice(priceWei),
|
|
751
|
+
pricePerToken: formatPrice(pricePerTokenWei),
|
|
752
|
+
currency: getCurrencySymbol(chainId),
|
|
753
|
+
expirationDate: Number(parameters.endTime),
|
|
754
|
+
orderHash: "0x",
|
|
755
|
+
// Will be computed later
|
|
756
|
+
orderStatus: 2 /* OPEN */,
|
|
757
|
+
// Will be validated later
|
|
758
|
+
messageData: message.data,
|
|
759
|
+
orderComponents: {
|
|
760
|
+
...parameters,
|
|
761
|
+
counter: submission.counter
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
} catch {
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
function sortErc20ListingsByPricePerToken(listings) {
|
|
769
|
+
return [...listings].sort((a, b) => {
|
|
770
|
+
const diff = a.pricePerTokenWei - b.pricePerTokenWei;
|
|
771
|
+
if (diff < BigInt(0)) return -1;
|
|
772
|
+
if (diff > BigInt(0)) return 1;
|
|
773
|
+
return 0;
|
|
774
|
+
});
|
|
775
|
+
}
|
|
705
776
|
|
|
706
777
|
// src/client/BazaarClient.ts
|
|
707
778
|
var CHAIN_RPC_URLS = {
|
|
@@ -997,6 +1068,87 @@ var BazaarClient = class {
|
|
|
997
1068
|
});
|
|
998
1069
|
return sortErc20OffersByPricePerToken(offers);
|
|
999
1070
|
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Get valid ERC20 listings for a token
|
|
1073
|
+
*
|
|
1074
|
+
* Returns listings that are:
|
|
1075
|
+
* - OPEN status (not filled, cancelled, or expired)
|
|
1076
|
+
* - Not expired
|
|
1077
|
+
* - Seller has sufficient ERC20 token balance
|
|
1078
|
+
*
|
|
1079
|
+
* Results are sorted by price per token (lowest first). No deduplication —
|
|
1080
|
+
* all valid listings are returned (grouped by maker in the UI).
|
|
1081
|
+
*/
|
|
1082
|
+
async getErc20Listings(options) {
|
|
1083
|
+
const { tokenAddress, excludeMaker, maxMessages = 200 } = options;
|
|
1084
|
+
const erc20BazaarAddress = getErc20BazaarAddress(this.chainId);
|
|
1085
|
+
const count = await this.netClient.getMessageCount({
|
|
1086
|
+
filter: {
|
|
1087
|
+
appAddress: erc20BazaarAddress,
|
|
1088
|
+
topic: tokenAddress.toLowerCase()
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
if (count === 0) {
|
|
1092
|
+
return [];
|
|
1093
|
+
}
|
|
1094
|
+
const startIndex = Math.max(0, count - maxMessages);
|
|
1095
|
+
const messages = await this.netClient.getMessages({
|
|
1096
|
+
filter: {
|
|
1097
|
+
appAddress: erc20BazaarAddress,
|
|
1098
|
+
topic: tokenAddress.toLowerCase()
|
|
1099
|
+
},
|
|
1100
|
+
startIndex,
|
|
1101
|
+
endIndex: count
|
|
1102
|
+
});
|
|
1103
|
+
let listings = [];
|
|
1104
|
+
for (const message of messages) {
|
|
1105
|
+
const listing = parseErc20ListingFromMessage(message, this.chainId);
|
|
1106
|
+
if (!listing) continue;
|
|
1107
|
+
if (listing.tokenAddress.toLowerCase() !== tokenAddress.toLowerCase()) {
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
if (excludeMaker && listing.maker.toLowerCase() === excludeMaker.toLowerCase()) {
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
listings.push(listing);
|
|
1114
|
+
}
|
|
1115
|
+
if (listings.length === 0) {
|
|
1116
|
+
return [];
|
|
1117
|
+
}
|
|
1118
|
+
const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
|
|
1119
|
+
for (const listing of listings) {
|
|
1120
|
+
const order = getSeaportOrderFromMessageData(listing.messageData);
|
|
1121
|
+
listing.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
|
|
1122
|
+
}
|
|
1123
|
+
const orderHashes = listings.map((l) => l.orderHash);
|
|
1124
|
+
const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
|
|
1125
|
+
listings.forEach((listing, index) => {
|
|
1126
|
+
const statusInfo = statusInfos[index];
|
|
1127
|
+
listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
|
|
1128
|
+
});
|
|
1129
|
+
listings = listings.filter(
|
|
1130
|
+
(l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
|
|
1131
|
+
);
|
|
1132
|
+
if (listings.length === 0) {
|
|
1133
|
+
return [];
|
|
1134
|
+
}
|
|
1135
|
+
const uniqueMakers = [...new Set(listings.map((l) => l.maker))];
|
|
1136
|
+
const balances = await bulkFetchErc20Balances(this.client, tokenAddress, uniqueMakers);
|
|
1137
|
+
const balanceMap = /* @__PURE__ */ new Map();
|
|
1138
|
+
uniqueMakers.forEach((maker, index) => {
|
|
1139
|
+
balanceMap.set(maker.toLowerCase(), balances[index]);
|
|
1140
|
+
});
|
|
1141
|
+
listings = listings.filter((listing) => {
|
|
1142
|
+
const balance = balanceMap.get(listing.maker.toLowerCase()) || BigInt(0);
|
|
1143
|
+
return isErc20ListingValid(
|
|
1144
|
+
listing.orderStatus,
|
|
1145
|
+
listing.expirationDate,
|
|
1146
|
+
listing.tokenAmount,
|
|
1147
|
+
balance
|
|
1148
|
+
);
|
|
1149
|
+
});
|
|
1150
|
+
return sortErc20ListingsByPricePerToken(listings);
|
|
1151
|
+
}
|
|
1000
1152
|
/**
|
|
1001
1153
|
* Get the chain ID this client is configured for
|
|
1002
1154
|
*/
|
|
@@ -1022,6 +1174,12 @@ var BazaarClient = class {
|
|
|
1022
1174
|
getErc20OffersAddress() {
|
|
1023
1175
|
return getErc20OffersAddress(this.chainId);
|
|
1024
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Get the ERC20 bazaar (listings) contract address for this chain
|
|
1179
|
+
*/
|
|
1180
|
+
getErc20BazaarAddress() {
|
|
1181
|
+
return getErc20BazaarAddress(this.chainId);
|
|
1182
|
+
}
|
|
1025
1183
|
/**
|
|
1026
1184
|
* Get the Seaport contract address for this chain
|
|
1027
1185
|
*/
|
|
@@ -1052,6 +1210,18 @@ var BazaarClient = class {
|
|
|
1052
1210
|
}
|
|
1053
1211
|
return this.prepareCancelOrder(offer.orderComponents);
|
|
1054
1212
|
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Prepare a transaction to cancel an ERC20 listing
|
|
1215
|
+
*
|
|
1216
|
+
* The listing must have been created by the caller.
|
|
1217
|
+
* Use the orderComponents from the Erc20Listing object returned by getErc20Listings().
|
|
1218
|
+
*/
|
|
1219
|
+
prepareCancelErc20Listing(listing) {
|
|
1220
|
+
if (!listing.orderComponents) {
|
|
1221
|
+
throw new Error("Listing does not have order components");
|
|
1222
|
+
}
|
|
1223
|
+
return this.prepareCancelOrder(listing.orderComponents);
|
|
1224
|
+
}
|
|
1055
1225
|
/**
|
|
1056
1226
|
* Prepare a transaction to cancel a Seaport order
|
|
1057
1227
|
*
|
|
@@ -1387,7 +1557,104 @@ function useBazaarErc20Offers({
|
|
|
1387
1557
|
refetch
|
|
1388
1558
|
};
|
|
1389
1559
|
}
|
|
1560
|
+
function useBazaarErc20Listings({
|
|
1561
|
+
chainId,
|
|
1562
|
+
tokenAddress,
|
|
1563
|
+
excludeMaker,
|
|
1564
|
+
maxMessages = 200,
|
|
1565
|
+
enabled = true
|
|
1566
|
+
}) {
|
|
1567
|
+
const [listings, setListings] = useState([]);
|
|
1568
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
1569
|
+
const [processingError, setProcessingError] = useState();
|
|
1570
|
+
const [refetchTrigger, setRefetchTrigger] = useState(0);
|
|
1571
|
+
const isSupported = useMemo(
|
|
1572
|
+
() => isBazaarSupportedOnChain(chainId),
|
|
1573
|
+
[chainId]
|
|
1574
|
+
);
|
|
1575
|
+
const erc20BazaarAddress = useMemo(
|
|
1576
|
+
() => isSupported ? getErc20BazaarAddress(chainId) : void 0,
|
|
1577
|
+
[chainId, isSupported]
|
|
1578
|
+
);
|
|
1579
|
+
const filter = useMemo(
|
|
1580
|
+
() => ({
|
|
1581
|
+
appAddress: erc20BazaarAddress,
|
|
1582
|
+
topic: tokenAddress.toLowerCase()
|
|
1583
|
+
}),
|
|
1584
|
+
[erc20BazaarAddress, tokenAddress]
|
|
1585
|
+
);
|
|
1586
|
+
const { count: totalCount, isLoading: isLoadingCount } = useNetMessageCount({
|
|
1587
|
+
chainId,
|
|
1588
|
+
filter,
|
|
1589
|
+
enabled: enabled && isSupported
|
|
1590
|
+
});
|
|
1591
|
+
const startIndex = useMemo(
|
|
1592
|
+
() => Math.max(0, totalCount - maxMessages),
|
|
1593
|
+
[totalCount, maxMessages]
|
|
1594
|
+
);
|
|
1595
|
+
const {
|
|
1596
|
+
messages,
|
|
1597
|
+
isLoading: isLoadingMessages,
|
|
1598
|
+
error: messagesError,
|
|
1599
|
+
refetch: refetchMessages
|
|
1600
|
+
} = useNetMessages({
|
|
1601
|
+
chainId,
|
|
1602
|
+
filter,
|
|
1603
|
+
startIndex,
|
|
1604
|
+
endIndex: totalCount,
|
|
1605
|
+
enabled: enabled && isSupported && totalCount > 0
|
|
1606
|
+
});
|
|
1607
|
+
useEffect(() => {
|
|
1608
|
+
if (!isSupported || !enabled) {
|
|
1609
|
+
setListings([]);
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
if (!messages || messages.length === 0) {
|
|
1613
|
+
setListings([]);
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
let cancelled = false;
|
|
1617
|
+
async function processListings() {
|
|
1618
|
+
setIsProcessing(true);
|
|
1619
|
+
setProcessingError(void 0);
|
|
1620
|
+
try {
|
|
1621
|
+
const client = new BazaarClient({ chainId });
|
|
1622
|
+
const validListings = await client.getErc20Listings({
|
|
1623
|
+
tokenAddress,
|
|
1624
|
+
excludeMaker,
|
|
1625
|
+
maxMessages
|
|
1626
|
+
});
|
|
1627
|
+
if (!cancelled) {
|
|
1628
|
+
setListings(validListings);
|
|
1629
|
+
}
|
|
1630
|
+
} catch (err) {
|
|
1631
|
+
if (!cancelled) {
|
|
1632
|
+
setProcessingError(err instanceof Error ? err : new Error(String(err)));
|
|
1633
|
+
setListings([]);
|
|
1634
|
+
}
|
|
1635
|
+
} finally {
|
|
1636
|
+
if (!cancelled) {
|
|
1637
|
+
setIsProcessing(false);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
processListings();
|
|
1642
|
+
return () => {
|
|
1643
|
+
cancelled = true;
|
|
1644
|
+
};
|
|
1645
|
+
}, [chainId, tokenAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
|
|
1646
|
+
const refetch = () => {
|
|
1647
|
+
refetchMessages();
|
|
1648
|
+
setRefetchTrigger((t) => t + 1);
|
|
1649
|
+
};
|
|
1650
|
+
return {
|
|
1651
|
+
listings,
|
|
1652
|
+
isLoading: isLoadingCount || isLoadingMessages || isProcessing,
|
|
1653
|
+
error: messagesError || processingError,
|
|
1654
|
+
refetch
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1390
1657
|
|
|
1391
|
-
export { useBazaarCollectionOffers, useBazaarErc20Offers, useBazaarListings };
|
|
1658
|
+
export { useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings };
|
|
1392
1659
|
//# sourceMappingURL=react.mjs.map
|
|
1393
1660
|
//# sourceMappingURL=react.mjs.map
|