@net-protocol/bazaar 0.1.0 → 0.1.2
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 +52 -3
- package/dist/index.d.ts +52 -3
- package/dist/index.js +203 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +199 -16
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +76 -3
- package/dist/react.d.ts +76 -3
- package/dist/react.js +320 -27
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +320 -28
- package/dist/react.mjs.map +1 -1
- package/dist/{types-CY-6M9Ta.d.mts → types-KQgBECzI.d.mts} +57 -1
- package/dist/{types-CY-6M9Ta.d.ts → types-KQgBECzI.d.ts} +57 -1
- package/package.json +1 -1
package/dist/react.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as Listing, C as CollectionOffer, E as Erc20Offer } from './types-
|
|
1
|
+
import { L as Listing, C as CollectionOffer, E as Erc20Offer, d as Erc20Listing } from './types-KQgBECzI.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* React hook for fetching NFT listings from Bazaar
|
|
@@ -11,8 +11,14 @@ interface UseBazaarListingsOptions {
|
|
|
11
11
|
nftAddress: `0x${string}`;
|
|
12
12
|
/** Exclude listings from this address */
|
|
13
13
|
excludeMaker?: `0x${string}`;
|
|
14
|
+
/** Only include listings from this address */
|
|
15
|
+
maker?: `0x${string}`;
|
|
14
16
|
/** Maximum number of messages to fetch (default: 200) */
|
|
15
17
|
maxMessages?: number;
|
|
18
|
+
/** Override start index for message range */
|
|
19
|
+
startIndex?: number;
|
|
20
|
+
/** Override end index for message range */
|
|
21
|
+
endIndex?: number;
|
|
16
22
|
/** Whether the query is enabled (default: true) */
|
|
17
23
|
enabled?: boolean;
|
|
18
24
|
}
|
|
@@ -58,7 +64,7 @@ interface UseBazaarListingsResult {
|
|
|
58
64
|
* );
|
|
59
65
|
* ```
|
|
60
66
|
*/
|
|
61
|
-
declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maxMessages, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
|
|
67
|
+
declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
|
|
62
68
|
|
|
63
69
|
/**
|
|
64
70
|
* React hook for fetching collection offers from Bazaar
|
|
@@ -175,4 +181,71 @@ interface UseBazaarErc20OffersResult {
|
|
|
175
181
|
*/
|
|
176
182
|
declare function useBazaarErc20Offers({ chainId, tokenAddress, excludeMaker, maxMessages, enabled, }: UseBazaarErc20OffersOptions): UseBazaarErc20OffersResult;
|
|
177
183
|
|
|
178
|
-
|
|
184
|
+
/**
|
|
185
|
+
* React hook for fetching ERC20 listings from Bazaar
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
interface UseBazaarErc20ListingsOptions {
|
|
189
|
+
/** Chain ID to query */
|
|
190
|
+
chainId: number;
|
|
191
|
+
/** ERC20 token address */
|
|
192
|
+
tokenAddress: `0x${string}`;
|
|
193
|
+
/** Exclude listings from this address */
|
|
194
|
+
excludeMaker?: `0x${string}`;
|
|
195
|
+
/** Only include listings from this address */
|
|
196
|
+
maker?: `0x${string}`;
|
|
197
|
+
/** Maximum number of messages to fetch (default: 200) */
|
|
198
|
+
maxMessages?: number;
|
|
199
|
+
/** Override start index for message range */
|
|
200
|
+
startIndex?: number;
|
|
201
|
+
/** Override end index for message range */
|
|
202
|
+
endIndex?: number;
|
|
203
|
+
/** Whether the query is enabled (default: true) */
|
|
204
|
+
enabled?: boolean;
|
|
205
|
+
}
|
|
206
|
+
interface UseBazaarErc20ListingsResult {
|
|
207
|
+
/** Valid ERC20 listings (sorted by price per token, lowest first) */
|
|
208
|
+
listings: Erc20Listing[];
|
|
209
|
+
/** Whether the data is loading */
|
|
210
|
+
isLoading: boolean;
|
|
211
|
+
/** Error if any */
|
|
212
|
+
error: Error | undefined;
|
|
213
|
+
/** Refetch function */
|
|
214
|
+
refetch: () => void;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* React hook for fetching valid ERC20 listings from Bazaar
|
|
218
|
+
*
|
|
219
|
+
* ERC20 listings are available on all supported chains.
|
|
220
|
+
*
|
|
221
|
+
* Returns listings that are:
|
|
222
|
+
* - OPEN status (not filled, cancelled, or expired)
|
|
223
|
+
* - Not expired
|
|
224
|
+
* - Seller has sufficient ERC20 token balance
|
|
225
|
+
*
|
|
226
|
+
* Results are sorted by price per token (lowest first)
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```tsx
|
|
230
|
+
* const { listings, isLoading, error } = useBazaarErc20Listings({
|
|
231
|
+
* chainId: 8453,
|
|
232
|
+
* tokenAddress: "0x...",
|
|
233
|
+
* });
|
|
234
|
+
*
|
|
235
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
236
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
237
|
+
*
|
|
238
|
+
* const bestListing = listings[0];
|
|
239
|
+
* if (bestListing) {
|
|
240
|
+
* return (
|
|
241
|
+
* <div>
|
|
242
|
+
* Best listing: {bestListing.pricePerToken} {bestListing.currency} per token
|
|
243
|
+
* (total: {bestListing.price} {bestListing.currency} for {bestListing.tokenAmount.toString()} tokens)
|
|
244
|
+
* </div>
|
|
245
|
+
* );
|
|
246
|
+
* }
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
declare function useBazaarErc20Listings({ chainId, tokenAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarErc20ListingsOptions): UseBazaarErc20ListingsResult;
|
|
250
|
+
|
|
251
|
+
export { type UseBazaarCollectionOffersOptions, type UseBazaarCollectionOffersResult, type UseBazaarErc20ListingsOptions, type UseBazaarErc20ListingsResult, type UseBazaarErc20OffersOptions, type UseBazaarErc20OffersResult, type UseBazaarListingsOptions, type UseBazaarListingsResult, useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as Listing, C as CollectionOffer, E as Erc20Offer } from './types-
|
|
1
|
+
import { L as Listing, C as CollectionOffer, E as Erc20Offer, d as Erc20Listing } from './types-KQgBECzI.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* React hook for fetching NFT listings from Bazaar
|
|
@@ -11,8 +11,14 @@ interface UseBazaarListingsOptions {
|
|
|
11
11
|
nftAddress: `0x${string}`;
|
|
12
12
|
/** Exclude listings from this address */
|
|
13
13
|
excludeMaker?: `0x${string}`;
|
|
14
|
+
/** Only include listings from this address */
|
|
15
|
+
maker?: `0x${string}`;
|
|
14
16
|
/** Maximum number of messages to fetch (default: 200) */
|
|
15
17
|
maxMessages?: number;
|
|
18
|
+
/** Override start index for message range */
|
|
19
|
+
startIndex?: number;
|
|
20
|
+
/** Override end index for message range */
|
|
21
|
+
endIndex?: number;
|
|
16
22
|
/** Whether the query is enabled (default: true) */
|
|
17
23
|
enabled?: boolean;
|
|
18
24
|
}
|
|
@@ -58,7 +64,7 @@ interface UseBazaarListingsResult {
|
|
|
58
64
|
* );
|
|
59
65
|
* ```
|
|
60
66
|
*/
|
|
61
|
-
declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maxMessages, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
|
|
67
|
+
declare function useBazaarListings({ chainId, nftAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarListingsOptions): UseBazaarListingsResult;
|
|
62
68
|
|
|
63
69
|
/**
|
|
64
70
|
* React hook for fetching collection offers from Bazaar
|
|
@@ -175,4 +181,71 @@ interface UseBazaarErc20OffersResult {
|
|
|
175
181
|
*/
|
|
176
182
|
declare function useBazaarErc20Offers({ chainId, tokenAddress, excludeMaker, maxMessages, enabled, }: UseBazaarErc20OffersOptions): UseBazaarErc20OffersResult;
|
|
177
183
|
|
|
178
|
-
|
|
184
|
+
/**
|
|
185
|
+
* React hook for fetching ERC20 listings from Bazaar
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
interface UseBazaarErc20ListingsOptions {
|
|
189
|
+
/** Chain ID to query */
|
|
190
|
+
chainId: number;
|
|
191
|
+
/** ERC20 token address */
|
|
192
|
+
tokenAddress: `0x${string}`;
|
|
193
|
+
/** Exclude listings from this address */
|
|
194
|
+
excludeMaker?: `0x${string}`;
|
|
195
|
+
/** Only include listings from this address */
|
|
196
|
+
maker?: `0x${string}`;
|
|
197
|
+
/** Maximum number of messages to fetch (default: 200) */
|
|
198
|
+
maxMessages?: number;
|
|
199
|
+
/** Override start index for message range */
|
|
200
|
+
startIndex?: number;
|
|
201
|
+
/** Override end index for message range */
|
|
202
|
+
endIndex?: number;
|
|
203
|
+
/** Whether the query is enabled (default: true) */
|
|
204
|
+
enabled?: boolean;
|
|
205
|
+
}
|
|
206
|
+
interface UseBazaarErc20ListingsResult {
|
|
207
|
+
/** Valid ERC20 listings (sorted by price per token, lowest first) */
|
|
208
|
+
listings: Erc20Listing[];
|
|
209
|
+
/** Whether the data is loading */
|
|
210
|
+
isLoading: boolean;
|
|
211
|
+
/** Error if any */
|
|
212
|
+
error: Error | undefined;
|
|
213
|
+
/** Refetch function */
|
|
214
|
+
refetch: () => void;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* React hook for fetching valid ERC20 listings from Bazaar
|
|
218
|
+
*
|
|
219
|
+
* ERC20 listings are available on all supported chains.
|
|
220
|
+
*
|
|
221
|
+
* Returns listings that are:
|
|
222
|
+
* - OPEN status (not filled, cancelled, or expired)
|
|
223
|
+
* - Not expired
|
|
224
|
+
* - Seller has sufficient ERC20 token balance
|
|
225
|
+
*
|
|
226
|
+
* Results are sorted by price per token (lowest first)
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```tsx
|
|
230
|
+
* const { listings, isLoading, error } = useBazaarErc20Listings({
|
|
231
|
+
* chainId: 8453,
|
|
232
|
+
* tokenAddress: "0x...",
|
|
233
|
+
* });
|
|
234
|
+
*
|
|
235
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
236
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
237
|
+
*
|
|
238
|
+
* const bestListing = listings[0];
|
|
239
|
+
* if (bestListing) {
|
|
240
|
+
* return (
|
|
241
|
+
* <div>
|
|
242
|
+
* Best listing: {bestListing.pricePerToken} {bestListing.currency} per token
|
|
243
|
+
* (total: {bestListing.price} {bestListing.currency} for {bestListing.tokenAmount.toString()} tokens)
|
|
244
|
+
* </div>
|
|
245
|
+
* );
|
|
246
|
+
* }
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
declare function useBazaarErc20Listings({ chainId, tokenAddress, excludeMaker, maker, maxMessages, startIndex: startIndexOverride, endIndex: endIndexOverride, enabled, }: UseBazaarErc20ListingsOptions): UseBazaarErc20ListingsResult;
|
|
250
|
+
|
|
251
|
+
export { type UseBazaarCollectionOffersOptions, type UseBazaarCollectionOffersResult, type UseBazaarErc20ListingsOptions, type UseBazaarErc20ListingsResult, type UseBazaarErc20OffersOptions, type UseBazaarErc20OffersResult, type UseBazaarListingsOptions, type UseBazaarListingsResult, useBazaarCollectionOffers, useBazaarErc20Listings, useBazaarErc20Offers, useBazaarListings };
|
package/dist/react.js
CHANGED
|
@@ -179,17 +179,20 @@ var DEFAULT_SEAPORT_ADDRESS = "0x0000000000000068F116a894984e2DB1123eB395";
|
|
|
179
179
|
var DEFAULT_BAZAAR_ADDRESS = "0x00000000E3dA5fC031282A39759bDDA78ae7fAE5";
|
|
180
180
|
var DEFAULT_COLLECTION_OFFERS_ADDRESS = "0x0000000D43423E0A12CecB307a74591999b32B32";
|
|
181
181
|
var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5";
|
|
182
|
+
var DEFAULT_ERC20_BAZAAR_ADDRESS = "0x00000000a2d173a4610c85c7471a25b6bc216a70";
|
|
182
183
|
var DEFAULT_NFT_FEE_BPS = 500;
|
|
183
184
|
var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
|
|
184
185
|
var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
|
|
185
186
|
var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000b50a9f2923f2db931391824f6d1278f712";
|
|
186
187
|
var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
|
|
188
|
+
var NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = "0x000000bC63761cbb05305632212e2f3AE2BE7a9B";
|
|
187
189
|
var BAZAAR_CHAIN_CONFIGS = {
|
|
188
190
|
// Base Mainnet
|
|
189
191
|
8453: {
|
|
190
192
|
bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
|
|
191
193
|
collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
|
|
192
194
|
erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
|
|
195
|
+
erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
|
|
193
196
|
seaportAddress: DEFAULT_SEAPORT_ADDRESS,
|
|
194
197
|
feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
|
|
195
198
|
nftFeeBps: 0,
|
|
@@ -279,6 +282,7 @@ var BAZAAR_CHAIN_CONFIGS = {
|
|
|
279
282
|
bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
|
|
280
283
|
collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
|
|
281
284
|
erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
|
|
285
|
+
erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
|
|
282
286
|
seaportAddress: DEFAULT_SEAPORT_ADDRESS,
|
|
283
287
|
feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
|
|
284
288
|
nftFeeBps: 0,
|
|
@@ -346,6 +350,9 @@ function getHighEthAddress(chainId) {
|
|
|
346
350
|
function getErc20OffersAddress(chainId) {
|
|
347
351
|
return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20OffersAddress;
|
|
348
352
|
}
|
|
353
|
+
function getErc20BazaarAddress(chainId) {
|
|
354
|
+
return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20BazaarAddress ?? DEFAULT_ERC20_BAZAAR_ADDRESS;
|
|
355
|
+
}
|
|
349
356
|
function decodeSeaportSubmission(messageData) {
|
|
350
357
|
const [decoded] = viem.decodeAbiParameters(BAZAAR_SUBMISSION_ABI, messageData);
|
|
351
358
|
return {
|
|
@@ -543,6 +550,19 @@ function isErc20OfferValid(orderStatus, expirationDate, priceWei, buyerWethBalan
|
|
|
543
550
|
}
|
|
544
551
|
return true;
|
|
545
552
|
}
|
|
553
|
+
function isErc20ListingValid(orderStatus, expirationDate, tokenAmount, sellerTokenBalance) {
|
|
554
|
+
if (orderStatus !== 2 /* OPEN */) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
558
|
+
if (expirationDate <= now) {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
if (sellerTokenBalance < tokenAmount) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
546
566
|
|
|
547
567
|
// src/utils/parsing.ts
|
|
548
568
|
function parseListingFromMessage(message, chainId) {
|
|
@@ -558,6 +578,7 @@ function parseListingFromMessage(message, chainId) {
|
|
|
558
578
|
}
|
|
559
579
|
const priceWei = getTotalConsiderationAmount(parameters);
|
|
560
580
|
const tokenId = offerItem.identifierOrCriteria.toString();
|
|
581
|
+
const targetFulfiller = parameters.zone.toLowerCase() === NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS.toLowerCase() && parameters.zoneHash !== "0x0000000000000000000000000000000000000000000000000000000000000000" ? parameters.zoneHash : void 0;
|
|
561
582
|
return {
|
|
562
583
|
maker: parameters.offerer,
|
|
563
584
|
nftAddress: offerItem.token,
|
|
@@ -574,7 +595,8 @@ function parseListingFromMessage(message, chainId) {
|
|
|
574
595
|
orderComponents: {
|
|
575
596
|
...parameters,
|
|
576
597
|
counter: submission.counter
|
|
577
|
-
}
|
|
598
|
+
},
|
|
599
|
+
targetFulfiller
|
|
578
600
|
};
|
|
579
601
|
} catch {
|
|
580
602
|
return null;
|
|
@@ -704,6 +726,58 @@ function sortErc20OffersByPricePerToken(offers) {
|
|
|
704
726
|
return 0;
|
|
705
727
|
});
|
|
706
728
|
}
|
|
729
|
+
function parseErc20ListingFromMessage(message, chainId) {
|
|
730
|
+
try {
|
|
731
|
+
const submission = decodeSeaportSubmission(message.data);
|
|
732
|
+
const { parameters } = submission;
|
|
733
|
+
if (parameters.zone.toLowerCase() === NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS.toLowerCase()) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
const offerItem = parameters.offer[0];
|
|
737
|
+
if (!offerItem || offerItem.itemType !== 1 /* ERC20 */) {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
const tokenAmount = offerItem.startAmount;
|
|
741
|
+
if (tokenAmount === BigInt(0)) {
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
const priceWei = getTotalConsiderationAmount(parameters);
|
|
745
|
+
if (priceWei === BigInt(0)) {
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
const pricePerTokenWei = priceWei / tokenAmount;
|
|
749
|
+
return {
|
|
750
|
+
maker: parameters.offerer,
|
|
751
|
+
tokenAddress: offerItem.token,
|
|
752
|
+
tokenAmount,
|
|
753
|
+
priceWei,
|
|
754
|
+
pricePerTokenWei,
|
|
755
|
+
price: formatPrice(priceWei),
|
|
756
|
+
pricePerToken: formatPrice(pricePerTokenWei),
|
|
757
|
+
currency: getCurrencySymbol(chainId),
|
|
758
|
+
expirationDate: Number(parameters.endTime),
|
|
759
|
+
orderHash: "0x",
|
|
760
|
+
// Will be computed later
|
|
761
|
+
orderStatus: 2 /* OPEN */,
|
|
762
|
+
// Will be validated later
|
|
763
|
+
messageData: message.data,
|
|
764
|
+
orderComponents: {
|
|
765
|
+
...parameters,
|
|
766
|
+
counter: submission.counter
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
} catch {
|
|
770
|
+
return null;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
function sortErc20ListingsByPricePerToken(listings) {
|
|
774
|
+
return [...listings].sort((a, b) => {
|
|
775
|
+
const diff = a.pricePerTokenWei - b.pricePerTokenWei;
|
|
776
|
+
if (diff < BigInt(0)) return -1;
|
|
777
|
+
if (diff > BigInt(0)) return 1;
|
|
778
|
+
return 0;
|
|
779
|
+
});
|
|
780
|
+
}
|
|
707
781
|
|
|
708
782
|
// src/client/BazaarClient.ts
|
|
709
783
|
var CHAIN_RPC_URLS = {
|
|
@@ -760,25 +834,30 @@ var BazaarClient = class {
|
|
|
760
834
|
* Results are deduplicated (one per token) and sorted by price (lowest first)
|
|
761
835
|
*/
|
|
762
836
|
async getListings(options) {
|
|
763
|
-
const { nftAddress, excludeMaker, maxMessages = 200 } = options;
|
|
837
|
+
const { nftAddress, excludeMaker, maker, maxMessages = 200 } = options;
|
|
764
838
|
const bazaarAddress = getBazaarAddress(this.chainId);
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
839
|
+
const filter = {
|
|
840
|
+
appAddress: bazaarAddress,
|
|
841
|
+
topic: nftAddress.toLowerCase(),
|
|
842
|
+
maker
|
|
843
|
+
};
|
|
844
|
+
let startIndex;
|
|
845
|
+
let endIndex;
|
|
846
|
+
if (options.startIndex != null && options.endIndex != null) {
|
|
847
|
+
startIndex = options.startIndex;
|
|
848
|
+
endIndex = options.endIndex;
|
|
849
|
+
} else {
|
|
850
|
+
const count = await this.netClient.getMessageCount({ filter });
|
|
851
|
+
if (count === 0) {
|
|
852
|
+
return [];
|
|
769
853
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
return [];
|
|
854
|
+
startIndex = Math.max(0, count - maxMessages);
|
|
855
|
+
endIndex = count;
|
|
773
856
|
}
|
|
774
|
-
const startIndex = Math.max(0, count - maxMessages);
|
|
775
857
|
const messages = await this.netClient.getMessages({
|
|
776
|
-
filter
|
|
777
|
-
appAddress: bazaarAddress,
|
|
778
|
-
topic: nftAddress.toLowerCase()
|
|
779
|
-
},
|
|
858
|
+
filter,
|
|
780
859
|
startIndex,
|
|
781
|
-
endIndex
|
|
860
|
+
endIndex
|
|
782
861
|
});
|
|
783
862
|
let listings = [];
|
|
784
863
|
for (const message of messages) {
|
|
@@ -999,6 +1078,92 @@ var BazaarClient = class {
|
|
|
999
1078
|
});
|
|
1000
1079
|
return sortErc20OffersByPricePerToken(offers);
|
|
1001
1080
|
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Get valid ERC20 listings for a token
|
|
1083
|
+
*
|
|
1084
|
+
* Returns listings that are:
|
|
1085
|
+
* - OPEN status (not filled, cancelled, or expired)
|
|
1086
|
+
* - Not expired
|
|
1087
|
+
* - Seller has sufficient ERC20 token balance
|
|
1088
|
+
*
|
|
1089
|
+
* Results are sorted by price per token (lowest first). No deduplication —
|
|
1090
|
+
* all valid listings are returned (grouped by maker in the UI).
|
|
1091
|
+
*/
|
|
1092
|
+
async getErc20Listings(options) {
|
|
1093
|
+
const { tokenAddress, excludeMaker, maker, maxMessages = 200 } = options;
|
|
1094
|
+
const erc20BazaarAddress = getErc20BazaarAddress(this.chainId);
|
|
1095
|
+
const filter = {
|
|
1096
|
+
appAddress: erc20BazaarAddress,
|
|
1097
|
+
topic: tokenAddress.toLowerCase(),
|
|
1098
|
+
maker
|
|
1099
|
+
};
|
|
1100
|
+
let startIndex;
|
|
1101
|
+
let endIndex;
|
|
1102
|
+
if (options.startIndex != null && options.endIndex != null) {
|
|
1103
|
+
startIndex = options.startIndex;
|
|
1104
|
+
endIndex = options.endIndex;
|
|
1105
|
+
} else {
|
|
1106
|
+
const count = await this.netClient.getMessageCount({ filter });
|
|
1107
|
+
if (count === 0) {
|
|
1108
|
+
return [];
|
|
1109
|
+
}
|
|
1110
|
+
startIndex = Math.max(0, count - maxMessages);
|
|
1111
|
+
endIndex = count;
|
|
1112
|
+
}
|
|
1113
|
+
const messages = await this.netClient.getMessages({
|
|
1114
|
+
filter,
|
|
1115
|
+
startIndex,
|
|
1116
|
+
endIndex
|
|
1117
|
+
});
|
|
1118
|
+
let listings = [];
|
|
1119
|
+
for (const message of messages) {
|
|
1120
|
+
const listing = parseErc20ListingFromMessage(message, this.chainId);
|
|
1121
|
+
if (!listing) continue;
|
|
1122
|
+
if (listing.tokenAddress.toLowerCase() !== tokenAddress.toLowerCase()) {
|
|
1123
|
+
continue;
|
|
1124
|
+
}
|
|
1125
|
+
if (excludeMaker && listing.maker.toLowerCase() === excludeMaker.toLowerCase()) {
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
listings.push(listing);
|
|
1129
|
+
}
|
|
1130
|
+
if (listings.length === 0) {
|
|
1131
|
+
return [];
|
|
1132
|
+
}
|
|
1133
|
+
const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
|
|
1134
|
+
for (const listing of listings) {
|
|
1135
|
+
const order = getSeaportOrderFromMessageData(listing.messageData);
|
|
1136
|
+
listing.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
|
|
1137
|
+
}
|
|
1138
|
+
const orderHashes = listings.map((l) => l.orderHash);
|
|
1139
|
+
const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
|
|
1140
|
+
listings.forEach((listing, index) => {
|
|
1141
|
+
const statusInfo = statusInfos[index];
|
|
1142
|
+
listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
|
|
1143
|
+
});
|
|
1144
|
+
listings = listings.filter(
|
|
1145
|
+
(l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
|
|
1146
|
+
);
|
|
1147
|
+
if (listings.length === 0) {
|
|
1148
|
+
return [];
|
|
1149
|
+
}
|
|
1150
|
+
const uniqueMakers = [...new Set(listings.map((l) => l.maker))];
|
|
1151
|
+
const balances = await bulkFetchErc20Balances(this.client, tokenAddress, uniqueMakers);
|
|
1152
|
+
const balanceMap = /* @__PURE__ */ new Map();
|
|
1153
|
+
uniqueMakers.forEach((maker2, index) => {
|
|
1154
|
+
balanceMap.set(maker2.toLowerCase(), balances[index]);
|
|
1155
|
+
});
|
|
1156
|
+
listings = listings.filter((listing) => {
|
|
1157
|
+
const balance = balanceMap.get(listing.maker.toLowerCase()) || BigInt(0);
|
|
1158
|
+
return isErc20ListingValid(
|
|
1159
|
+
listing.orderStatus,
|
|
1160
|
+
listing.expirationDate,
|
|
1161
|
+
listing.tokenAmount,
|
|
1162
|
+
balance
|
|
1163
|
+
);
|
|
1164
|
+
});
|
|
1165
|
+
return sortErc20ListingsByPricePerToken(listings);
|
|
1166
|
+
}
|
|
1002
1167
|
/**
|
|
1003
1168
|
* Get the chain ID this client is configured for
|
|
1004
1169
|
*/
|
|
@@ -1024,6 +1189,12 @@ var BazaarClient = class {
|
|
|
1024
1189
|
getErc20OffersAddress() {
|
|
1025
1190
|
return getErc20OffersAddress(this.chainId);
|
|
1026
1191
|
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Get the ERC20 bazaar (listings) contract address for this chain
|
|
1194
|
+
*/
|
|
1195
|
+
getErc20BazaarAddress() {
|
|
1196
|
+
return getErc20BazaarAddress(this.chainId);
|
|
1197
|
+
}
|
|
1027
1198
|
/**
|
|
1028
1199
|
* Get the Seaport contract address for this chain
|
|
1029
1200
|
*/
|
|
@@ -1054,6 +1225,18 @@ var BazaarClient = class {
|
|
|
1054
1225
|
}
|
|
1055
1226
|
return this.prepareCancelOrder(offer.orderComponents);
|
|
1056
1227
|
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Prepare a transaction to cancel an ERC20 listing
|
|
1230
|
+
*
|
|
1231
|
+
* The listing must have been created by the caller.
|
|
1232
|
+
* Use the orderComponents from the Erc20Listing object returned by getErc20Listings().
|
|
1233
|
+
*/
|
|
1234
|
+
prepareCancelErc20Listing(listing) {
|
|
1235
|
+
if (!listing.orderComponents) {
|
|
1236
|
+
throw new Error("Listing does not have order components");
|
|
1237
|
+
}
|
|
1238
|
+
return this.prepareCancelOrder(listing.orderComponents);
|
|
1239
|
+
}
|
|
1057
1240
|
/**
|
|
1058
1241
|
* Prepare a transaction to cancel a Seaport order
|
|
1059
1242
|
*
|
|
@@ -1101,13 +1284,17 @@ function useBazaarListings({
|
|
|
1101
1284
|
chainId,
|
|
1102
1285
|
nftAddress,
|
|
1103
1286
|
excludeMaker,
|
|
1287
|
+
maker,
|
|
1104
1288
|
maxMessages = 200,
|
|
1289
|
+
startIndex: startIndexOverride,
|
|
1290
|
+
endIndex: endIndexOverride,
|
|
1105
1291
|
enabled = true
|
|
1106
1292
|
}) {
|
|
1107
1293
|
const [listings, setListings] = react.useState([]);
|
|
1108
1294
|
const [isProcessing, setIsProcessing] = react.useState(false);
|
|
1109
1295
|
const [processingError, setProcessingError] = react.useState();
|
|
1110
1296
|
const [refetchTrigger, setRefetchTrigger] = react.useState(0);
|
|
1297
|
+
const hasRangeOverride = startIndexOverride != null && endIndexOverride != null;
|
|
1111
1298
|
const isSupported = react.useMemo(
|
|
1112
1299
|
() => isBazaarSupportedOnChain(chainId),
|
|
1113
1300
|
[chainId]
|
|
@@ -1119,19 +1306,18 @@ function useBazaarListings({
|
|
|
1119
1306
|
const filter = react.useMemo(
|
|
1120
1307
|
() => ({
|
|
1121
1308
|
appAddress: bazaarAddress,
|
|
1122
|
-
topic: nftAddress.toLowerCase()
|
|
1309
|
+
topic: nftAddress.toLowerCase(),
|
|
1310
|
+
maker
|
|
1123
1311
|
}),
|
|
1124
|
-
[bazaarAddress, nftAddress]
|
|
1312
|
+
[bazaarAddress, nftAddress, maker]
|
|
1125
1313
|
);
|
|
1126
1314
|
const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
|
|
1127
1315
|
chainId,
|
|
1128
1316
|
filter,
|
|
1129
|
-
enabled: enabled && isSupported
|
|
1317
|
+
enabled: enabled && isSupported && !hasRangeOverride
|
|
1130
1318
|
});
|
|
1131
|
-
const startIndex =
|
|
1132
|
-
|
|
1133
|
-
[totalCount, maxMessages]
|
|
1134
|
-
);
|
|
1319
|
+
const startIndex = hasRangeOverride ? startIndexOverride : Math.max(0, totalCount - maxMessages);
|
|
1320
|
+
const endIndex = hasRangeOverride ? endIndexOverride : totalCount;
|
|
1135
1321
|
const {
|
|
1136
1322
|
messages,
|
|
1137
1323
|
isLoading: isLoadingMessages,
|
|
@@ -1141,8 +1327,8 @@ function useBazaarListings({
|
|
|
1141
1327
|
chainId,
|
|
1142
1328
|
filter,
|
|
1143
1329
|
startIndex,
|
|
1144
|
-
endIndex
|
|
1145
|
-
enabled: enabled && isSupported && totalCount > 0
|
|
1330
|
+
endIndex,
|
|
1331
|
+
enabled: enabled && isSupported && (hasRangeOverride || totalCount > 0)
|
|
1146
1332
|
});
|
|
1147
1333
|
react.useEffect(() => {
|
|
1148
1334
|
if (!isSupported || !enabled) {
|
|
@@ -1162,7 +1348,10 @@ function useBazaarListings({
|
|
|
1162
1348
|
const validListings = await client.getListings({
|
|
1163
1349
|
nftAddress,
|
|
1164
1350
|
excludeMaker,
|
|
1165
|
-
|
|
1351
|
+
maker,
|
|
1352
|
+
maxMessages,
|
|
1353
|
+
startIndex: hasRangeOverride ? startIndexOverride : void 0,
|
|
1354
|
+
endIndex: hasRangeOverride ? endIndexOverride : void 0
|
|
1166
1355
|
});
|
|
1167
1356
|
if (!cancelled) {
|
|
1168
1357
|
setListings(validListings);
|
|
@@ -1182,14 +1371,14 @@ function useBazaarListings({
|
|
|
1182
1371
|
return () => {
|
|
1183
1372
|
cancelled = true;
|
|
1184
1373
|
};
|
|
1185
|
-
}, [chainId, nftAddress, excludeMaker, maxMessages, messages, isSupported, enabled, refetchTrigger]);
|
|
1374
|
+
}, [chainId, nftAddress, excludeMaker, maker, maxMessages, startIndexOverride, endIndexOverride, hasRangeOverride, messages, isSupported, enabled, refetchTrigger]);
|
|
1186
1375
|
const refetch = () => {
|
|
1187
1376
|
refetchMessages();
|
|
1188
1377
|
setRefetchTrigger((t) => t + 1);
|
|
1189
1378
|
};
|
|
1190
1379
|
return {
|
|
1191
1380
|
listings,
|
|
1192
|
-
isLoading: isLoadingCount || isLoadingMessages || isProcessing,
|
|
1381
|
+
isLoading: (hasRangeOverride ? false : isLoadingCount) || isLoadingMessages || isProcessing,
|
|
1193
1382
|
error: messagesError || processingError,
|
|
1194
1383
|
refetch
|
|
1195
1384
|
};
|
|
@@ -1389,8 +1578,112 @@ function useBazaarErc20Offers({
|
|
|
1389
1578
|
refetch
|
|
1390
1579
|
};
|
|
1391
1580
|
}
|
|
1581
|
+
function useBazaarErc20Listings({
|
|
1582
|
+
chainId,
|
|
1583
|
+
tokenAddress,
|
|
1584
|
+
excludeMaker,
|
|
1585
|
+
maker,
|
|
1586
|
+
maxMessages = 200,
|
|
1587
|
+
startIndex: startIndexOverride,
|
|
1588
|
+
endIndex: endIndexOverride,
|
|
1589
|
+
enabled = true
|
|
1590
|
+
}) {
|
|
1591
|
+
const [listings, setListings] = react.useState([]);
|
|
1592
|
+
const [isProcessing, setIsProcessing] = react.useState(false);
|
|
1593
|
+
const [processingError, setProcessingError] = react.useState();
|
|
1594
|
+
const [refetchTrigger, setRefetchTrigger] = react.useState(0);
|
|
1595
|
+
const hasRangeOverride = startIndexOverride != null && endIndexOverride != null;
|
|
1596
|
+
const isSupported = react.useMemo(
|
|
1597
|
+
() => isBazaarSupportedOnChain(chainId),
|
|
1598
|
+
[chainId]
|
|
1599
|
+
);
|
|
1600
|
+
const erc20BazaarAddress = react.useMemo(
|
|
1601
|
+
() => isSupported ? getErc20BazaarAddress(chainId) : void 0,
|
|
1602
|
+
[chainId, isSupported]
|
|
1603
|
+
);
|
|
1604
|
+
const filter = react.useMemo(
|
|
1605
|
+
() => ({
|
|
1606
|
+
appAddress: erc20BazaarAddress,
|
|
1607
|
+
topic: tokenAddress.toLowerCase(),
|
|
1608
|
+
maker
|
|
1609
|
+
}),
|
|
1610
|
+
[erc20BazaarAddress, tokenAddress, maker]
|
|
1611
|
+
);
|
|
1612
|
+
const { count: totalCount, isLoading: isLoadingCount } = react$1.useNetMessageCount({
|
|
1613
|
+
chainId,
|
|
1614
|
+
filter,
|
|
1615
|
+
enabled: enabled && isSupported && !hasRangeOverride
|
|
1616
|
+
});
|
|
1617
|
+
const startIndex = hasRangeOverride ? startIndexOverride : Math.max(0, totalCount - maxMessages);
|
|
1618
|
+
const endIndex = hasRangeOverride ? endIndexOverride : totalCount;
|
|
1619
|
+
const {
|
|
1620
|
+
messages,
|
|
1621
|
+
isLoading: isLoadingMessages,
|
|
1622
|
+
error: messagesError,
|
|
1623
|
+
refetch: refetchMessages
|
|
1624
|
+
} = react$1.useNetMessages({
|
|
1625
|
+
chainId,
|
|
1626
|
+
filter,
|
|
1627
|
+
startIndex,
|
|
1628
|
+
endIndex,
|
|
1629
|
+
enabled: enabled && isSupported && (hasRangeOverride || totalCount > 0)
|
|
1630
|
+
});
|
|
1631
|
+
react.useEffect(() => {
|
|
1632
|
+
if (!isSupported || !enabled) {
|
|
1633
|
+
setListings([]);
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
if (!messages || messages.length === 0) {
|
|
1637
|
+
setListings([]);
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
let cancelled = false;
|
|
1641
|
+
async function processListings() {
|
|
1642
|
+
setIsProcessing(true);
|
|
1643
|
+
setProcessingError(void 0);
|
|
1644
|
+
try {
|
|
1645
|
+
const client = new BazaarClient({ chainId });
|
|
1646
|
+
const validListings = await client.getErc20Listings({
|
|
1647
|
+
tokenAddress,
|
|
1648
|
+
excludeMaker,
|
|
1649
|
+
maker,
|
|
1650
|
+
maxMessages,
|
|
1651
|
+
startIndex: hasRangeOverride ? startIndexOverride : void 0,
|
|
1652
|
+
endIndex: hasRangeOverride ? endIndexOverride : void 0
|
|
1653
|
+
});
|
|
1654
|
+
if (!cancelled) {
|
|
1655
|
+
setListings(validListings);
|
|
1656
|
+
}
|
|
1657
|
+
} catch (err) {
|
|
1658
|
+
if (!cancelled) {
|
|
1659
|
+
setProcessingError(err instanceof Error ? err : new Error(String(err)));
|
|
1660
|
+
setListings([]);
|
|
1661
|
+
}
|
|
1662
|
+
} finally {
|
|
1663
|
+
if (!cancelled) {
|
|
1664
|
+
setIsProcessing(false);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
processListings();
|
|
1669
|
+
return () => {
|
|
1670
|
+
cancelled = true;
|
|
1671
|
+
};
|
|
1672
|
+
}, [chainId, tokenAddress, excludeMaker, maker, maxMessages, startIndexOverride, endIndexOverride, hasRangeOverride, messages, isSupported, enabled, refetchTrigger]);
|
|
1673
|
+
const refetch = () => {
|
|
1674
|
+
refetchMessages();
|
|
1675
|
+
setRefetchTrigger((t) => t + 1);
|
|
1676
|
+
};
|
|
1677
|
+
return {
|
|
1678
|
+
listings,
|
|
1679
|
+
isLoading: (hasRangeOverride ? false : isLoadingCount) || isLoadingMessages || isProcessing,
|
|
1680
|
+
error: messagesError || processingError,
|
|
1681
|
+
refetch
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1392
1684
|
|
|
1393
1685
|
exports.useBazaarCollectionOffers = useBazaarCollectionOffers;
|
|
1686
|
+
exports.useBazaarErc20Listings = useBazaarErc20Listings;
|
|
1394
1687
|
exports.useBazaarErc20Offers = useBazaarErc20Offers;
|
|
1395
1688
|
exports.useBazaarListings = useBazaarListings;
|
|
1396
1689
|
//# sourceMappingURL=react.js.map
|