Ethereum's missing NFT swap library for web3 developers. Written in TypeScript. Powered by 0x.

Last update: Aug 3, 2022

NFT Swap Banner

NFT Swap SDK

_The missing NFT swap SDK for Ethereum and EVM compatible chains, powered by the 0x protocol, written in TypeScript for web3 developers.

Overview

tl;dr: NFT Swap SDK is the easiest, most-powerful NFT swap library. Supports Ethereum and EVM-compatible chains (Polygon, Avalanche, BSC, etc..). Works in both browser and node.js. Written in TypeScript, built using the 0x protocol. With this library, you can build support for NFT marketplaces or over-the-counter (OTC) exchange.

The NFT Swap SDK developed by Trader.xyz offers swap support for ERC20s, ERC721s, and ERC1155s. Exchange NFTs for NFTs, NFTs for ERC20 tokens, or bundles of NFTs and tokens. This library provides the ultimate swap flexibility combined with a simple API surface area so you can be productive immediately and focus on building your web3 app.

This library is powered and secured by the 0x v3 protocol. The 0x v3 protocol has been in production for multiple years securing billions of dollars with of trades.

Goals

We want to share all underlying technology trader.xyz uses with the community. While we won't be open-sourcing our frontend, as we think design and UX is our differentiator, we believe in open-sourcing and freely sharing all underlying technology.

Our end goal is every piece of tech you see trader.xyz use (protocol, swap libraries, open-source orderbook, order monitor, high-performance NFT indexer, property-based orders, specific React hooks, and NFT aggregation) end up open-source. This library is the first step to achieving our goal.

Installation

You can install the SDK with yarn:

yarn add @traderxyz/nft-swap-sdk

or npm:

npm install @traderxyz/nft-swap-sdk

Configuration

To use the SDK, create a new NftSwap instance.

import { NftSwap } from '@traderxyz/nft-swap-sdk';

// From your app, provide NftSwap the web3 provider or signer, and the chainId to instantiate
const nftSwapSdk = new NftSwap(providerOrSigner, chainId);

Now you're setup and ready to use the SDK in your program. Check out the examples for how to swap with the library.

Examples

Example 1: NFT <> NFT swap

In this first example, we're going to do a 1:1 NFT swap. We're going to swap User A's CryptoPunk NFT for User B's Bored Ape NFT.

Terminology: maker: Since User A will initiate the trade, we'll refer to User A as the maker of the trade.

Terminology: taker: Since User B will be filling and completing the trade created by User A, we'll refer to User B as the taker of the trade.

// Setup the sample data...
const CHAIN_ID = 1; // Chain 1 corresponds to Mainnet. Visit https://chainid.network/ for a complete list of chain ids

const CRYPTOPUNK_420 = {
  tokenAddress: '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb', // CryptoPunk contract address
  tokenId: '420', // Token Id of the CryptoPunk we want to swap
  type: 'ERC721', // Must be one of 'ERC20', 'ERC721', or 'ERC1155'
};

const BORED_APE_69 = {
  tokenAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D', // BAYC contract address
  tokenId: '69', // Token Id of the BoredApe we want to swap
  type: 'ERC721',
};

// User A Trade Data
const walletAddressUserA = '0x1eeD19957E0a81AED9a80f09a3CCEaD83Ea6D86b';
const assetsToSwapUserA = [CRYPTOPUNK_420];

// User B Trade Data
const walletAddressUserB = '0x44beA2b43600eE240AB6Cb90696048CeF32aBf1D';
const assetsToSwapUserB = [BORED_APE_69];

// ............................
// Part 1 of the trade -- User A (the 'maker') initiates an order
// ............................

// Initiate the SDK for User A.
// Pass the user's wallet signer (available via the user's wallet provider) to the Swap SDK
const nftSwapSdk = new NftSwap(signerUserA, CHAIN_ID);

// Check if we need to approve the NFT for swapping
const approvalStatusForUserA = await nftSwapSdk.loadApprovalStatus(
  assetsToSwapUserA[0],
  walletAddressUserA
);
// If we do need to approve User A's CryptoPunk for swapping, let's do that now
if (!approvalStatusForUserA.contractApproved) {
  const approvalTx = await nftSwapSdk.approveTokenOrNftByAsset(
    assetsToSwapUserA[0],
    makerAddress
  );
  const approvalTxReceipt = await approvalTx.wait();
  console.log(
    `Approved ${assetsToSwapUserA[0].tokenAddress} contract to swap with 0x (txHash: ${approvalTxReceipt.transactionHash})`
  );
}

// Create the order (Remember, User A initiates the trade, so User A creates the order)
const order = nftSwapSdk.buildOrder(
  assetsToSwapUserA,
  assetsToSwapUserB,
  walletAddressUserA
);
// Sign the order (User A signs since they are initiating the trade)
const signedOrder = await nftSwapSdk.signOrder(order, takerAddress);
// Part 1 Complete. User A is now done. Now we send the `signedOrder` to User B to complete the trade.

// ............................
// Part 2 of the trade -- User B (the 'taker') accepts and fills order from User A and completes trade
// ............................
// Initiate the SDK for User B.
// Pass the user's wallet signer (available via the user's wallet provider) to the Swap SDK
const nftSwapSdk = new NftSwap(signerUserB, CHAIN_ID);

// Check if we need to approve the NFT for swapping
const approvalStatusForUserB = await nftSwapSdk.loadApprovalStatus(
  assetsToSwapUserB[0],
  walletAddressUserB
);
// If we do need to approve NFT for swapping, let's do that now
if (!approvalStatusForUserB.contractApproved) {
  const approvalTx = await nftSwapSdk.approveTokenOrNftByAsset(
    assetsToSwapUserB[0],
    walletAddressUserB
  );
  const approvalTxReceipt = await approvalTx.wait();
  console.log(
    `Approved ${assetsToSwapUserB[0].tokenAddress} contract to swap with 0x. TxHash: ${approvalTxReceipt.transactionHash})`
  );
}
// The final step is the taker (User B) submitting the order.
// The taker approves the trade transaction and it will be submitted on the blockchain for settlement.
// Once the transaction is confirmed, the trade will be settled and cannot be reversed.
const fillTx = await nftSwapSdk.fillSignedOrder(signedOrder);
const fillTxReceipt = await nftSwapSdk.awaitTransactionHash(fillTx);
console.log(`🎉 🥳 Order filled. TxHash: ${fillTxReceipt.transactionHash}`);

Example 2: Swap bundles -- Bundle of mixed ERC721s and ERC20 <> Bundle of ERC20s

Here we show an example of what the swap library is capable of. We can even swap arbitrary ERC tokens in bundles. We call it a bundle when we have more than one item that a party will swap. Bundles can have different ERC types within the same bundle.

In other words, we can swap [ERC721, ERC1155, ERC20] <> [ERC721, ERC1155, ERC20]. There's really no limit to what we can swap.

More concrete example: We can swap [2 CryptoPunks and 1,000 DAI] for [420 WETH and 694,200 USDC]. In this case we'd be swapping an ERC721 and an ERC20 (Punk NFT and DAI, respectively) for two ERC20s (WETH and USDC).

This is just one example. In reality, you can swap as many things as you'd like, any way you'd like. The underlying 0x protocol is extremely flexible, and the NFT swap library abstracts all the complexity away so you don't have to worry about protocol nuances.

// Setup the sample data for the swap...
const CHAIN_ID = 1; // Mainnet

const CRYPTOPUNK_420 = {
  tokenAddress: '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb',
  tokenId: '420',
  type: 'ERC721',
};

const CRYPTOPUNK_421 = {
  tokenAddress: '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb',
  tokenId: '421',
  type: 'ERC721',
};

const ONE_THOUSAND_DAI = {
  tokenAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', // DAI contract address
  amount: '1000000000000000000000', // 1,000 DAI (DAI is 18 digits) -- amount to swap
  type: 'ERC20',
};

const SIXTY_NINE_USDC = {
  tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC contract address
  amount: '69000000', // 69 USDC (USDC is 6 digits)
  type: 'ERC20',
};

const FOUR_THOUSAND_TWENTY_WETH = {
  tokenAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', // WETH contract address
  amount: '420000000000000000000', // 420 Wrapped-ETH (WETH is 18 digits)
  type: 'ERC20',
};

// User A Trade Data
const walletAddressUserA = '0x1eeD19957E0a81AED9a80f09a3CCEaD83Ea6D86b';
const assetsToSwapUserA = [CRYPTOPUNK_420, CRYPTOPUNK_421, ONE_THOUSAND_DAI];

// User B Trade Data
const walletAddressUserB = '0x44beA2b43600eE240AB6Cb90696048CeF32aBf1D';
const assetsToSwapUserB = [SIXTY_NINE_USDC, FOUR_THOUSAND_TWENTY_WETH];

// ............................
// Part 1 of the trade -- User A (the 'maker') initiates an order
// ............................
const nftSwapSdk = new NftSwap(signerUserA, CHAIN_ID);
// Note: For brevity, we assume all assets are approved for swap in this example.
// See previous example on how to approve an asset.

const order = nftSwapSdk.buildOrder(
  assetsToSwapUserA,
  assetsToSwapUserB,
  walletAddressUserA
);
const signedOrder = await nftSwapSdk.signOrder(order, takerAddress);

// ............................
// Part 2 of the trade -- User B (the 'taker') accepts and fills order from User A and completes trade
// ............................
const nftSwapSdk = new NftSwap(signerUserB, CHAIN_ID);

const fillTx = await nftSwapSdk.fillSignedOrder(signedOrder);
const fillTxReceipt = await nftSwapSdk.awaitTransactionHash(fillTx);
console.log(`🎉 🥳 Order filled. TxHash: ${fillTxReceipt.transactionHash}`);

// Not so bad, right? We can arbitrarily add more assets to our swap without introducing additional complexity!

Example 3: React Hooks + Swap SDK

In this example, we'll leverage the amazing web3-react React Hook library.

const App = () => {
  const { library, chainId } = useWeb3React();

  const [swapSdk, setSwapSdk] = useState(null);
  useEffect(() => {
    const sdk = new NftSwap(library.getSigner(), chainId);
    setSwapSdk(sdk);
  }, [library, chainId])

  // Use the SDK however you'd like in the app...
  const handleClick = useCallback(() => {
    if (!swapSdk) {
      return;
    }
    swapSdk.buildOrder(...)
  }, [swapSdk])

  // ...
}

FAQ

  • Which ERCs does this library support

    • ERC20, ERC721, and ERC1155
  • What EVM chains are currently supported?

    • Mainnet (1)
    • Kovan (42)
    • Rinkeby (4)
    • Polygon (137)
    • Binance Smart Chain (56)
    • Avalance (43114)
  • What protocol does this library?

    • trader.xyz and trader.xyz libraries are powered by 0x v3 Protocol. This protocol is mature and lindy, and has been extremely well-audited.
    • Check out the 0x v3 spec here
    • Check out the 0x v3 Consensys audit here
  • Are there any protocol fees to execute swaps?

    • No
  • How do I get the user's signer object?

    • Generally you can get it from the user's web3 wallet provider, by something like this: provider.getSigner().
    • See this ethers guide (control-f for getSigner).
    • In web3-react you can do:
      • const { library } = useWeb3React();
      • const signer = library.getSigner();
  • How do I store a SignedOrder

    • That's up to you. This library has no opinions on how to store orders. You can throw them in a centralized SQL database, save them to localstorage, use a decentralized messaging solution -- it's really up to you and your app concerns. You can even serialize and compress an order to fit in a tweet or shareable URL! 🤯

Roadmap

We're currently working on the following features for the next iteration of this library

  • Persistent data store of orders (off-the-shelf storage in trader.xyz's public order storage server). Think of it as a public good
  • Property-based orders
  • Order validation
  • Live order status
  • Order event streaming via websockets

If you have feature requests, reach out in our Discord.

We want to make this library a one-stop shop for all your NFT swapping needs.

  • We're also moving off of @0x/* libraries due to the payload size of these packages.

GitHub

https://github.com/trader-xyz/nft-swap-sdk
Comments
  • 1. verifyOrderSignature always returns false !

    Hey Guys.

    trying to verify an order on Polygon swapSDK v3

    I am passing 0x0c58c1170f1ded633862a1166f52107490a9c594 as the exchange contract address. Chain ID as 137

    I keep getting false even though the swap goes through. seems to be an issue.

    Reviewed by rahuldamodar94 at 2022-03-11 22:37
  • 2. Add Ubiq support to 0x v4. Chain ID 8

    Deployed and configured the following.

    deploying "InitialMigration" (tx: 0x67ae19bfa08cc0328e1b9d8a5488cf8ef0997aa9de27dd477c3cd10c38aaa120)...: deployed at 0x5b957E61FF15863c29B69da1c1172baBB044c728 with 620174 gas
    deploying "ZeroEx" (tx: 0xa124fd7dbb970e4aa849a69b710103cac00a85830052e9d6937678ab663e5503)...: deployed at 0x19aaD856cE8c4C7e813233b21d56dA97796cC052 with 755195 gas
    deploying "ERC721OrdersFeature" (tx: 0x7d66b56f180a5c664e027a8e623820463d568fdcaac6db3f2396b182989c9ddf)...: deployed at 0x7AE76139C07099FD77F5100af73871ec367Ca808 with 4728224 gas
    deploying "ERC1155OrdersFeature" (tx: 0x44e098dbc98c4295526de1064ace1c7a557100ac52f0b98824ef01c488404f6f)...: deployed at 0x5e850FC7104d1843957627c5028020faB1fd09dD with 4313656 gas
    deploying "OtcOrdersFeature" (tx: 0x622222b8c1e23181ed8672501c3dec941abf8c85095a724e6373ea7253beacf9)...: deployed at 0x27548434B9b5dF3EF60fb1ec289CaABBA6B4fe2A with 2524104 gas
    deploying "ERC165Feature" (tx: 0x53f1151d456cbdc1e957babda3952105096e537015a19d4efb8d8c52464b6774)...: deployed at 0x71d56d94261086bFfa3D5f97c2043cD7E1a87afb with 210133 gas
    deploying "SimpleFunctionRegistryFeature" (tx: 0x50976cb462af877eaf96a6e1eb1bec7ae6d96e22d7ff4091c5673eb481b89e74)...: deployed at 0xC1Ab827a823d17D9db77fdF4D61809F0391B9050 with 773300 gas
    deploying "OwnableFeature" (tx: 0x42eb9017396e78baccec288b68a8c444ab5632ec0d216762d511d92fa88e0270)...: deployed at 0x3956FB6BDFcb81c12b3B965DEC05B4012f4Be6DD with 758315 gas
    
    executing InitialMigration.initializeZeroEx (tx: 0x1568e6e62c8d2d7662d33def2f1677281ad0b87b56e057aeaf6204bd7436600a) ...: performed with 445304 gas
    executing ERC165Feature extend (tx: 0x376aeeab485ad5ee1e7de6109c6218aea370dcf7f4520501878248a0a6881091)
    executing ERC721OrdersFeature migrate (tx: 0x83223933804071f3bdbc942740373221a28f896426cf0fcf1ed40a2d908b41c1)
    executing ERC1155OrdersFeature migrate (tx: 0x88a4a6933104274f8ba5a3830fc3cb500106d1f8f844d207bdb801dc389468ef)
    executing OtcOrdersFeature migrate (tx: 0xaacb1d507a6e1a426f50a275ce6da09b038bd7c942066a736122c33cadbe643d)
    

    Waiting for https://sourcify.dev to be up to Verify the contract source there.

    Thanks!

    Reviewed by jyap808 at 2022-05-23 05:39
  • 3. Fixes V3 verifyOrderSignature signature to validate correctly

    Sometimes (just due to how signatures are derived between 0x orders and other standards), signatures would not validate successfully when calling verifyOrderSignature. This fixes that to use a standard way of deriving a signature that can be passed to verify the typed data (since you can't pass a 0x order signature directly to a verifyTypedData signature)

    Reviewed by johnrjj at 2022-03-12 04:15
  • 4. Adds support to batch buy NFTs

    e.g. shopping cart functionality, buy multiple ERC721 or ERC1155s in one tx

    const fillTx = await nftSwap.batchBuyNfts([
      signedNftSellOrder1,
      signedNftSellOrder2,
    ]);
    
    Reviewed by johnrjj at 2022-05-19 02:07
  • 5. Orderbook Allowance Error

    I've using the sdk for a couple of days.

    Today I started to get an error after call the "postOrder" method:

    {errorCode: "INSUFFICIENT_MAKER_ALLOWANCE",…} errorCode: "INSUFFICIENT_MAKER_ALLOWANCE" errorMessage: "Maker does not have sufficient allowance of 0xc778417e063141139fce010982780140aa0cd5ab (ERC20)"

    Reviewed by aecdanjundex at 2022-05-13 12:31
  • 6. Adds support for integrator attribution

    Adds support for integrator attribution, so dune dashboards etc can attribute volume to an integrator.

    Opt-in by default, of course

    Uses the 256bit nonce, divides it into a [128bit attribution][128bit random nonce for order], and that will be the canonical 0x v4 standard schema for nonces.

    To add an app identifier to your app, instantiate the sdk with a unique positive integer (up to 2**126 -1)

    const nftSwap = new NftSwapV4(
      provider,
      signer,
      chainId,
      { appId: '69420' },
    )
    
    Reviewed by johnrjj at 2022-04-21 01:31
  • 7. Adds unit tests for invalid orders attempting to post to orderbook

    Open orderbook now rejects order unless they meet certain criteria of validity (e.g. maker has sufficient balance of maker asset, maker approval in order, tokens are valid, signature valid). This adds tests around those invalid orders to ensure the orderbook is providing the correct error codes to the end-user SDK.

    Reviewed by johnrjj at 2022-04-06 04:28
  • 8. Order validation helper functions for v4

    Sharing useful logic on how to validate orders since this exists on the API side.

    Basically check either (or both) the maker and taker assets for: a) wallet has sufficient balance b) asset being traded is approved 0x v4 exchange proxy contract (everything except ETH requires approval*)

    *unless using super secret fillBuyNftOrderWithoutApproval function, then you don't need to approve your NFT to accept a bid on it lol

    Reviewed by johnrjj at 2022-03-25 05:21
  • 9. Add validation guardrails around trying to bid with native token

    Bids for NFTs cannot technically be bid in native token (e.g. ETH) and need to use wrapped token (e.g. WETH) (since ETH cannot be moved via smart contracts like an ERC20).

    Fills can still be filled in ETH (and the bid WETH can be converted just-in-time during fill to ETH).

    Reviewed by johnrjj at 2022-03-24 17:54
  • 10. MetaTx support on swap-sdk

    Can we the meta tx functionality in the swap sdk ? Like this -> https://github.com/0xProject/0x-starter-project/blob/master/src/scenarios/execute_metatransaction_fill_rfq_order.ts#L121-L153

    This would be really helpful for those who wish to setup gasless swaps using swap sdk. Currently developers can't make use of swap sdk to enable 0x meta tx gasless swaps.

    Reviewed by rahuldamodar94 at 2022-07-21 15:31
  • 11. SDK ready for v1.0.0

    SDK seems stable enough to release a 1.0.0.

    That way we can start semantically verisoning any changes, since we have a good bit of integrators using the sdk now!

    Reviewed by johnrjj at 2022-04-27 21:49
React-NFT-App - NFT-Web-Application built using Third web , ReactJs and use Crypto Punks with API

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Apr 25, 2022
Cheatsheets for experienced React developers getting started with TypeScript
Cheatsheets for experienced React developers getting started with TypeScript

Cheatsheets for experienced React developers getting started with TypeScript

Jul 31, 2022
React People lists and connects React developers around the world.

React People React People lists and connects React developers around the world. Progress View the Project page for details on what's planned and what'

Jun 14, 2022
_buildspace - web3 Read/Write Solana Blockchain Project
_buildspace - web3 Read/Write Solana Blockchain Project

_buildspace - web3 Read/Write Solana Blockchain Project

Feb 5, 2022
Gif Portal build using solana, anchor, web3 and react

Features of the dapp View Popular Dance Moves Gifs Vote for your favorite Gifs Add link of your favorite dance gif on the portal All the data includin

May 14, 2022
Create a Web3 Forum with Polygon

Create a Web3 Forum with Polygon Tutorial Details Today we're going to build together a fullstack decentralized forum that can be used in any dapp. Se

Jul 29, 2022
Tsnip.nvim - Plugin to expand snippets written in Pure TypeScript(Deno)

tsnip.nvim Plugin to expand snippets written in Pure TypeScript(Deno). This plug

Jan 28, 2022
How to mint your own NFT token with react
How to mint your own NFT token with react

Mint your own basic off chain NFT Description This project teaches you how to mint your own NFT token. Here are some important packages that we will b

May 17, 2022
Youtube Tutorial showcasing how to create a fullstack NFT mingint dapp.
Youtube Tutorial showcasing how to create a fullstack NFT mingint dapp.

Emoji Faces NFT Minting dApp This a complete example of fullstack NFT minting dApp. EmojiFaces is built with the purpose of providing an entry point f

Jul 4, 2022
This is used for minting NFTs and getting metadata , token owner, wallet address assigned to an NFT, just check it out and enjoy

nft-minter A Heroku web server to easily mint non-fungible tokens via an API Example Configuration: Blockchain: Ethereum Testnet: Rinkeby Contract: ER

Apr 17, 2022
Ethereum nft marketplace template using react

ethereum-marketplace-template ⭐️ Star us If this boilerplate helps you build Ethereum dapps faster - please star this project, every star makes us ver

Jul 21, 2022
This Project is a fork of Ethereum Boilerplate and demonstrates how you can build your own NFT Rarity Ranker.
This Project is a fork of Ethereum Boilerplate and demonstrates how you can build your own NFT Rarity Ranker.

This Project is a fork of Ethereum Boilerplate and demonstrates how you can build your own NFT Rarity Ranker.

Aug 7, 2022
This is a proof of concept of an NFT vending machine built using Solana Pay, Metaplex, Phantom Mobile, and Next.js

Solana NFT Vending Machine This is a proof of concept of an NFT vending machine built using Solana Pay, Metaplex, Phantom Mobile, and Next.js. This wa

Jul 4, 2022
A comments system powered by GitHub Discussions.
A comments system powered by GitHub Discussions.

A comments system powered by GitHub Discussions. Let visitors leave comments and reactions on your website via GitHub! Heavily inspired by utterances.

Aug 6, 2022
(Optional) First challenge on ignite ReactJS powered by Rocketseat
(Optional) First challenge on ignite ReactJS powered by Rocketseat

Segundo desafio da trilha de React do Ignite da Rocketseat. O projeto consiste em listar filmes de uma API fake, utilizando o JSON Server. ?? Conteúdo

Feb 7, 2022
Isomorphic application written in React
Isomorphic application written in React

Isomorphic "Quiz Wall" for itsquiz.com Motivation There are a lot of tutorials and boilerplates showing how to write isomorphic ReactJs applications.

Jun 9, 2022
Implementation of WebAuthn API written in React and Express

Simple WebAuthn demo Implementation of WebAuthn API written in React and Express. Demo that shows the future of passwordless authentication. Users reg

May 24, 2022
An algebraic effects library for javascript and typescript using generators

Algebraify Algebraic Effects Are Here! (sort of) (If you're unfamiliar with algebraic effects, here's a great article: Algebraic Effects for the Rest

Jul 3, 2022
A React library to show an administrative UI for the Mock Service Worker JS library
A React library to show an administrative UI for the Mock Service Worker JS library

A React library to show an administrative UI for the Mock Service Worker JS library

May 27, 2022