@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/index.mjs
CHANGED
|
@@ -354,18 +354,21 @@ var DEFAULT_SEAPORT_ADDRESS = "0x0000000000000068F116a894984e2DB1123eB395";
|
|
|
354
354
|
var DEFAULT_BAZAAR_ADDRESS = "0x00000000E3dA5fC031282A39759bDDA78ae7fAE5";
|
|
355
355
|
var DEFAULT_COLLECTION_OFFERS_ADDRESS = "0x0000000D43423E0A12CecB307a74591999b32B32";
|
|
356
356
|
var DEFAULT_FEE_COLLECTOR_ADDRESS = "0x32D16C15410248bef498D7aF50D10Db1a546b9E5";
|
|
357
|
+
var DEFAULT_ERC20_BAZAAR_ADDRESS = "0x00000000a2d173a4610c85c7471a25b6bc216a70";
|
|
357
358
|
var DEFAULT_NFT_FEE_BPS = 500;
|
|
358
359
|
var BULK_SEAPORT_ORDER_STATUS_FETCHER_ADDRESS = "0x0000009112ABCE652674b4fE3eD9C765B22d11A7";
|
|
359
360
|
var ERC721_OWNER_OF_HELPER_ADDRESS = "0x000000aa4eFa2e5A4a6002C7F08B6e8Ec8cf1dDa";
|
|
360
361
|
var ERC20_BULK_BALANCE_CHECKER_ADDRESS = "0x000000b50a9f2923f2db931391824f6d1278f712";
|
|
361
362
|
var NET_SEAPORT_ZONE_ADDRESS = "0x000000007F8c58fbf215bF91Bda7421A806cf3ae";
|
|
362
363
|
var NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS = "0x000000B799ec6D7aCC1B578f62bFc324c25DFC5A";
|
|
364
|
+
var NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS = "0x000000bC63761cbb05305632212e2f3AE2BE7a9B";
|
|
363
365
|
var BAZAAR_CHAIN_CONFIGS = {
|
|
364
366
|
// Base Mainnet
|
|
365
367
|
8453: {
|
|
366
368
|
bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
|
|
367
369
|
collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
|
|
368
370
|
erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
|
|
371
|
+
erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
|
|
369
372
|
seaportAddress: DEFAULT_SEAPORT_ADDRESS,
|
|
370
373
|
feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
|
|
371
374
|
nftFeeBps: 0,
|
|
@@ -455,6 +458,7 @@ var BAZAAR_CHAIN_CONFIGS = {
|
|
|
455
458
|
bazaarAddress: "0x000000058f3ade587388daf827174d0e6fc97595",
|
|
456
459
|
collectionOffersAddress: "0x0000000f9c45efcff0f78d8b54aa6a40092d66dc",
|
|
457
460
|
erc20OffersAddress: "0x0000000e23a89aa06f317306aa1ae231d3503082",
|
|
461
|
+
erc20BazaarAddress: "0x00000006557e3629e2fc50bbad0c002b27cac492",
|
|
458
462
|
seaportAddress: DEFAULT_SEAPORT_ADDRESS,
|
|
459
463
|
feeCollectorAddress: "0x66547ff4f7206e291F7BC157b54C026Fc6660961",
|
|
460
464
|
nftFeeBps: 0,
|
|
@@ -531,6 +535,9 @@ function getHighEthAddress(chainId) {
|
|
|
531
535
|
function getErc20OffersAddress(chainId) {
|
|
532
536
|
return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20OffersAddress;
|
|
533
537
|
}
|
|
538
|
+
function getErc20BazaarAddress(chainId) {
|
|
539
|
+
return BAZAAR_CHAIN_CONFIGS[chainId]?.erc20BazaarAddress ?? DEFAULT_ERC20_BAZAAR_ADDRESS;
|
|
540
|
+
}
|
|
534
541
|
function decodeSeaportSubmission(messageData) {
|
|
535
542
|
const [decoded] = decodeAbiParameters(BAZAAR_SUBMISSION_ABI, messageData);
|
|
536
543
|
return {
|
|
@@ -752,6 +759,19 @@ function isErc20OfferValid(orderStatus, expirationDate, priceWei, buyerWethBalan
|
|
|
752
759
|
}
|
|
753
760
|
return true;
|
|
754
761
|
}
|
|
762
|
+
function isErc20ListingValid(orderStatus, expirationDate, tokenAmount, sellerTokenBalance) {
|
|
763
|
+
if (orderStatus !== 2 /* OPEN */) {
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
767
|
+
if (expirationDate <= now) {
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
if (sellerTokenBalance < tokenAmount) {
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
return true;
|
|
774
|
+
}
|
|
755
775
|
|
|
756
776
|
// src/utils/parsing.ts
|
|
757
777
|
function parseListingFromMessage(message, chainId) {
|
|
@@ -767,6 +787,7 @@ function parseListingFromMessage(message, chainId) {
|
|
|
767
787
|
}
|
|
768
788
|
const priceWei = getTotalConsiderationAmount(parameters);
|
|
769
789
|
const tokenId = offerItem.identifierOrCriteria.toString();
|
|
790
|
+
const targetFulfiller = parameters.zone.toLowerCase() === NET_SEAPORT_PRIVATE_ORDER_ZONE_ADDRESS.toLowerCase() && parameters.zoneHash !== "0x0000000000000000000000000000000000000000000000000000000000000000" ? parameters.zoneHash : void 0;
|
|
770
791
|
return {
|
|
771
792
|
maker: parameters.offerer,
|
|
772
793
|
nftAddress: offerItem.token,
|
|
@@ -783,7 +804,8 @@ function parseListingFromMessage(message, chainId) {
|
|
|
783
804
|
orderComponents: {
|
|
784
805
|
...parameters,
|
|
785
806
|
counter: submission.counter
|
|
786
|
-
}
|
|
807
|
+
},
|
|
808
|
+
targetFulfiller
|
|
787
809
|
};
|
|
788
810
|
} catch {
|
|
789
811
|
return null;
|
|
@@ -921,6 +943,58 @@ function sortErc20OffersByPricePerToken(offers) {
|
|
|
921
943
|
return 0;
|
|
922
944
|
});
|
|
923
945
|
}
|
|
946
|
+
function parseErc20ListingFromMessage(message, chainId) {
|
|
947
|
+
try {
|
|
948
|
+
const submission = decodeSeaportSubmission(message.data);
|
|
949
|
+
const { parameters } = submission;
|
|
950
|
+
if (parameters.zone.toLowerCase() === NET_SEAPORT_COLLECTION_OFFER_ZONE_ADDRESS.toLowerCase()) {
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
const offerItem = parameters.offer[0];
|
|
954
|
+
if (!offerItem || offerItem.itemType !== 1 /* ERC20 */) {
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
const tokenAmount = offerItem.startAmount;
|
|
958
|
+
if (tokenAmount === BigInt(0)) {
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
const priceWei = getTotalConsiderationAmount(parameters);
|
|
962
|
+
if (priceWei === BigInt(0)) {
|
|
963
|
+
return null;
|
|
964
|
+
}
|
|
965
|
+
const pricePerTokenWei = priceWei / tokenAmount;
|
|
966
|
+
return {
|
|
967
|
+
maker: parameters.offerer,
|
|
968
|
+
tokenAddress: offerItem.token,
|
|
969
|
+
tokenAmount,
|
|
970
|
+
priceWei,
|
|
971
|
+
pricePerTokenWei,
|
|
972
|
+
price: formatPrice(priceWei),
|
|
973
|
+
pricePerToken: formatPrice(pricePerTokenWei),
|
|
974
|
+
currency: getCurrencySymbol(chainId),
|
|
975
|
+
expirationDate: Number(parameters.endTime),
|
|
976
|
+
orderHash: "0x",
|
|
977
|
+
// Will be computed later
|
|
978
|
+
orderStatus: 2 /* OPEN */,
|
|
979
|
+
// Will be validated later
|
|
980
|
+
messageData: message.data,
|
|
981
|
+
orderComponents: {
|
|
982
|
+
...parameters,
|
|
983
|
+
counter: submission.counter
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
} catch {
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function sortErc20ListingsByPricePerToken(listings) {
|
|
991
|
+
return [...listings].sort((a, b) => {
|
|
992
|
+
const diff = a.pricePerTokenWei - b.pricePerTokenWei;
|
|
993
|
+
if (diff < BigInt(0)) return -1;
|
|
994
|
+
if (diff > BigInt(0)) return 1;
|
|
995
|
+
return 0;
|
|
996
|
+
});
|
|
997
|
+
}
|
|
924
998
|
|
|
925
999
|
// src/client/BazaarClient.ts
|
|
926
1000
|
var CHAIN_RPC_URLS = {
|
|
@@ -977,25 +1051,30 @@ var BazaarClient = class {
|
|
|
977
1051
|
* Results are deduplicated (one per token) and sorted by price (lowest first)
|
|
978
1052
|
*/
|
|
979
1053
|
async getListings(options) {
|
|
980
|
-
const { nftAddress, excludeMaker, maxMessages = 200 } = options;
|
|
1054
|
+
const { nftAddress, excludeMaker, maker, maxMessages = 200 } = options;
|
|
981
1055
|
const bazaarAddress = getBazaarAddress(this.chainId);
|
|
982
|
-
const
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1056
|
+
const filter = {
|
|
1057
|
+
appAddress: bazaarAddress,
|
|
1058
|
+
topic: nftAddress.toLowerCase(),
|
|
1059
|
+
maker
|
|
1060
|
+
};
|
|
1061
|
+
let startIndex;
|
|
1062
|
+
let endIndex;
|
|
1063
|
+
if (options.startIndex != null && options.endIndex != null) {
|
|
1064
|
+
startIndex = options.startIndex;
|
|
1065
|
+
endIndex = options.endIndex;
|
|
1066
|
+
} else {
|
|
1067
|
+
const count = await this.netClient.getMessageCount({ filter });
|
|
1068
|
+
if (count === 0) {
|
|
1069
|
+
return [];
|
|
986
1070
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
return [];
|
|
1071
|
+
startIndex = Math.max(0, count - maxMessages);
|
|
1072
|
+
endIndex = count;
|
|
990
1073
|
}
|
|
991
|
-
const startIndex = Math.max(0, count - maxMessages);
|
|
992
1074
|
const messages = await this.netClient.getMessages({
|
|
993
|
-
filter
|
|
994
|
-
appAddress: bazaarAddress,
|
|
995
|
-
topic: nftAddress.toLowerCase()
|
|
996
|
-
},
|
|
1075
|
+
filter,
|
|
997
1076
|
startIndex,
|
|
998
|
-
endIndex
|
|
1077
|
+
endIndex
|
|
999
1078
|
});
|
|
1000
1079
|
let listings = [];
|
|
1001
1080
|
for (const message of messages) {
|
|
@@ -1216,6 +1295,92 @@ var BazaarClient = class {
|
|
|
1216
1295
|
});
|
|
1217
1296
|
return sortErc20OffersByPricePerToken(offers);
|
|
1218
1297
|
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Get valid ERC20 listings for a token
|
|
1300
|
+
*
|
|
1301
|
+
* Returns listings that are:
|
|
1302
|
+
* - OPEN status (not filled, cancelled, or expired)
|
|
1303
|
+
* - Not expired
|
|
1304
|
+
* - Seller has sufficient ERC20 token balance
|
|
1305
|
+
*
|
|
1306
|
+
* Results are sorted by price per token (lowest first). No deduplication —
|
|
1307
|
+
* all valid listings are returned (grouped by maker in the UI).
|
|
1308
|
+
*/
|
|
1309
|
+
async getErc20Listings(options) {
|
|
1310
|
+
const { tokenAddress, excludeMaker, maker, maxMessages = 200 } = options;
|
|
1311
|
+
const erc20BazaarAddress = getErc20BazaarAddress(this.chainId);
|
|
1312
|
+
const filter = {
|
|
1313
|
+
appAddress: erc20BazaarAddress,
|
|
1314
|
+
topic: tokenAddress.toLowerCase(),
|
|
1315
|
+
maker
|
|
1316
|
+
};
|
|
1317
|
+
let startIndex;
|
|
1318
|
+
let endIndex;
|
|
1319
|
+
if (options.startIndex != null && options.endIndex != null) {
|
|
1320
|
+
startIndex = options.startIndex;
|
|
1321
|
+
endIndex = options.endIndex;
|
|
1322
|
+
} else {
|
|
1323
|
+
const count = await this.netClient.getMessageCount({ filter });
|
|
1324
|
+
if (count === 0) {
|
|
1325
|
+
return [];
|
|
1326
|
+
}
|
|
1327
|
+
startIndex = Math.max(0, count - maxMessages);
|
|
1328
|
+
endIndex = count;
|
|
1329
|
+
}
|
|
1330
|
+
const messages = await this.netClient.getMessages({
|
|
1331
|
+
filter,
|
|
1332
|
+
startIndex,
|
|
1333
|
+
endIndex
|
|
1334
|
+
});
|
|
1335
|
+
let listings = [];
|
|
1336
|
+
for (const message of messages) {
|
|
1337
|
+
const listing = parseErc20ListingFromMessage(message, this.chainId);
|
|
1338
|
+
if (!listing) continue;
|
|
1339
|
+
if (listing.tokenAddress.toLowerCase() !== tokenAddress.toLowerCase()) {
|
|
1340
|
+
continue;
|
|
1341
|
+
}
|
|
1342
|
+
if (excludeMaker && listing.maker.toLowerCase() === excludeMaker.toLowerCase()) {
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
listings.push(listing);
|
|
1346
|
+
}
|
|
1347
|
+
if (listings.length === 0) {
|
|
1348
|
+
return [];
|
|
1349
|
+
}
|
|
1350
|
+
const seaport = createSeaportInstance(this.chainId, this.rpcUrl);
|
|
1351
|
+
for (const listing of listings) {
|
|
1352
|
+
const order = getSeaportOrderFromMessageData(listing.messageData);
|
|
1353
|
+
listing.orderHash = computeOrderHash(seaport, order.parameters, order.counter);
|
|
1354
|
+
}
|
|
1355
|
+
const orderHashes = listings.map((l) => l.orderHash);
|
|
1356
|
+
const statusInfos = await bulkFetchOrderStatuses(this.client, this.chainId, orderHashes);
|
|
1357
|
+
listings.forEach((listing, index) => {
|
|
1358
|
+
const statusInfo = statusInfos[index];
|
|
1359
|
+
listing.orderStatus = getOrderStatusFromInfo(listing.orderComponents, statusInfo);
|
|
1360
|
+
});
|
|
1361
|
+
listings = listings.filter(
|
|
1362
|
+
(l) => l.orderStatus === 2 /* OPEN */ && l.expirationDate > Math.floor(Date.now() / 1e3)
|
|
1363
|
+
);
|
|
1364
|
+
if (listings.length === 0) {
|
|
1365
|
+
return [];
|
|
1366
|
+
}
|
|
1367
|
+
const uniqueMakers = [...new Set(listings.map((l) => l.maker))];
|
|
1368
|
+
const balances = await bulkFetchErc20Balances(this.client, tokenAddress, uniqueMakers);
|
|
1369
|
+
const balanceMap = /* @__PURE__ */ new Map();
|
|
1370
|
+
uniqueMakers.forEach((maker2, index) => {
|
|
1371
|
+
balanceMap.set(maker2.toLowerCase(), balances[index]);
|
|
1372
|
+
});
|
|
1373
|
+
listings = listings.filter((listing) => {
|
|
1374
|
+
const balance = balanceMap.get(listing.maker.toLowerCase()) || BigInt(0);
|
|
1375
|
+
return isErc20ListingValid(
|
|
1376
|
+
listing.orderStatus,
|
|
1377
|
+
listing.expirationDate,
|
|
1378
|
+
listing.tokenAmount,
|
|
1379
|
+
balance
|
|
1380
|
+
);
|
|
1381
|
+
});
|
|
1382
|
+
return sortErc20ListingsByPricePerToken(listings);
|
|
1383
|
+
}
|
|
1219
1384
|
/**
|
|
1220
1385
|
* Get the chain ID this client is configured for
|
|
1221
1386
|
*/
|
|
@@ -1241,6 +1406,12 @@ var BazaarClient = class {
|
|
|
1241
1406
|
getErc20OffersAddress() {
|
|
1242
1407
|
return getErc20OffersAddress(this.chainId);
|
|
1243
1408
|
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Get the ERC20 bazaar (listings) contract address for this chain
|
|
1411
|
+
*/
|
|
1412
|
+
getErc20BazaarAddress() {
|
|
1413
|
+
return getErc20BazaarAddress(this.chainId);
|
|
1414
|
+
}
|
|
1244
1415
|
/**
|
|
1245
1416
|
* Get the Seaport contract address for this chain
|
|
1246
1417
|
*/
|
|
@@ -1271,6 +1442,18 @@ var BazaarClient = class {
|
|
|
1271
1442
|
}
|
|
1272
1443
|
return this.prepareCancelOrder(offer.orderComponents);
|
|
1273
1444
|
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Prepare a transaction to cancel an ERC20 listing
|
|
1447
|
+
*
|
|
1448
|
+
* The listing must have been created by the caller.
|
|
1449
|
+
* Use the orderComponents from the Erc20Listing object returned by getErc20Listings().
|
|
1450
|
+
*/
|
|
1451
|
+
prepareCancelErc20Listing(listing) {
|
|
1452
|
+
if (!listing.orderComponents) {
|
|
1453
|
+
throw new Error("Listing does not have order components");
|
|
1454
|
+
}
|
|
1455
|
+
return this.prepareCancelOrder(listing.orderComponents);
|
|
1456
|
+
}
|
|
1274
1457
|
/**
|
|
1275
1458
|
* Prepare a transaction to cancel a Seaport order
|
|
1276
1459
|
*
|
|
@@ -1313,6 +1496,6 @@ var BazaarClient = class {
|
|
|
1313
1496
|
}
|
|
1314
1497
|
};
|
|
1315
1498
|
|
|
1316
|
-
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_ZONE_ADDRESS, OrderType, SEAPORT_CANCEL_ABI, SeaportOrderStatus, bulkFetchErc20Balances, bulkFetchNftOwners, bulkFetchOrderStatuses, computeOrderHash, createBalanceMap, createOrderStatusMap, createOwnershipMap, createSeaportInstance, decodeSeaportSubmission, formatPrice, getBazaarAddress, getBazaarChainConfig, getBazaarSupportedChainIds, getBestCollectionOffer, getBestListingPerToken, getCollectionOffersAddress, getCurrencySymbol, getErc20OffersAddress, getFeeCollectorAddress, getHighEthAddress, getNftFeeBps, getOrderStatusFromInfo, getSeaportAddress, getSeaportOrderFromMessageData, getTotalConsiderationAmount, getWrappedNativeCurrency, isBazaarSupportedOnChain, isCollectionOfferValid, isErc20OfferValid, isListingValid, parseCollectionOfferFromMessage, parseErc20OfferFromMessage, parseListingFromMessage, sortErc20OffersByPricePerToken, sortListingsByPrice, sortOffersByPrice };
|
|
1499
|
+
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 };
|
|
1317
1500
|
//# sourceMappingURL=index.mjs.map
|
|
1318
1501
|
//# sourceMappingURL=index.mjs.map
|