Skip to content

Whitelabel marketplace template built with MintBOS on NEAR's decentralized front-end framework

License

Notifications You must be signed in to change notification settings

NEARBuilders/mintbos-marketplace-template

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

98 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MintBOS Marketplace

Decentralized front ends meets NFT infrastructure on NEAR. Clone & customize this whitelabel marketplace template.

Read the full documentation.

Demo Demo

Tooling:

Use Case Framework

Author:

Author Organization

Setup

Install dependencies

pnpm install

and run the project

pnpm run dev

or

pnpm run dev:testnet

for testnet

Project Walkthrough

This guide will take you step by step through the process of creating a basic marketplace where you can purchase tokens and filter your selection by price. It uses getStoreNFTs and buyTokens from mintbos-sdk for retrieving data and executing marketplace methods.

The mintbos-sdk provides convenient functions for retrieving data from Mintbase indexer. In this example, you will be able to view and purchase NFTs from a specific store.

You can find more information on Github: GitHub link

A live demo of the marketplace can be found here: Live demo link

Step 1: Connect Wallet

Before proceeding, it is important to have a wallet connection feature implemented in your application in order to interact with the contract. To do this, ensure you are accessing the Wallet custom element provided through the gateway.

// widget/Index

const Header = () => (
  <div className="header">
    <div className="nav">
        // ... navbar
        <NavItem>
          {context.accountId ? (
            <ProfileIcon />
          ) : (
            <div style={{ width: 100 }} class="login-container">
              <Wallet
                config={{ contractId: "social.near" }}
                provides={({ signIn, signOut }) => {
                  return (
                    <button
                      onClick={signIn}
                      type="button"
                      class="login-button button"
                    >
                      Login
                    </button>
                  );
                }}
              />
            </div>
          )}
        </NavItem>
      </div>
    </div>
  </div>
);

Step 2: Get NFTs from Store

In this example, we utilized the getStoreNFTs method to retrieve NFTs and store this data in state via useState. This method returns all listed NFTs from the specified contract, allowing you to display them in the user interface.

// widget/page/home
const { getStoreNFTs } = VM.require(
  "bos.genadrop.near/widget/Mintbase.utils.sdk"
) || { getStoreNFTs: () => new Promise((resolve) => resolve([])) };

const perPage = 52;
const [nftData, setNftData] = useState([]);
const [loading, setLoading] = useState(true);
const [countNFTs, setCountNFTs] = useState(0);
const [pageNumber, setPageNumber] = useState(1);

getStoreNFTs &&
  getStoreNFTs({
    offset: (pageNumber - 1) * perPage,
    id: storeId ?? "nft.genadrop.near",
    limit: perPage,
    listedFilter: true,
    accountId: context?.accountId || "jgodwill.near",
  })
    .then(({ results, totalRecords, errors }) => {
      if (errors) {
        console.error(errors);
      }
      setCountNFTs(totalRecords);
      setLoading(false);
      setNftData(results);
    })
    .catch((error) => {
      console.error(error);
    });

Step 3: Get Store Data

To control the tabs, we need to retrieve store data using the getCombinedStoreData method. This method returns the data from the specified contract, enabling you to display it in the user interface.

// bos.genadrop.near/widget/Mintbase.utils.get_combined_store_data.jsx
const { getCombinedStoreData } = VM.require(
  "bos.genadrop.near/widget/Mintbase.utils.sdk"
) || {
  getCombinedStoreData: () => {},
};

const [storeData, setStoreData] = useState(null);

useEffect(() => {
  accountId &&
    getCombinedStoreData({ id: accountId, limit, offset })
      .then(({ data, errors }) => {
        if (errors) {
          console.error(errors);
        }
        setStoreData(data);
      })
      .catch((error) => {
        console.error(error);
      });
}, [accountId]);

Step 6: Execute the Contract Call - Buy

The execute method accepts one or more contract call objects and executes them using a specified wallet instance. In this example, we need to use the execute method to execute the "buy" call, allowing the user to purchase the desired NFT.

// widget/page/product
const { buyTokens } = VM.require(
  "bos.genadrop.near/widget/Mintbase.NFT.modules"
) || { buyTokens: () => {} };

const { data } = props;

const firstListing = data?.listings[0];

const handleBuy = () => {
  if (!context.accountId) return;
  buyTokens({
    contractId: data?.nft_contract_id,
    tokenId: data?.token_id,
    price: data?.listings[0]?.price,
    mainnet: context?.networkId === "mainnet",
    ftAddress: firstListing?.currency,
  });
};

alternatively, for multiple NFTs in the cart, we map through the items from the local storage cart and pass them into the buyTokens method that executes thesame "buy" call as above

//widget/page/cart
const { getCart } = VM.require("example.near/widget/lib.cart") || {
  getCart: () => {},
};

const cart = getCart();
const newData = Object.values(cart).map((data) => {
  const firstListing = data?.listings[0];
  return {
    contractId: data?.nft_contract_id,
    tokenId: data?.token_id,
    price: data?.listings[0]?.price,
    mainnet: context?.networkId === "mainnet",
    ftAddress: firstListing?.currency,
  };
});

const handleBuy = () => {
  const data = newData;

  if (!context.accountId) return;
  buyTokens(data);
};

Step 7: Customize the Gateway

This repository optionally includes a custom gateway for full control of the environment the Widgets run in.

Reasons for customization may include:

  1. Supporting more or different versions of wallets
  2. Introducing external APIs through custom elements (e.g. Wallet, Link, or StripePayment)
  3. Query parameter pre-processing, router configurations, etc.

Follow the Customizing the Gateway guide for how to customize.

Once done, remember to Publish the build to NEARFS, and then this bundleUrl can be configured in bos.config.json.

Step 8: Deploy

Deploy to Vercel

To deploy to Vercel, configure the Build & Development Settings to the following:

Framework Preset: "Other"
Output Directory: (Override) "dist"

On deploy, this will build the distribution bundle via pnpm run build. This build command populates metadata from the index widget's metadata json, and uses details from bos.config.json to consturct the index.html.

Deploy to Web4

Rather than deploying to a hosting provider like Vercel, this repository comes equipped with the scripts necessary to deploy to Web4, for fully decentralized web hosting. For full documentation, refer to web4-deploy.

  1. Build the distribution bundle, pnpm run build. This will populate metadata via the index widget's metadata json, and use details from bos.config.json to construct the index.html.
  2. Be sure to have deployed a web4 smart contract, such as the web4-min-contract to web4.YOUR_ACCOUNT.near. If deploying for the first time, you can replace the next step with NEAR_ENV=testnet npx vgrichina/web4-deploy ./dist web4.[YOUR_ACCOUNT].testnet --deploy-contract --nearfs
  3. Configure with the web4 account and run pnpm run web4:deploy

This final command will upload the /dist to NEARFS and then call web4_setStaticUrl on your web4 contract to point to this uploaded bundle.

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you're interested in contributing to this project, please read the contribution guide.

About

Whitelabel marketplace template built with MintBOS on NEAR's decentralized front-end framework

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Languages