Create Listings

The GoTrading SDK offers robust support for efficient Bulk Listing across multiple marketplaces. This feature enables you to conveniently list multiple NFTs you own across various marketplaces in simplified operations, significantly streamlining the listing process. By automating and consolidating this process, the SDK saves you valuable time and reduces the complexity usually associated with managing listings on multiple platforms.

For Dapp Developers

List Multiple NFTs

For Dapp developers, the most straightforward approach to incorporate the NFT Bulk Listing feature into your product is detailed below. Please note, the Bulk Listing feature necessitates several stages of interaction between the user and your client-end.

1. Initialize the ListingIndexer Instance with configuration as you boot up your server-end

// Server-end code

// Init sdk client
import Web3 from 'web3';
import { initListingIndexer, NFTInfoForListing } from '@nftgo/gotrading';

const openseaApi = {
    apiKey: 'apiKey', // Replace with your own opensea api key
    requestsPerInterval: 2,
    interval: 1000,
};

const x2y2Api = {
    apiKey: 'apiKey', // Replace with your own x2y2 api key
    requestsPerInterval: 2,
    interval: 1000,
};

const config = {
  apiKey: "YOUR-API-KEY", // Replace with your own API Key.
  openSeaApiKeyConfig: openseaApi,
  x2y2ApiKeyConfig: x2y2Api,
};

// Create ListingIndexer client
const { listingIndexer } = initListingIndexer(config);

The ListingIndexer will utilize the NFTGo API Key configured here to invoke NFTGo Developer APIs, and it will use the other marketplaces' API Keys to interact with their corresponding APIs.

2. User views the NFTs he/she owns on your Dapp

3. User chooses the NFTs that he/she wants to sell

Your client-end should allow the user to toggle on the NFTs for the next step of the operation.

4. Design your own Bulk Listing Edit page for the user

You'll need to design your own bulk listing edit page, allowing users to customize listing parameters. For this feature to be minimally viable on your platform, the edit page could simply allow users to specify the List Price and Duration.

When the user completes the form and clicks the 'Confirm' button, your client-end should trigger the server-end API to obtain the steps for Bulk Listing.

Your corresponding server-end API service code should invoke ListingIndexer.prepareListing() method to get the Bulk Listing steps. This method returns the following steps of actions that require the client-end to execute.

// Server-end code

const baycAddress = '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D';

// You can define your server-end service layer function parameter
async function bulkListing(params: any) => {
    const data = await listingIndexer.prepareListing({
        listingNFTS: [ // You can construct the NFT Listing Info freely yourself
            {
                contract: baycAddress,
                tokenId: '1',
                ethPrice: 60,
                marketplace: 'OpenSea',
            },
            {
                contract: baycAddress,
                tokenId: '1',
                ethPrice: 60,
                marketplace: 'X2Y2',
            },
            {
                contract: baycAddress,
                tokenId: '2',
                ethPrice: 60,
                marketplace: 'OpenSea',
            },
            {
                contract: baycAddress,
                tokenId: '2',
                ethPrice: 60,
                marketplace: 'X2Y2',
            },
        ],
        maker: 'User Wallet Address'
    });
    
    return data;
}

5. Manage Bulk Listing Steps at Client-End

In terms of the Bulk Listing process, the user typically needs to undertake two actions:

  1. Approve the marketplaces for NFT access. This is optional if the user has already granted approval;
  2. Sign the listing orders. This information is encompassed in the data returned in the previous step. Therefore, your client-end needs to parse this data and trigger the Metamask popup to advance with the process.

So, at this stage, your client-end needs to interpret the data. Here's an example pseudo-code to illustrate this:

// Client-end code

// The approval associated data is described in index 0 of the steps array
const approvalItems = data.steps[0].items;
const provider = (globalThis as any)?.ethereum as any;
const web3 = new Web3(provider);
// Status value incomplete represents that the user 
// hasn't approved the markplace to access regarding NFT before
approvalItems.filter((item) => item.status === 'incomplete').forEach(incompleteApprovalItem => {
    const txInfo = incompleteApprovalItem.data;
    // Compose your client-side code to trigger the Metamask popup for this transaction.
    
    // https://web3js.readthedocs.io/en/v1.2.11/web3-eth.html#sendtransaction
    web3.eth.sendTransaction({
        data: txInfo.data,
        value: txInfo.value,
        from: txInfo.from,
        to: txInfo.to,
    })
    .on('transactionHash', function(hash){
      ...
    })
    .on('receipt', function(receipt){
      ...
    })
    .on('confirmation', function(confirmationNumber, receipt){ ... })
    .on('error', console.error); // If a out of gas error, the second parameter is the receipt.
});

After the user has approved these transactions and they've been recorded on the Ethereum blockchain, your client-end can prompt the user to sign the listings on Metamask.

// Client-end code
// Init ethersProvider
const ethersProvider = new ethers.providers.Web3Provider((globalThis as any)?.ethereum);
// The listings data that requires user to sign is described in index 1 of the steps array
const listingItems = data.steps[1].items;

listingItems.forEach(listingItem => {
    const signData = listingItem.data.sign;
    await signListingInfo(signData)
    const { domain, types, value } = sign;
    // Get signer from the ethersProvider 
    // https://docs.ethers.org/v5/api/signer/
    const signer = ethersProvider.getSigner(walletConfig?.address);
    let signature: string = '0x0000000000000000000000000000000000000000000000000000000000000000';
    if (signer) {
      if (sign.signatureKind === 'eip191') {
        if (sign.message?.match(/0x[0-9a-fA-F]{64}/)) {
          // If the message represents a hash, we need to convert it to raw bytes first
          signature = await signer.signMessage(arrayify(sign.message));
        } else {
          signature = await signer.signMessage(sign.message ?? '');
        }
      } else if (sign.signatureKind === 'eip712') {
        signature = await signer._signTypedData(domain, types, value);
      }
    }
    return signature;
    
});

In the next step, the user will sign the listings. After that, your client-end needs to transmit these signed listings to your server-end. The server-end will then use the GoTrading SDK to post the signed listings to the designated marketplaces. The ListingIndex.bulkPostListingOrders method will take care of the rest for you. With this, you won't need to concern yourself with handling the different API protocols of various marketplaces.

// Server-end code

async function postOrders(signedListings: any) => {
    const result = listingIndexer.bulkPostListingOrders(signedListings);
}

Complete Sequence Diagram

For NFT Market Makers

List Multiple NFTs

As an NFT Market Maker operating a Node.js server, integrating our GoTrading SDK into your platform is straightforward. The sequence diagram provided below outlines the step-by-step process, illuminating the underlying operations to ensure you have a comprehensive understanding of the integration process. By following this guide, you can seamlessly incorporate GoTrading SDK's functionality into your existing setup, enhancing your capacity for efficient NFT Bulk Listing.

The example code for NFT Bulk Listing is provided below. You can even directly copy and execute this code using the bulkListing method we've implemented to complete your task.

// Init sdk client
import Web3 from 'web3';
import { initListingIndexer, NFTInfoForListing } from '@nftgo/gotrading';

// Server
const provider = new Web3.providers.HttpProvider('https://cloudflare-eth.com/');

const openseaApi = {
  apiKey: 'apiKey', // Replace with your own api key
  requestsPerInterval: 2,
  interval: 1000,
};
// Replace with your own provider
const config = {
  apiKey: 'api key', // Replace with your own API Key.
  web3Provider: provider, // Replace with your provider,
  walletConfig: {
    address: 'Your wallet address',
    privateKey: 'Your private key',
  }, // Replace with your wallet info.
  openSeaApiKeyConfig: openseaApi,
  //   looksRareApiKeyConfig: looksrareApi,
  x2y2ApiKeyConfig: x2y2Api,
};
// Create Indexer client
const { listingIndexer } = initListingIndexer(config);

// Get the listing info of BAYC No.1
const baycContract = '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D';
const maker = '0x0000' ?? this.config.walletConfig?.address

const listingNFTS: NFTInfoForListing[] = [
  {
    contract: baycContract,
    tokenId: '1',
    ethPrice: 60,
    marketplace: 'OpenSea',
  },
  {
    contract: baycContract,
    tokenId: '2',
    ethPrice: 60,
    marketplace: 'OpenSea',
  },
  {
    contract: baycContract,
    tokenId: '2',
    ethPrice: 60,
    marketplace: 'X2Y2',
  },
];

  const bulkListing = () => {
    /**
     * Step 1: Prepare listing:
     * This function takes two parameters: a list of NFTs to be listed and the owner's address.
     * The prepareListing function returns the specific parameter details required for the subsequent steps of the process
     * such as the parameters needed for signing and posting.
     */
    const data = await listingIndexer.prepareListing(listingNFTS, maker);
    /**
     * Then, do some simple data formatting and prepare to hand it over to the next process.
     */
    const approvalData = listingIndexer.parseApprovalData(data);
    const listingData = listingIndexer.parseListingData(data);
     /**
     * Step 2: Approve Listing Item with Policy:
     * This function will authorize the approvedItems and return the final set of ListingItems.
     * Note that NFTs must be authorized before being listed, and only one authorization is required per collection per address.
     */
    const approvalResult = await listingIndexer.approveWithPolicy([approvalData, listingData]);
    /**
     * Step 3: Sign Listing Item:
     * This function takes in an array of ListingItem objects that need to be listed.
     * The user will sign these items using their configured private key, typically stored in their wallet on the client-side.
     * Once signed, the function returns an array containing two elements:
        SignedListingItem[]: the successfully signed ListingItems.
        ErrorListingItem[]: any ListingItems that failed to be signed.
    */
    const [listingResult, errorOrders] = await listingIndexer.signListingOrders(approvalResult);
    /**
     * Step 4: Post Listing Item:
     * This function will post the listing order to the target marketplace.
     * It takes as input the SignedListingItem that was previously signed in the previous step.
     * This is the final step of the listing process, where a request is made to the market API.
     * The function will return information about the final result of the listing.
     */
    const [successIndexes, errorItems] = await listingIndexer.bulkPostListingOrders(listingResult);
    const errorIndexes = [...errorOrders, ...errorItems];
  }

Complete Sequence Diagram