opensea-js
Version:
TypeScript SDK for the OpenSea marketplace helps developers build new experiences using NFTs and our marketplace data
442 lines • 17.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeTokenIds = exports.getFeeRecipient = exports.getSignedZone = exports.getSeaportAddress = exports.getDefaultConduitKey = exports.requireValidProtocol = exports.isValidProtocol = exports.basisPointsForFee = exports.totalBasisPointsForFees = exports.getAddressAfterRemappingSharedStorefrontAddressToLazyMintAdapterAddress = exports.getWETHAddress = exports.getListingPaymentToken = exports.getOfferPaymentToken = exports.getChainId = exports.getAssetItemType = exports.hasErrorCode = exports.getMaxOrderExpirationTimestamp = exports.estimateGas = exports.feeFromJSON = exports.accountFromJSON = exports.paymentTokenFromJSON = exports.rarityFromJSON = exports.collectionFromJSON = void 0;
const constants_1 = require("@opensea/seaport-js/lib/constants");
const ethers_1 = require("ethers");
const constants_2 = require("../constants");
const types_1 = require("../types");
/* eslint-disable @typescript-eslint/no-explicit-any */
const collectionFromJSON = (collection) => {
return {
name: collection.name,
collection: collection.collection,
description: collection.description,
imageUrl: collection.image_url,
bannerImageUrl: collection.banner_image_url,
owner: collection.owner,
safelistStatus: collection.safelist_status,
category: collection.category,
isDisabled: collection.is_disabled,
isNSFW: collection.is_nsfw,
traitOffersEnabled: collection.trait_offers_enabled,
collectionOffersEnabled: collection.collection_offers_enabled,
openseaUrl: collection.opensea_url,
projectUrl: collection.project_url,
wikiUrl: collection.wiki_url,
discordUrl: collection.discord_url,
telegramUrl: collection.telegram_url,
twitterUsername: collection.twitter_username,
instagramUsername: collection.instagram_username,
contracts: (collection.contracts ?? []).map((contract) => ({
address: contract.address,
chain: contract.chain,
})),
editors: collection.editors,
fees: (collection.fees ?? []).map(exports.feeFromJSON),
rarity: (0, exports.rarityFromJSON)(collection.rarity),
paymentTokens: (collection.payment_tokens ?? []).map(exports.paymentTokenFromJSON),
totalSupply: collection.total_supply,
createdDate: collection.created_date,
requiredZone: collection.required_zone,
};
};
exports.collectionFromJSON = collectionFromJSON;
const rarityFromJSON = (rarity) => {
if (!rarity) {
return null;
}
const fromJSON = {
strategyId: rarity.strategy_id,
strategyVersion: rarity.strategy_version,
calculatedAt: rarity.calculated_at,
maxRank: rarity.max_rank,
tokensScored: rarity.tokens_scored,
};
return fromJSON;
};
exports.rarityFromJSON = rarityFromJSON;
const paymentTokenFromJSON = (token) => {
const fromJSON = {
name: token.name,
symbol: token.symbol,
decimals: token.decimals,
address: token.address,
chain: token.chain,
imageUrl: token.image,
ethPrice: token.eth_price,
usdPrice: token.usd_price,
};
return fromJSON;
};
exports.paymentTokenFromJSON = paymentTokenFromJSON;
const accountFromJSON = (account) => {
return {
address: account.address,
username: account.username,
profileImageUrl: account.profile_image_url,
bannerImageUrl: account.banner_image_url,
website: account.website,
socialMediaAccounts: (account.social_media_accounts ?? []).map((acct) => ({
platform: acct.platform,
username: acct.username,
})),
bio: account.bio,
joinedDate: account.joined_date,
};
};
exports.accountFromJSON = accountFromJSON;
const feeFromJSON = (fee) => {
const fromJSON = {
fee: fee.fee,
recipient: fee.recipient,
required: fee.required,
};
return fromJSON;
};
exports.feeFromJSON = feeFromJSON;
/**
* Estimate gas usage for a transaction.
* @param provider The Provider
* @param from Address sending transaction
* @param to Destination contract address
* @param data Data to send to contract
* @param value Value in ETH to send with data
*/
async function estimateGas(provider, { from, to, data, value = 0n }) {
return await provider.estimateGas({
from,
to,
value: value.toString(),
data,
});
}
exports.estimateGas = estimateGas;
/**
* The longest time that an order is valid for is one month from the current date
* @returns unix timestamp
*/
const getMaxOrderExpirationTimestamp = () => {
const maxExpirationDate = new Date();
maxExpirationDate.setMonth(maxExpirationDate.getMonth() + constants_2.MAX_EXPIRATION_MONTHS);
maxExpirationDate.setDate(maxExpirationDate.getDate() - 1);
return Math.round(maxExpirationDate.getTime() / 1000);
};
exports.getMaxOrderExpirationTimestamp = getMaxOrderExpirationTimestamp;
const hasErrorCode = (error) => {
const untypedError = error;
return !!untypedError.code;
};
exports.hasErrorCode = hasErrorCode;
const getAssetItemType = (tokenStandard) => {
switch (tokenStandard) {
case "ERC20":
return constants_1.ItemType.ERC20;
case "ERC721":
return constants_1.ItemType.ERC721;
case "ERC1155":
return constants_1.ItemType.ERC1155;
default:
throw new Error(`Unknown schema name: ${tokenStandard}`);
}
};
exports.getAssetItemType = getAssetItemType;
const getChainId = (chain) => {
switch (chain) {
case types_1.Chain.Mainnet:
return "1";
case types_1.Chain.Polygon:
return "137";
case types_1.Chain.Avalanche:
return "43114";
case types_1.Chain.Arbitrum:
return "42161";
case types_1.Chain.ArbitrumNova:
return "42170";
case types_1.Chain.Blast:
return "238";
case types_1.Chain.Base:
return "8453";
case types_1.Chain.Optimism:
return "10";
case types_1.Chain.Zora:
return "7777777";
case types_1.Chain.Sei:
return "1329";
case types_1.Chain.B3:
return "8333";
case types_1.Chain.BeraChain:
return "80094";
case types_1.Chain.Flow:
return "747";
case types_1.Chain.ApeChain:
return "33139";
case types_1.Chain.Ronin:
return "2020";
case types_1.Chain.Abstract:
return "2741";
case types_1.Chain.Shape:
return "360";
case types_1.Chain.Unichain:
return "130";
case types_1.Chain.Gunzilla:
return "43419";
default:
throw new Error(`Unknown chainId for ${chain}`);
}
};
exports.getChainId = getChainId;
/** Returns the default currency for offers on the given chain. */
const getOfferPaymentToken = (chain) => {
switch (chain) {
case types_1.Chain.Mainnet:
return "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; // WETH
case types_1.Chain.Polygon:
return "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"; // WETH
case types_1.Chain.Avalanche:
return "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"; // WAVAX
case types_1.Chain.Arbitrum:
return "0x82af49447d8a07e3bd95bd0d56f35241523fbab1"; // WETH
case types_1.Chain.ArbitrumNova:
return "0x722e8bdd2ce80a4422e880164f2079488e115365"; // WETH
case types_1.Chain.Blast:
return "0x4300000000000000000000000000000000000004"; // WETH
// OP Chains have WETH at the same address
case types_1.Chain.Base:
case types_1.Chain.Optimism:
case types_1.Chain.Zora:
case types_1.Chain.B3:
case types_1.Chain.Shape:
case types_1.Chain.Unichain:
return "0x4200000000000000000000000000000000000006"; // WETH
case types_1.Chain.BeraChain:
return "0x6969696969696969696969696969696969696969"; // WBERA
case types_1.Chain.Sei:
return "0xe30fedd158a2e3b13e9badaeabafc5516e95e8c7"; // WSEI
case types_1.Chain.Flow:
return "0xd3bf53dac106a0290b0483ecbc89d40fcc961f3e"; // WFLOW
case types_1.Chain.ApeChain:
return "0x48b62137edfa95a428d35c09e44256a739f6b557"; // WAPE
case types_1.Chain.Ronin:
return "0xe514d9deb7966c8be0ca922de8a064264ea6bcd4"; // WRON
case types_1.Chain.Abstract:
return "0x3439153eb7af838ad19d56e1571fbd09333c2809"; // WETH
case types_1.Chain.Gunzilla:
return "0x5aad7bba61d95c2c4e525a35f4062040264611f1"; // WGUN
default:
throw new Error(`Unknown offer currency for ${chain}`);
}
};
exports.getOfferPaymentToken = getOfferPaymentToken;
/** Returns the default currency for listings on the given chain. */
const getListingPaymentToken = (chain) => {
switch (chain) {
case types_1.Chain.Mainnet:
case types_1.Chain.Arbitrum:
case types_1.Chain.ArbitrumNova:
case types_1.Chain.Blast:
case types_1.Chain.Base:
case types_1.Chain.Optimism:
case types_1.Chain.Zora:
case types_1.Chain.B3:
case types_1.Chain.Abstract:
case types_1.Chain.Shape:
case types_1.Chain.Unichain:
return "0x0000000000000000000000000000000000000000"; // ETH
case types_1.Chain.Polygon:
return "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"; // WETH
case types_1.Chain.Avalanche:
return "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"; // WETH
case types_1.Chain.BeraChain:
return "0x0000000000000000000000000000000000000000"; // BERA
case types_1.Chain.Sei:
return "0x0000000000000000000000000000000000000000"; // SEI
case types_1.Chain.Flow:
return "0xd3bf53dac106a0290b0483ecbc89d40fcc961f3e"; // WETH
case types_1.Chain.ApeChain:
return "0x0000000000000000000000000000000000000000"; // APE
case types_1.Chain.Ronin:
return "0xe514d9deb7966c8be0ca922de8a064264ea6bcd4"; // WETH
case types_1.Chain.Gunzilla:
return "0x0000000000000000000000000000000000000000"; // GUN
default:
throw new Error(`Unknown listing currency for ${chain}`);
}
};
exports.getListingPaymentToken = getListingPaymentToken;
/** @deprecated Use getOfferPaymentToken instead. Backward compatibility alias. */
exports.getWETHAddress = exports.getOfferPaymentToken;
/**
* Checks if the token address is the shared storefront address and if so replaces
* that address with the lazy mint adapter address. Otherwise, returns the input token address
* @param tokenAddress token address
* @returns input token address or lazy mint adapter address
*/
const getAddressAfterRemappingSharedStorefrontAddressToLazyMintAdapterAddress = (tokenAddress) => {
return constants_2.SHARED_STOREFRONT_ADDRESSES.includes(tokenAddress.toLowerCase())
? constants_2.SHARED_STOREFRONT_LAZY_MINT_ADAPTER_CROSS_CHAIN_ADDRESS
: tokenAddress;
};
exports.getAddressAfterRemappingSharedStorefrontAddressToLazyMintAdapterAddress = getAddressAfterRemappingSharedStorefrontAddressToLazyMintAdapterAddress;
/**
* Sums up the basis points for fees.
* @param fees The fees to sum up
* @returns sum of basis points
*/
const totalBasisPointsForFees = (fees) => {
const feeBasisPoints = fees.map((fee) => (0, exports.basisPointsForFee)(fee));
const totalBasisPoints = feeBasisPoints.reduce((sum, basisPoints) => basisPoints + sum, 0n);
return totalBasisPoints;
};
exports.totalBasisPointsForFees = totalBasisPointsForFees;
/**
* Converts a fee to its basis points representation.
* @param fee The fee to convert
* @returns the basis points
*/
const basisPointsForFee = (fee) => {
return BigInt(ethers_1.FixedNumber.fromString(fee.fee.toString())
.mul(constants_2.FIXED_NUMBER_100)
.toFormat(0) // format to 0 decimal places to convert to bigint
.toString());
};
exports.basisPointsForFee = basisPointsForFee;
/**
* Returns if a protocol address is valid.
* @param protocolAddress The protocol address
*/
const isValidProtocol = (protocolAddress) => {
const checkSumAddress = ethers_1.ethers.getAddress(protocolAddress);
const validProtocolAddresses = [
constants_1.CROSS_CHAIN_SEAPORT_V1_6_ADDRESS,
constants_2.GUNZILLA_SEAPORT_1_6_ADDRESS,
].map((address) => ethers_1.ethers.getAddress(address));
return validProtocolAddresses.includes(checkSumAddress);
};
exports.isValidProtocol = isValidProtocol;
/**
* Throws an error if the protocol address is not valid.
* @param protocolAddress The protocol address
*/
const requireValidProtocol = (protocolAddress) => {
if (!(0, exports.isValidProtocol)(protocolAddress)) {
throw new Error(`Unsupported protocol address: ${protocolAddress}`);
}
};
exports.requireValidProtocol = requireValidProtocol;
/**
* Get the default conduit key for a given chain.
* @param chain The chain to get the conduit key for
* @returns The conduit key for the chain
*/
const getDefaultConduitKey = (chain) => {
switch (chain) {
case types_1.Chain.Abstract:
return constants_2.OPENSEA_CONDUIT_KEY_2;
case types_1.Chain.Gunzilla:
return constants_2.GUNZILLA_CONDUIT_KEY;
default:
return constants_2.OPENSEA_CONDUIT_KEY;
}
};
exports.getDefaultConduitKey = getDefaultConduitKey;
/**
* Get the Seaport 1.6 contract address for a given chain.
* @param chain The chain to get the Seaport address for
* @returns The Seaport 1.6 address for the chain
*/
const getSeaportAddress = (chain) => {
switch (chain) {
case types_1.Chain.Gunzilla:
return constants_2.GUNZILLA_SEAPORT_1_6_ADDRESS;
default:
return constants_1.CROSS_CHAIN_SEAPORT_V1_6_ADDRESS;
}
};
exports.getSeaportAddress = getSeaportAddress;
/**
* Get the signed zone address for a given chain.
* @param chain The chain to get the signed zone address for
* @returns The signed zone address for the chain
*/
const getSignedZone = (chain) => {
switch (chain) {
case types_1.Chain.Gunzilla:
return constants_2.GUNZILLA_SIGNED_ZONE_V2_ADDRESS;
default:
return constants_2.SIGNED_ZONE;
}
};
exports.getSignedZone = getSignedZone;
/**
* Get the fee recipient address for a given chain
* @param chain The blockchain chain
* @returns The fee recipient address for the chain
*/
const getFeeRecipient = (chain) => {
switch (chain) {
case types_1.Chain.Gunzilla:
return constants_2.GUNZILLA_FEE_RECIPIENT;
default:
return constants_2.OPENSEA_FEE_RECIPIENT;
}
};
exports.getFeeRecipient = getFeeRecipient;
/**
* Decodes an encoded string of token IDs into an array of individual token IDs using bigint for precise calculations.
*
* The encoded token IDs can be in the following formats:
* 1. Single numbers: '123' => ['123']
* 2. Comma-separated numbers: '1,2,3,4' => ['1', '2', '3', '4']
* 3. Ranges of numbers: '5:8' => ['5', '6', '7', '8']
* 4. Combinations of single numbers and ranges: '1,3:5,8' => ['1', '3', '4', '5', '8']
* 5. Wildcard '*' (matches all token IDs): '*' => ['*']
*
* @param encodedTokenIds - The encoded string of token IDs to be decoded.
* @returns An array of individual token IDs after decoding the input.
*
* @throws {Error} If the input is not correctly formatted or if bigint operations fail.
*
* @example
* const encoded = '1,3:5,8';
* const decoded = decodeTokenIds(encoded); // Output: ['1', '3', '4', '5', '8']
*
* @example
* const encodedWildcard = '*';
* const decodedWildcard = decodeTokenIds(encodedWildcard); // Output: ['*']
*
* @example
* const emptyEncoded = '';
* const decodedEmpty = decodeTokenIds(emptyEncoded); // Output: []
*/
const decodeTokenIds = (encodedTokenIds) => {
if (encodedTokenIds === "*") {
return ["*"];
}
const validFormatRegex = /^(\d+(:\d+)?)(,\d+(:\d+)?)*$/;
if (!validFormatRegex.test(encodedTokenIds)) {
throw new Error("Invalid input format. Expected a valid comma-separated list of numbers and ranges.");
}
const ranges = encodedTokenIds.split(",");
const tokenIds = [];
for (const range of ranges) {
if (range.includes(":")) {
const [startStr, endStr] = range.split(":");
const start = BigInt(startStr);
const end = BigInt(endStr);
const diff = end - start + 1n;
if (diff <= 0) {
throw new Error(`Invalid range. End value: ${end} must be greater than or equal to the start value: ${start}.`);
}
for (let i = 0n; i < diff; i += 1n) {
tokenIds.push((start + i).toString());
}
}
else {
const tokenId = BigInt(range);
tokenIds.push(tokenId.toString());
}
}
return tokenIds;
};
exports.decodeTokenIds = decodeTokenIds;
//# sourceMappingURL=utils.js.map