Integrating the Bazaar

Interacting with the Bazaar Contracts

List and trade NFTs

The Bazaar is a router for several smart contracts that allow users to list and trade NFTs.

This guide provides examples on how to interact with the Bazaar through your own custom interface. The guide includes detailed code examples with the use of wagmi and viem for ethereum interactions.

Prerequisites

Before proceeding, ensure your development environment is set up with the necessary libraries:

  • wagmi: A collection of React Hooks simplifying Ethereum blockchain interactions.

  • viem: A utility library for Ethereum address and transaction management.

Deployed Contracts

BAZAAR CONTRACT

Mainnet: 0x6D7c44773C52D396F43c2D511B81aa168E9a7a42

Sepolia: 0xC8Edc7049b233641ad3723D6C60019D1c8771612

Install Dependencies

Begin by adding the required libraries to your project. Execute the following commands in your terminal:

Using npm:

npm install wagmi viem

Listing

There are many components required in order to set a sale price on an NFT with the Bazaar.

originContract // The token contract address
currencyAddress // Must be either the NULL address for ETH, or $RARE token address.
target // Specify an address that is allowed to purchase.
amount // The price of the NFT in currency units.
tokenId // The token number of the NFT to list.
splitRecipients // A list of addresses to each receive a portion of the sale price.
splitRatios // A list of ratios for each recipient to receive a portion of the sale price.

splitRecipients and splitRatios must be the same length and the ratios must add up to 100. for example:

splitRecipients = [address1, address2, address3]
splitRatios = [10, 20, 70]

The amount should not include the 3% network fee. That will be added automatically by the contract when a sale is made.

import { useState } from 'react'
import { Address, parseEther } from 'viem'
import { useWriteContract } from 'wagmi'

const abi = [
  {
    type: 'function',
    name: 'setSalePrice',
    inputs: [
      {
        name: '_originContract',
        type: 'address',
        internalType: 'address',
      },
      { name: '_tokenId', type: 'uint256', internalType: 'uint256' },
      {
        name: '_currencyAddress',
        type: 'address',
        internalType: 'address',
      },
      { name: '_listPrice', type: 'uint256', internalType: 'uint256' },
      { name: '_target', type: 'address', internalType: 'address' },
      {
        name: '_splitAddresses',
        type: 'address[]',
        internalType: 'address payable[]',
      },
      { name: '_splitRatios', type: 'uint8[]', internalType: 'uint8[]' },
    ],
    outputs: [],
    stateMutability: 'nonpayable',
  },
] as const

// The address of the bazaar contract
const bazaarAddress = '0x6D7c44773C52D396F43c2D511B81aa168E9a7a42' as Address

function ListForSaleComponent() {
  const [contractAddress, setContractAddress] = useState('')
  const [tokenId, setTokenId] = useState('')
  const [currencyAddress, setCurrencyAddress] = useState('')
  const [listPrice, setListPrice] = useState('')
  const [target, setTarget] = useState('')
  const [splitAddresses, setSplitAddresses] = useState('')
  const [splitRatios, setSplitRatios] = useState('')
  const { writeContract } = useWriteContract()

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault() // Prevent the form from submitting in the traditional way

    const parsedSplitAddresses = splitAddresses.split(',').map((address) => address.trim())
    const parsedSplitRatios = splitRatios.split(',').map((ratio) => parseInt(ratio))

    writeContract({
      abi: abi,
      address: bazaarAddress,
      functionName: 'setSalePrice',
      args: [
        contractAddress as Address,
        BigInt(tokenId),
        currencyAddress as Address,
        parseEther(listPrice),
        target as Address,
        parsedSplitAddresses as Address[],
        parsedSplitRatios,
      ],
    })
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="contractAddress">Contract Address:</label>
        <input
          id="contractAddress"
          type="text"
          value={contractAddress}
          onChange={(e) => setContractAddress(e.target.value)}
          placeholder="Enter token contract address"
          required
        />
      </div>

      <div>
        <label htmlFor="tokenId">Token ID:</label>
        <input
          id="tokenId"
          type="text"
          value={tokenId}
          onChange={(e) => setTokenId(e.target.value)}
          placeholder="Enter token ID"
          required
        />
      </div>

      <div>
        <label htmlFor="currencyAddress">Currency Address:</label>
        <input
          id="currencyAddress"
          type="text"
          value={currencyAddress}
          onChange={(e) => setCurrencyAddress(e.target.value)}
          placeholder="Enter currency address"
          required
        />
      </div>

      <div>
        <label htmlFor="listPrice">List Price:</label>
        <input
          id="listPrice"
          type="text"
          value={listPrice}
          onChange={(e) => setListPrice(e.target.value)}
          placeholder="Enter list price"
          required
        />
      </div>

      <div>
        <label htmlFor="target">Target Address:</label>
        <input
          id="target"
          type="text"
          value={target}
          onChange={(e) => setTarget(e.target.value)}
          placeholder="Enter target address"
          required
        />
      </div>

      <div>
        <label htmlFor="splitAddresses">Split Addresses:</label>
        <input
          id="splitAddresses"
          type="text"
          value={splitAddresses}
          onChange={(e) => setSplitAddresses(e.target.value)}
          placeholder="Enter split addresses separated by commas"
          required
        />
      </div>

      <div>
        <label htmlFor="splitRatios">Split Ratios:</label>
        <input
          id="splitRatios"
          type="text"
          value={splitRatios}
          onChange={(e) => setSplitRatios(e.target.value)}
          placeholder="Enter split ratios separated by commas"
          required
        />
      </div>

      <button type="submit">List token</button>
    </form>
  )
}

Buying

To buy an NFT from the Bazaar, you need to call the buy function on the Bazaar contract. The NFT must have a sale price set and the buyer must have the required currency to purchase the NFT.

originContract // The token contract address
tokenId // The token number of the NFT to buy.
currencyAddress // Must be either the NULL address for ETH, or $RARE token address.
amount // The price of the NFT in currency units.

Like when setting the sale price, the amount should not include the 3% network fee. That will be added automatically by the contract when a sale is made.

import { useState } from 'react'
import { Address, parseEther } from 'viem'
import { useWriteContract } from 'wagmi'

const abi = [
  {
    type: 'function',
    name: 'buy',
    inputs: [
      { name: '_originContract', type: 'address', internalType: 'address' },
      { name: '_tokenId', type: 'uint256', internalType: 'uint256' },
      { name: '_currencyAddress', type: 'address', internalType: 'address' },
      { name: '_amount', type: 'uint256', internalType: 'uint256' },
    ],
    outputs: [],
    stateMutability: 'payable',
  },
] as const

const bazaarAddress = '0x6D7c44773C52D396F43c2D511B81aa168E9a7a42' as Address

function BuyComponent() {
  const [contractAddress, setContractAddress] = useState('')
  const [tokenId, setTokenId] = useState('')
  const [currencyAddress, setCurrencyAddress] = useState('')
  const [amount, setAmount] = useState('')
  const { writeContract } = useWriteContract()

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()

    writeContract({
      abi: abi,
      address: bazaarAddress,
      functionName: 'buy',
      args: [
        contractAddress as Address,
        BigInt(tokenId),
        currencyAddress as Address,
        parseEther(amount),
      ],
    })
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="originContract">Origin Contract:</label>
        <input
          id="originContract"
          type="text"
          value={contractAddress}
          onChange={(e) => setContractAddress(e.target.value)}
          placeholder="Enter token contract address"
          required
        />
      </div>

      <div>
        <label htmlFor="tokenId">Token ID:</label>
        <input
          id="tokenId"
          type="text"
          value={tokenId}
          onChange={(e) => setTokenId(e.target.value)}
          placeholder="Enter token ID"
          required
        />
      </div>

      <div>
        <label htmlFor="currencyAddress">Currency Address:</label>
        <input
          id="currencyAddress"
          type="text"
          value={currencyAddress}
          onChange={(e) => setCurrencyAddress(e.target.value)}
          placeholder="Enter currency address"
          required
        />
      </div>

      <div>
        <label htmlFor="amount">Amount:</label>
        <input
          id="amount"
          type="text"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="Enter amount"
          required
        />
      </div>

      <button type="submit">Buy token</button>
    </form>
  )
}

Explore the available functions.

The examples above are just a few of many functions available in the Bazaar contract. Largely the pattern is the same. You need to know the contract address, the function name, and the arguments required. Then you can use wagmi to call the function.

Look here for a full list of functions and their arguments.

Staking Rewards

The Bazaar contract natively handles staking rewards. When a sale of an NFT is made, the contract checks if there is an associated staking pool. And if so, 1% of the sale price is forwarded to the reward accumulator associated with that pool. Automatically. Nothing else is needed.

Tip: add reward accumulator to splits

To add larger reward amounts greater than 1% to the seller's pool, you can add the reward accumulator address to the splits argument. This will reward a portion of the sale price with the seller's pool.

Last updated