Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
opensea-js
Advanced tools
JavaScript SDK for the OpenSea marketplace. Let users buy or sell crypto collectibles and other cryptogoods, all on your own site!
A JavaScript library for crypto-native ecommerce: buying, selling, and bidding on any cryptogood. With OpenSea JS, you can easily build your own native marketplace for your ERC721 items without having to deploy your own smart contracts or backend orderbooks. GitHub | npm
This is the JavaScript SDK for OpenSea, the largest marketplace for crypto collectibles. It allows developers to access the official orderbook, filter it, create buy orders (offers), create sell orders (auctions), create collections of assets to sell at once (bundles), and complete trades programmatically.
For the first time, you can build a cryptocommerce dapp.
You get started by instantiating your own seaport. Then you can create orders off-chain or fulfill orders on-chain, and listen to events (like ApproveAllAssets
or WrapEth
) in the process.
Happy seafaring! ⛵️
We recommend switching to Node.js version 8.11 to make sure common crypto dependencies work. Execute nvm use
, if you have Node Version Manager.
Then, in your project, run:
npm install --save opensea-js
Install web3 too if you haven't already.
To get started, create a new OpenSeaJS client, called an OpenSeaPort 🚢, using your Web3 provider:
import * as Web3 from 'web3'
import { OpenSeaPort, Network } from 'opensea-js'
const provider = new Web3.providers.HttpProvider('https://mainnet.infura.io')
const seaport = new OpenSeaPort(provider, {
networkName: Network.Main
})
Then, you can do this to make an offer on an asset:
// An expirationTime of 0 means it will never expire
const offer = await seaport.createBuyOrder({ tokenId, tokenAddress, accountAddress, startAmount, expirationTime: 0 })
When you make an offer on an item owned by an OpenSea user, that user will automatically get an email notifying them with the offer amount, if it's above their desired threshold.
To sell an asset, call createSellOrder
. You can do a fixed-price sale, where startAmount
is equal to endAmount
, or a declining Dutch auction, where endAmount
is lower and the price declines until expirationTime
is hit:
// Expire this auction one day from now
const expirationTime = (Date.now() / 1000 + 60 * 60 * 24)
// If `endAmount` is specified, the order will decline in value to that amount until `expirationTime`. Otherwise, it's a fixed-price order.
const auction = await seaport.createSellOrder({ tokenId, tokenAddress, accountAddress, startAmount, endAmount, expirationTime })
The units for startAmount
and endAmount
are Ether, ETH. If you want to specify another ERC-20 token to use, see Using ERC-20 Tokens Instead of Ether.
See Listening to Events to respond to the setup transactions that occur the first time a user sells an item.
You can now sell items to users without having to pay gas to mint them!
To create a presale or crowdsale and create batches of sell orders for a single asset factory, first follow the tutorial for creating your crowdsale contract.
Then call createFactorySellOrders
with your factory contract address and asset option identifier, and set numberOfOrders
to the number of assets you'd like to let users buy and mint:
// Expire these auctions one day from now
const expirationTime = (Date.now() / 1000 + 60 * 60 * 24)
const sellOrders = await seaport.createFactorySellOrders({
assetId: ASSET_OPTION_ID,
factoryAddress: FACTORY_CONTRACT_ADDRESS,
accountAddress, startAmount, endAmount, expirationTime,
numberOfOrders: 100 // Will create 100 sell orders in parallel batches of 10, to speed things up
})
Here's an example script you can use to mint items.
NOTE: If numberOfOrders
is greater than 5, we will automatically batch them in groups of 5 so you can post orders in parallel. Requires an apiKey
to be set during seaport initialization in order to not be throttled by the API.
Games using this method include Coins & Steel and a couple in stealth :) If you have questions or want support, contact us at contact@opensea.io (or in Discord).
To retrieve a list of offers and auction on an asset, you can use an instance of the OpenSeaAPI
exposed on the client. Parameters passed into API filter objects are underscored instead of camel-cased, similar to the main OpenSea API parameters:
import { OrderSide } from 'opensea-js/lib/types'
// Get offers (bids), a.k.a. orders where `side == 0`
const { orders, count } = await seaport.api.getOrders({
asset_contract_address: tokenAddress,
token_id: token_id,
side: OrderSide.Buy
})
// Get page 2 of all auctions, a.k.a. orders where `side == 1`
const { orders, count } = await seaport.api.getOrders({
asset_contract_address: tokenAddress,
token_id: token_id,
side: OrderSide.Sell
}, 2)
Note that the listing price of an asset is equal to the currentPrice
of the lowest valid sell order on the asset. Users can lower their listing price without invalidating previous sell orders, so all get shipped down until they're cancelled or one is fulfilled.
The available API filters for the orders endpoint is documented in the OrderJSON
interface:
/**
* Attrs used by orderbook to make queries easier
* More to come soon!
*/
maker?: string, // Address of the order's creator
taker?: string, // The null address if anyone is allowed to take the order
side?: OrderSide, // 0 for offers, 1 for auctions
owner?: string, // Address of owner of the order's asset
sale_kind?: SaleKind, // 0 for fixed-price, 1 for Dutch auctions
asset_contract_address?: string, // Contract address for order's asset
token_id?: number | string,
token_ids?: Array<number | string>,
listed_after?: number | string, // This means listing_time > value in seconds
listed_before?: number | string, // This means listing_time <= value in seconds
// For pagination
limit?: number,
offset?: number,
To buy an item , you need to fulfill a sell order. To do that, it's just one call:
const order = await seaport.api.getOrder({ side: OrderSide.Sell, ... })
const accountAddress = "0x..." // The buyer's wallet address, also the taker
await this.props.seaport.fulfillOrder({ order, accountAddress })
If the order is a sell order (order.side === OrderSide.Sell
), the taker is the buyer and this will prompt the buyer to pay for the item(s).
Similar to fulfilling sell orders above, you need to fulfill a buy order on an item you own to receive the tokens in the offer.
const order = await seaport.api.getOrder({ side: OrderSide.Buy, ... })
const accountAddress = "0x..." // The owner's wallet address, also the taker
await this.props.seaport.fulfillOrder({ order, accountAddress })
If the order is a buy order (order.side === OrderSide.Buy
), then the taker is the owner and this will prompt the owner to exchange their item(s) for whatever is being offered in return. See Listening to Events below to respond to the setup transactions that occur the first time a user accepts a bid.
Interested in making an affiliate program, bundling items together, or making bids in different ERC-20 tokens? OpenSea.js can help with that.
NOTE: This feature is in beta.
You can instantly create an affiliate program for your assets by just passing in one more parameter when fulfilling orders! Whenever someone refers a sale or the acceptance of an offer, you can add a referrerAddress
to give their wallet credit:
const referrerAddress = "0x..." // The referrer's wallet address
await this.props.seaport.fulfillOrder({ order, accountAddress, referrerAddress })
This works for buying assets and bundles, along with accepting bids!
OpenSea will send the referrer 1% of the item's sale price. Soon, if you've customized your fees using the storefront editor, you'll be able to set an amount that you can send referrers as well.
More information will appear here when our redesigned affiliate program is ready. In the meantime, contact us at contact@opensea.io (or in Discord), or use our legacy affiliate program at https://opensea.io/account#referrals.
New in version 0.2.9, you can create bundles of assets to sell at the same time! If the owner has approved all the assets in the bundle already, only a signature is needed to create it.
To make a bundle, it's just one call:
const assets: Array<{tokenId: string; tokenAddress: string}> = [...]
const bundle = await seaport.createBundleSellOrder({
bundleName, bundleDescription, bundleExternalLink, assets, accountAddress, startAmount, endAmount, expirationTime, paymentTokenAddress
})
The parameters bundleDescription
, bundleExternalLink
, and expirationTime
are optional, and endAmount
can equal startAmount
, similar to the normal createSellOrder
functionality.
The parameter paymentTokenAddress
is the address of the ERC-20 token to accept in return. If it's undefined
or null
, the amount is assumed to be in Ether.
Wait what, you can use other currencies than ETH?
New in version 0.3: now you can make auctions and offers in whatever ERC-20 token you want! Just specify the token's contract address as the paymentTokenAddress
when creating the order.
Here's an example of listing the Genesis CryptoKitty for $100! No more needing to worry about the exchange rate:
// Token address for the DAI stablecoin, which is pegged to $1 USD
const paymentTokenAddress = "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"
// The units for `startAmount` and `endAmount` are now in DAI, so $100 USD
const auction = await seaport.createSellOrder({
tokenAddress: "0x06012c8cf97bead5deae237070f9587f8e7a266d", // CryptoKitties
tokenId: "1", // Token ID
accountAddress: OWNERS_WALLET_ADDRESS,
startAmount: 100,
expirationTime: 0,
paymentTokenAddress
})
You can use getFungibleTokens
to search for tokens by symbol name. And you can even list all orders for a specific ERC-20 token by querying the API:
const token = await seaport.getFungibleTokens({ symbol: 'MANA'})[0]
const order = await seaport.api.getOrders({
side: OrderSide.Sell,
payment_token_address: token.address
})
Fun note: all ERC-20 tokens are allowed! This means you can create crazy offers on crypto collectibles using your own ERC-20 token. However, opensea.io will only display offers and auctions in ERC-20 tokens that it knows about, optimizing the user experience of order takers. Orders made with the following tokens will be shown on OpenSea for the near future:
We share fees for successful sales with game developers, relayers, and affiliates using the OpenSea orderbook. Developers can customize the fee amount to apply to buyers and/or sellers.
See Affiliate Program above for how to register referrers for sales.
More information will appear here when our redesigned affiliate program is ready. In the meantime, contact us at contact@opensea.io (or in Discord), or use our legacy affiliate program at https://opensea.io/account#referrals.
Events are fired whenever transactions or orders are being created, and when transactions return receipts from recently mined blocks on the Ethereum blockchain.
Our recommendation is that you "forward" OpenSea events to your own store or state management system. Here's an example of doing that with a Redux action:
import { EventType } from 'opensea-js'
import * as ActionTypes from './index'
import { openSeaPort } from '../globalSingletons'
// ...
handleSeaportEvents() {
return async function(dispatch, getState) {
openSeaPort.addListener(EventType.TransactionCreated, ({ transactionHash, event }) => {
console.info({ transactionHash, event })
dispatch({ type: ActionTypes.SET_PENDING_TRANSACTION_HASH, hash: transactionHash })
})
openSeaPort.addListener(EventType.TransactionConfirmed, ({ transactionHash, event }) => {
console.info({ transactionHash, event })
// Only reset your exchange UI if we're finishing an order fulfillment or cancellation
if (event == EventType.MatchOrders || event == EventType.CancelOrder) {
dispatch({ type: ActionTypes.RESET_EXCHANGE })
}
})
openSeaPort.addListener(EventType.TransactionDenied, ({ transactionHash, event }) => {
console.info({ transactionHash, event })
dispatch({ type: ActionTypes.RESET_EXCHANGE })
})
openSeaPort.addListener(EventType.TransactionFailed, ({ transactionHash, event }) => {
console.info({ transactionHash, event })
dispatch({ type: ActionTypes.RESET_EXCHANGE })
})
openSeaPort.addListener(EventType.InitializeAccount, ({ accountAddress }) => {
console.info({ accountAddress })
dispatch({ type: ActionTypes.INITIALIZE_PROXY })
})
openSeaPort.addListener(EventType.WrapEth, ({ accountAddress, amount }) => {
console.info({ accountAddress, amount })
dispatch({ type: ActionTypes.WRAP_ETH })
})
openSeaPort.addListener(EventType.UnwrapWeth, ({ accountAddress, amount }) => {
console.info({ accountAddress, amount })
dispatch({ type: ActionTypes.UNWRAP_WETH })
})
openSeaPort.addListener(EventType.ApproveCurrency, ({ accountAddress, tokenAddress }) => {
console.info({ accountAddress, tokenAddress })
dispatch({ type: ActionTypes.APPROVE_WETH })
})
openSeaPort.addListener(EventType.ApproveAllAssets, ({ accountAddress, proxyAddress, tokenAddress }) => {
console.info({ accountAddress, proxyAddress, tokenAddress })
dispatch({ type: ActionTypes.APPROVE_ALL_ASSETS })
})
openSeaPort.addListener(EventType.ApproveAsset, ({ accountAddress, proxyAddress, tokenAddress, tokenId }) => {
console.info({ accountAddress, proxyAddress, tokenAddress, tokenId })
dispatch({ type: ActionTypes.APPROVE_ASSET })
})
openSeaPort.addListener(EventType.CreateOrder, ({ order, accountAddress }) => {
console.info({ order, accountAddress })
dispatch({ type: ActionTypes.CREATE_ORDER })
})
openSeaPort.addListener(EventType.OrderDenied, ({ order, accountAddress }) => {
console.info({ order, accountAddress })
dispatch({ type: ActionTypes.RESET_EXCHANGE })
})
openSeaPort.addListener(EventType.MatchOrders, ({ buy, sell, accountAddress }) => {
console.info({ buy, sell, accountAddress })
dispatch({ type: ActionTypes.FULFILL_ORDER })
})
openSeaPort.addListener(EventType.CancelOrder, ({ order, accountAddress }) => {
console.info({ order, accountAddress })
dispatch({ type: ActionTypes.CANCEL_ORDER })
})
}
}
To remove all listeners and start over, just call seaport.removeAllListeners()
.
Auto-generated documentation for each export is available here.
If you need extra help, support is free! Contact the OpenSea devs. They're available every day on Discord in the #developers
channel.
Check out the Ship's Log, built with the SDK, which shows the recent orders in the OpenSea orderbook.
You can view a live demo here! Also check out the Mythereum marketplace, which is entirely powered by OpenSea.js.
Setup
Node >= v8.11.2 required.
Before any development, install the required NPM dependencies:
npm install
Build
Then, lint and build the library into the lib
directory:
npm run build
Or run the tests:
npm test
Note that the tests require access to both Infura and the OpenSea API. The timeout is adjustable via the test
script in package.json
.
Generate Documentation
Generate html docs, also available for browsing here:
npm run docsHtml
Or generate markdown docs available for browsing on git repos:
npm run docsMarkdown
Due to a markdown theme typescript issue, docs
just generates html docs right now:
npm run docs
Contributing
Contributions welcome! Please use GitHub issues for suggestions/concerns - if you prefer to express your intentions in code, feel free to submit a pull request.
FAQs
TypeScript SDK for the OpenSea marketplace helps developers build new experiences using NFTs and our marketplace data
The npm package opensea-js receives a total of 1,485 weekly downloads. As such, opensea-js popularity was classified as popular.
We found that opensea-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.