Creating an order

Before a user can send a transaction to pre-sign an order, they need to have tokens and appropriate approvals. This is explained in more detail in Preparing for transactions.

Before starting this tutorial, make sure you've installed Third party helpers.

Preparing fees

To create an order that will be integrated into our system, it's important that the order matches the fees that were defined by the collection's owner. To get the collection fees settings please check Get collection data.

First, we will define two helper functions to help us with arithmetics. Since Bignumbers are integers, we need to make sure we don't lose precision when computing percentages.

const FEE_PERCENTAGE_PRECISION = 6

const _scalePrecision = (value: BigNumberish): BigNumber => {
  if (typeof value === "number") {
    return BigNumber.from(value * 10 ** FEE_PERCENTAGE_PRECISION)
  } else {
    return BigNumber.from(value).mul(10 ** FEE_PERCENTAGE_PRECISION)
  }
}

export const calculateAmountWithoutFees = (
  priceWithFees: BigNumberish,
  feePercentage: BigNumberish
): BigNumber => {
  const scaledPercentage = _scalePrecision(feePercentage).div(100)
  return _scalePrecision(priceWithFees).div(
    _scalePrecision(1).add(scaledPercentage)
  )
}

const calculateFeesAmount = (
  price: BigNumberish,
  percentage: number
): string => {
  const intFeePercentage = percentage * 10 ** FEE_PERCENTAGE_PRECISION

  const feeAmount = BigNumber.from(intFeePercentage)
    .mul(price)
    .div(100)
    .div(10 ** FEE_PERCENTAGE_PRECISION)
    .toString()

  return feeAmount.toString()
}

We can then use those helpers to prepare our order fees:

  const sumOfFeesPercentages = collection.collectionFees.reduce(
    (sum, fee) => sum + fee.feePercentage,
    0
  )
  const amountWithoutFees = calculateAmountWithoutFees(
    userChosenPrice,
    sumOfFeesPercentages
  )

  const orderFees = collection.collectionFees.map((fee) => {
    return {
      amount: calculateAmountWithoutFees(amountWithoutFees, fee.feePercentage),
      recipient: fee.recipientAddress
    }
  })

Assembling the order arguments

We can use the user's ERC721 data and our marketplace ERC20 config to initialize two corresponding objects:


  const erc721Data: UserFacingERC721AssetDataSerializedV4 = {
    tokenAddress: userAsset.contractAddress,
    tokenId: userAsset.tokenId,
    type: 'ERC721'
  }

  const erc20Data: UserFacingERC20AssetDataSerializedV4 = {
    tokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
    amount: amountWithoutFees.toString(),
    type: 'ERC20'
  }

We also need an expiry date for the order:

const tomorrow = new Date()
tomorrow.setDate(tomorrow.getDate() + 1)

Sending the transaction

At this point, we have everything to call the NFT swap SDK function which will send the transaction:

  return nftSwapSdk.buildNftAndErc20Order(
    erc721Data,
    erc20Data,
    'sell',
    userAddres,
    {
      fees: orderFees,
      expiry: tomorrow,
      taker: ethers.constants.AddressZero
    }
  )

Ultimately, the NFT swap SDK calls the preSignERC721Order function from 0x.

Last updated