Skip to main content
Glama
opensea.ts19.5 kB
import { OpenSeaSDK, Chain, OrderV2, CollectionOffer, AssetWithTokenId, Order } from 'opensea-js'; import { BigNumberish, ethers, Overrides } from 'ethers'; import { getPrivateKeyAsHex, getOpenSeaApiKey } from '../config.js'; import { getRpcUrl } from '../chains.js'; // --- Helper Functions --- /** * Initializes and returns an OpenSeaSDK instance. * This is called by each service function that needs to interact with the SDK. * @returns An instance of OpenSeaSDK */ const getOpenSeaSDK = (): OpenSeaSDK => { const privateKey = getPrivateKeyAsHex(); if (!privateKey) { throw new Error('Private key not available. Ensure it is set in your environment or config.'); } const rpcUrl = getRpcUrl('sei'); const provider = new ethers.JsonRpcProvider(rpcUrl); const signer = new ethers.Wallet(privateKey, provider); (signer as any).signTypedData = async (domain: any, types: any, value: any) => { return signer.signTypedData(domain, types, value); }; return new OpenSeaSDK(signer as any, { chain: Chain.Sei, apiKey: getOpenSeaApiKey(), }); }; /** * Initializes and returns an ethers.js Wallet instance for direct contract interactions. * @returns An instance of ethers.Wallet */ const getSigner = (): ethers.Wallet => { const privateKey = getPrivateKeyAsHex(); if (!privateKey) throw new Error('Private key not available.'); const rpcUrl = getRpcUrl('sei'); const provider = new ethers.JsonRpcProvider(rpcUrl); return new ethers.Wallet(privateKey, provider); } // --- SDK-based Service Functions --- /** * Create and submit a listing for an asset on OpenSea. * @param params Parameters for creating the listing. * @param params.asset The asset to list (tokenAddress and tokenId). * @param params.accountAddress The seller's wallet address. * @param params.startAmount The starting price for the listing. * @param params.endAmount The ending price for the listing (optional). * @param params.quantity The quantity of the asset to list (optional). * @param params.domain The domain for the listing (optional). * @param params.salt The salt for the listing (optional). * @param params.listingTime The listing time for the listing (optional). * @param params.expirationTime The expiration time for the listing (optional). * @param params.paymentTokenAddress The payment token address for the listing (optional). * @param params.buyerAddress The buyer's wallet address for the listing (optional). * @param params.englishAuction Whether the listing is an English auction (optional). * @param params.excludeOptionalCreatorFees Whether to exclude optional creator fees (optional). * @param params.zone The zone for the listing (optional). * @returns The created OrderV2 object from the SDK. */ export async function createListing(params: { asset: AssetWithTokenId; accountAddress: string; startAmount: BigNumberish; endAmount?: BigNumberish; quantity?: BigNumberish; domain?: string; salt?: BigNumberish; listingTime?: number; expirationTime?: number; paymentTokenAddress?: string; buyerAddress?: string; englishAuction?: boolean; excludeOptionalCreatorFees?: boolean; zone?: string; }): Promise<OrderV2> { try { console.log(`Creating listing for asset ${params.asset.tokenAddress}/${params.asset.tokenId}`); const sdk = getOpenSeaSDK(); const { startAmount, endAmount, quantity, salt, ...rest } = params; return await sdk.createListing({ ...rest, startAmount: startAmount.toString(), endAmount: endAmount?.toString(), quantity: quantity?.toString(), salt: salt?.toString(), paymentTokenAddress: params.paymentTokenAddress || ethers.ZeroAddress, zone: params.zone || ethers.ZeroAddress, }); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to create OpenSea listing: ${message}`); } } /** * Create and submit an offer on an asset. * @param params Parameters for creating the offer. * @param params.asset The asset to make an offer on. * @param params.accountAddress The buyer's wallet address. * @param params.startAmount The offer price. * @param params.domain The domain for the offer (optional). * @param params.salt The salt for the offer (optional). * @param params.expirationTime The expiration time for the offer (optional). * @param params.paymentTokenAddress The payment token address for the offer (optional). * @param params.quantity The quantity of the asset to offer (optional). * @param params.excludeOptionalCreatorFees Whether to exclude optional creator fees (optional). * @param params.zone The zone for the offer (optional). * @returns The created OrderV2 object from the SDK. */ export async function createOffer(params: { asset: AssetWithTokenId; accountAddress: string; startAmount: BigNumberish; domain?: string; salt?: BigNumberish; expirationTime?: BigNumberish; paymentTokenAddress?: string; quantity?: BigNumberish; excludeOptionalCreatorFees?: boolean; zone?: string; }): Promise<OrderV2> { try { console.log(`Creating offer for asset ${params.asset.tokenAddress}/${params.asset.tokenId}`); const sdk = getOpenSeaSDK(); const { startAmount, expirationTime, quantity, salt, ...rest } = params; return await sdk.createOffer({ ...rest, startAmount: startAmount.toString(), expirationTime: expirationTime?.toString(), quantity: quantity?.toString(), salt: salt?.toString(), paymentTokenAddress: params.paymentTokenAddress || ethers.ZeroAddress, zone: params.zone || ethers.ZeroAddress, }); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to create OpenSea offer: ${message}`); } } /** * Fulfill an order for an asset (either a listing or an offer). * @param params Parameters for fulfilling the order. * @param params.order The order object from the SDK or API. * @param params.accountAddress The address of the account fulfilling the order. * @param params.domain The domain for the fulfillment (optional). * @param params.recipientAddress The recipient address for the fulfillment (optional). * @param params.overrides The overrides for the fulfillment (optional). * @returns Transaction hash of the fulfillment transaction. */ export async function fulfillOrder(params: { order: OrderV2 | Order; accountAddress: string; domain?: string; recipientAddress?: string; overrides?: Overrides; }): Promise<string> { try { console.log(`Fulfilling order by ${params.accountAddress}`); const sdk = getOpenSeaSDK(); return await sdk.fulfillOrder(params); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to fulfill OpenSea order: ${message}`); } } /** * Create and submit a collection offer. * @param params Parameters for creating the collection offer. * @returns The CollectionOffer that was created. */ export async function createCollectionOffer(params: { collectionSlug: string; accountAddress: string; amount: BigNumberish; quantity: number; domain?: string; salt?: BigNumberish; expirationTime?: number | string; paymentTokenAddress: string; excludeOptionalCreatorFees?: boolean; offerProtectionEnabled?: boolean; traitType?: string; traitValue?: string; }): Promise<CollectionOffer | null> { try { console.log(`Creating collection offer for ${params.collectionSlug}`); const sdk = getOpenSeaSDK(); const { amount, salt, ...rest } = params; return await sdk.createCollectionOffer({ ...rest, amount: amount.toString(), salt: salt?.toString(), }); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to create OpenSea collection offer: ${message}`); } } /** * Cancel an order onchain, preventing it from ever being fulfilled. * @param params Parameters for cancelling the order. * @param params.order The order to cancel. * @param params.accountAddress The address of the account cancelling the order. * @param params.domain The domain for the cancellation (optional). */ export async function cancelOrder(params: { order: OrderV2; accountAddress: string; domain?: string; }): Promise<void> { try { console.log(`Cancelling order for account ${params.accountAddress}`); const sdk = getOpenSeaSDK(); await sdk.cancelOrder(params); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to cancel OpenSea order: ${message}`); } } // --- API-based Service Functions --- const OPENSEA_API_BASE_URL = 'https://api.opensea.io/api/v2'; const chain = 'sei'; /** * A generic fetch handler for interacting with the OpenSea REST API. * @param endpoint The API endpoint to request (e.g., '/collections'). * @returns The JSON response from the API. */ async function fetchOpenSeaAPI(endpoint: string) { const apiKey = getOpenSeaApiKey() || ''; if (!apiKey) { console.warn('Warning: OPENSEA_API_KEY environment variable not set. API calls may be rate-limited.'); } const response = await fetch(`${OPENSEA_API_BASE_URL}${endpoint}`, { method: 'GET', headers: { 'Accept': 'application/json', 'X-API-KEY': apiKey } }); if (!response.ok) { const errorBody = await response.text(); throw new Error(`OpenSea API error! Status: ${response.status}, Body: ${errorBody}`); } return response.json(); } /** * Get an OpenSea Account Profile. * @param addressOrUsername The address or username of the account to fetch. * @returns Promise with the account profile data. */ export async function getAccount(addressOrUsername: string): Promise<any> { try { console.log(`Fetching account profile for: ${addressOrUsername}`); const endpoint = `/accounts/${addressOrUsername}`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get OpenSea account: ${message}`); } } /** * Get a smart contract for a given address on the Sei chain. * @param address The contract address. * @returns Promise with the contract details. */ export async function getContract(address: string): Promise<any> { try { console.log(`Fetching contract: ${chain}/${address}`); const endpoint = `/chain/${chain}/contract/${address}`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get OpenSea contract: ${message}`); } } /** * Get a list of OpenSea collections for the Sei chain. * @returns Promise with the collections data. */ export async function getCollections(): Promise<any> { try { console.log(`Fetching collections for chain: ${chain}`); const endpoint = `/collections?chain=${chain}`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get OpenSea collections: ${message}`); } } /** * Get stats for a single collection. * @param collectionSlug Unique string to identify a collection on OpenSea. * @returns Promise with the collection stats data. */ export async function getCollectionStats(collectionSlug: string): Promise<any> { try { console.log(`Fetching stats for collection: ${collectionSlug}`); const endpoint = `/collections/${collectionSlug}/stats`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get collection stats: ${message}`); } } /** * Get a single NFT's metadata, traits, and ownership information. * @param address The NFT contract address. * @param identifier The token ID of the NFT. * @returns The NFT details from the API. */ export async function getNFT(address: string, identifier: string): Promise<any> { try { console.log(`Fetching NFT: ${chain}/${address}/${identifier}`); const endpoint = `/chain/${chain}/contract/${address}/nfts/${identifier}`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get NFT: ${message}`); } } /** * Get NFTs owned by a given account address on the Sei chain. * @param address The account address to get NFTs for. * @returns Promise with the account's NFTs. */ export async function getNFTsByAccount(address: string): Promise<any> { try { console.log(`Fetching NFTs for account: ${address} on chain: ${chain}`); const endpoint = `/chain/${chain}/account/${address}/nfts`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get NFTs by account: ${message}`); } } /** * Get multiple NFTs for a collection. * @param collectionSlug The slug of the collection. * @returns Promise with the collection's NFTs. */ export async function getNFTsByCollection(collectionSlug: string): Promise<any> { try { console.log(`Fetching NFTs for collection: ${collectionSlug}`); const endpoint = `/collection/${collectionSlug}/nfts`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get NFTs by collection: ${message}`); } } /** * Get a list of events for an account. * @param address The account address. * @param options Optional parameters (after, before timestamps). * @returns Promise with the account's events. */ export async function getEventsByAccount(address: string, options?: { after?: number; before?: number }): Promise<any> { try { let endpoint = `/events/accounts/${address}`; if (options) { const params = new URLSearchParams(); if (options.after) params.append('after', options.after.toString()); if (options.before) params.append('before', options.before.toString()); if (params.toString()) { endpoint += `?${params.toString()}`; } } console.log(`Fetching events for account: ${address}`); return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get events by account: ${message}`); } } /** * Get a list of events for a collection. * @param collectionSlug The collection slug. * @returns Promise with the collection's events. */ export async function getEventsByCollection(collectionSlug: string): Promise<any> { try { console.log(`Fetching events for collection: ${collectionSlug}`); const endpoint = `/events/collection/${collectionSlug}`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get events by collection: ${message}`); } } /** * Get a list of events for a single NFT. * @param address The NFT contract address. * @param identifier The token ID of the NFT. * @returns Promise with the NFT's events. */ export async function getEventsByNFT(address: string, identifier: string): Promise<any> { try { console.log(`Fetching events for NFT: ${chain}/${address}/${identifier}`); const endpoint = `/events/chain/${chain}/contract/${address}/nfts/${identifier}`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get events by NFT: ${message}`); } } /** * Get the cheapest priced active, valid listings on a single collection. * @param collectionSlug Unique string to identify a collection on OpenSea. * @returns Promise with the best listings data. */ export async function getBestListingsByCollection(collectionSlug: string): Promise<any> { try { console.log(`Fetching best listings for collection: ${collectionSlug}`); const endpoint = `/listings/collection/${collectionSlug}/best`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get best listings for collection: ${message}`); } } /** * Get the best (lowest priced) listing for a single NFT. * @param collectionSlug The collection slug of the NFT. * @param identifier The token ID of the NFT. * @returns The best listing details from the API. */ export async function getBestListingForNFT(collectionSlug: string, identifier: string): Promise<any> { try { console.log(`Fetching best listing for: ${collectionSlug}/${identifier}`); const endpoint = `/listings/collection/${collectionSlug}/nfts/${identifier}/best`; return await fetchOpenSeaAPI(endpoint); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to get best listing for NFT: ${message}`); } } /** * Buys an NFT by first fetching its best listing from the API and then fulfilling the order using the SDK. * @param collectionSlug The collection slug of the NFT to buy. * @param identifier The token ID of the NFT to buy. * @param accountAddress The wallet address of the buyer. * @returns The transaction hash of the purchase. */ export async function buyNFT( collectionSlug: string, identifier: string, accountAddress: string ): Promise<string> { try { console.log(`Initiating purchase of NFT ${collectionSlug}/${identifier} for ${accountAddress}`); const listing = await getBestListingForNFT(collectionSlug, identifier); if (!listing || !listing.protocol_data) { throw new Error('No valid listing was found for this NFT.'); } const order: Order = { protocol_address: listing.protocol_address, protocol_data: listing.protocol_data, order_hash: listing.order_hash, price: listing.price, chain: Chain.Sei }; const txHash = await fulfillOrder({ order, accountAddress }); console.log(`✅ Successfully purchased NFT. Transaction hash: ${txHash}`); return txHash; } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to buy NFT: ${message}`); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/testinguser1111111/sei-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server