# Hedera 0x NFT Marketplace
An example web app that demonstrates how to interact with 0x protocol on the Hedera network using [Metamask](https://metamask.io/). All NFT on marketplace to be well displayed should be compilante with [HIP-412](https://hips.hedera.com/hip/hip-412). On marketplace sellers can sell NFTS on ``BUY NOW`` or ``DUTCH AUCTION`` orders. To purchase buyers can buy order straight-forward from seller or either make an offer. Marketplace (mostly) supports multi currencies using ``HBAR`` and ``Custom Fungible Token``.

#### Built With
- [Hedera Hashgraph](https://www.hedera.com/) - The enterprise-grade public network
- [Hedera Mirror Node](https://docs.hedera.com/guides/core-concepts/mirror-nodes/) - provides a way to store and cost-effectively query historical data from the public ledger
- [Hedera Hashgraph JavaScript SDK](https://github.com/hashgraph/hedera-sdk-js) - The easiest way to use Hedera in JavaScript
- [0x protocol](https://www.0x.org/) - Is an open protocol that enables the peer-to-peer exchange of assets on the Ethereum blockchain.
- [Node.JS](https://nodejs.org) - Node.js is an open-source, cross-platform, back-end JavaScript runtime environment
- [React.JS](https://reactjs.org/) - A fast, unopinionated web framework for node.js
- [TypeScript](https://www.typescriptlang.org/) - Strongly typed programming language that builds on JavaScript
- [SASS](https://sass-lang.com/) - The most mature, stable, and powerful professional-grade CSS extension language in the world.
- [Tailwind CSS](https://tailwindcss.com/) - A utility-first CSS framework.
- [BabelJS](https://babeljs.io/) - A real-time client-to-server framework for node.js
- [WebPack](https://webpack.js.org/) - Static module bundler for modern JavaScript applications
## Created by
### Product Manager
- [Ashe Oro](https://github.com/Ashe-Oro)
### Front-end team
- [Norbert Kulus](https://github.com/norbert-kulus-arianelabs)
- [Patryk Matyjasiak](https://github.com/PatMat-Ariane)
### Back-end team
- [Bartosz Solka](https://github.com/BartoszSolkaArianelabs)
- [Piotr Swierzy](https://github.com/se7enarianelabs)
## Prerequisites
This demo assumes that you are familiar with [Node.JS](https://nodejs.org) based applications and using [React.JS](https://reactjs.org/) UI framework.
Also, you need to be familiar with using [Hedera Mirror Node](https://docs.hedera.com/guides/core-concepts/mirror-nodes/), [Hedera Hashgraph JavaScript SDK](https://github.com/hashgraph/hedera-sdk-js).
Before first connection via [Metamask](https://metamask.io/) to marketplace, user has to connect with ECDSA Hedera account to HASHGRAPH.IO jRPC.
## Getting Started
You can clone this repository by running the following command:
```
git clone https://github.com/hashgraph/hedera-nft-marketplace
```
Copy the `.env.sample` file and rename the copy to `.env`
Then populate the newly renamed `.env` file with your data:
```
#### HEDERA CONNECTION DATA
HEDERA_NETWORK=
HEDERA_MIRROR_NODE_API_VERSION=
CHAIN_ID=
#### ORDERBOOK CONNECTION DATA
API_URL=
#### TOKENS DATA
CONTRACT_0x=
ERC20_FT=
ERC20_HBAR=
AUSDC_CONTRACT_ID=
### IPFS DATA
IPFS_GATEWAYS=
## HEDERA RPC DATA
HEDERA_RPC_URL=
HEDERA_NATIVE_CURRENCY_NAME=
HEDERA_NATIVE_CURRENCY_SYMBOL=
HEDERA_NATIVE_CURRENCY_DECIMALS=
HEDERA_CHAIN_NAME=
TOKEN_PROXY_CONTRACT_ID=
MARKETPLACE_FOOTER_LINK_URL=
MARKETPLACE_FOOTER_LINK_NAME=
```
- The `HEDERA_NETWORK` holds Hedera Network type (testnet, mainnet)
- The `HEDERA_MIRROR_NODE_API_VERSION` is a variable for storing the mirror node API version
- The `CHAIN_ID` is a variable for storing jRPC chain ID
- The `API_URL` is your backend orderbook API url
- The `CONTRACT_0x` storing 0x contract ID for executing operations
- The `AUSDC_CONTRACT_ID` storing AUSDC contract ID for executing operations
- The `ERC20_FT` is for storing the ``Custom Fungible Token`` address in solidity format
- The `ERC20_HBAR` is for storing the HBAR address in solidity format
- The `IPFS_GATEWAYS` stores array of ipfs gateways. The ``{cid}`` prase in each string will be replaced with real NFT metadata CID.
- The `HEDERA_RPC_URL` stores url address to Hedera RPC.
- The `HEDERA_NATIVE_CURRENCY_NAME` holds currency name showed in MetaMask.
- The `HEDERA_NATIVE_CURRENCY_SYMBOL` holds currency symbol showed in Metamask.
- The `HEDERA_NATIVE_CURRENCY_DECIMALS` is for defining the decimals for native currency token. For HBAR it is 18.
- The `TOKEN_PROXY_CONTRACT_ID` storing Hedera based ID for proxy contract
- The `MARKETPLACE_FOOTER_LINK_URL` is for the external link in footer.
- The `MARKETPLACE_FOOTER_LINK_NAME` is for the external link name in footer.
After downloading and setting up our environment, we'll install our packages via [npm](https://docs.npmjs.com/about-npm/).
```
npm install
```
If installing the dependencies was successful, now try to run the app
```
npm run start
```
## Application design
#### Page Components (*src/pages*)
1. **Analytics** Page Component : On this page user can take a look on collections which has/had active orders. Analytics page shows ``total volume``, ``% change``, ``floor price`` and ``total sales`` for each collections.
2. **Auctions** Page Component: The active ``Dutch auction`` orders are listed here.
3. **Collection** Page Component: This page lists all NFTs from selected collections. NFTs which have active sell order have the prices displayed. Collection analytics are included here.
3. **Homepage** Page Component: The active ``Buy now`` orders are listed here.
3. **My NFT collection** Page Component: This Component displays owned NFTs of the connected user.
3. **NFT Details** Page Component: NFT details page render basic NFT details, and orders related to this NFT.
#### Services (*src/services*)
##### IPFS
Both methods are using random IPFS key from ``.env`` variable for each request.
1. ``fetchData(cid: string)``: fetch data from IPFS by given CID
2. ``fetchImage(cid: string)``: fetch image from IPFS by given CID
#### ZeroX
1. ``makeOrder(tokenId: string, serialNumber: number | string, erc20Token: string, price: number, expire: number, type: TradeDirection)``: makes ``ERC721Order`` by given data.
2. ``makeBuyOrder(tokenId: string, serialNumber: number, price: number, erc20Token: string, expire: number)``: prepares ``Buy Order`` transaction by given data.
3. ``makeSellOrder(tokenId: string, serialNumber: number | string, price: number, erc20TokenAddress: string, expire: number)``: prepares transaction for sell firstly settled ``Buy Order`` by given data
4. ``makeDutchAuctionOrder(erc20Token: string, tokenId: string, serialNumber: number, startAt: number, expiresAt: number, startingPrice: number, discountPeriod: number, discountRate: number)``: prepares ``Dutch Auction`` order transaction by given data.
5. ``convertOrderBookAuctionToZeroXDutchAuction(dutchAuction: NFTDutchAuction)``: converts ``Dutch Auction`` transaction to ``Orderbook`` supported format.
#### Metamask
1. ``checkForConnectedAccounts())``: check for connected accounts
2. ``connect()``: connect via Metamask
3. ``sign(hash: string)``: hash string via connected Metamask account
4. ``signERC7210(order: ERC721Order)``: prepares ``Dutch Auction`` order transaction by given data. Return ``signature``.
5. ``buyERC721(order: ERC721Order, signature: Signature)``: execute ``buyERC721`` contract method via Metamask.
6. ``sellERC721(order: ERC721Order, signature: Signature)``: execute ``sellERC721`` contract method via Metamask.
7. ``setApprovalToken(token: string, approved: boolean = true)``: execute ``setApprovalToken`` contract method via Metamask to approve all NFTs by given collection ID(``token``).
8. ``setApproval(value: number)``: execute ``setApproval`` contract method via Metamask. After successfully executing the ammount(``value``) of ``Custom Fungible Token`` approve ``0x contract`` for transfer tokens.
9. ``cancelOrder(nonce: string | number)``: execute ``cancelOrder`` contract method via Metamask by given nonce.
10. ``cancelAuction(auctionNonce: string | number)``: execute ``cancelAuction`` contract method via Metamask by given auctionNonce.
11. ``associateToken(tokenId: string)``: execute ``associateToken`` contract method via Metamask. Return true when association went throught or false if occurs error.
12. ``getNFTDutchAuctionHash(nftDutchAuction: ZeroXDutchAuction)``: execute ``getNFTDutchAuctionHash`` contract method via Metamask. Return hash to be signed with Metamask when preparing sell ``Dutch Auction`` order transaction.
13. ``freeMintAUSDCFromFaucet()``: execute our contract method via Metamask to mint free testnet USDC.
14. ``addTokenIntoWallet(tokenAddress: string, tokenSymbol: string, tokenImage?: string, tokenDecimals?: number)``: this method allow the user to add token to Metamask with specified token params.
#### Analytics
1. ``fetchCollectionAnalytics(params: { range: AnalyticsRange, orderBy: AnalyticsOrderBy, sortDirection?: 'ASC' | 'DESC' })``: fetch analytic and sort via parameters. Returns ``Pageable<CollectionAnalytics>``.
#### OrderBook
1. ``fetchOrders(params: { [key: string]: unknown })``: check for connected accounts
2. ``fetchAuctions(params: { [key: string]: unknown })``: connect via Metamask
3. ``createOrder(orderData: PostOrderData)``: hash string via connected Metamask account
4. ``fetchOrderById(orderId: string | number)``: prepares ``Dutch Auction`` order transaction by given data. Return ``signature``.
5. ``fetchCollectionAnalytics(collectionId: string, range: AnalyticsRange = 'HALF_YEAR')``: execute ``buyERC721`` contract method via Metamask.
6. ``fetchOffers(tokenId: string, serialNumber: number)``: execute ``sellERC721`` contract method via Metamask.
7. ``fetchListings(tokenId: string, serialNumber: number)``: execute ``setApprovalToken`` contract method via Metamask to approve all NFTs by given collection ID(``token``).
8. ``fetchPriceHistory(tokenId: string, serialNumber: number)``: execute ``setApproval`` contract method via Metamask. After successfully executing the ammount(``value``) of ``Custom Fungible Token`` approve ``0x contract`` for transfer tokens.
9. ``fetchCollections(params: {search?: string, page?: number, size?: number, sort?: CollectionSortQuery[]})``: execute ``cancelOrder`` contract method via Metamask by given nonce.
10. ``fetchCollectionNFTs(params: {[key: string]: unknown, tokenId: string})``: execute ``cancelAuction`` contract method via Metamask by given auctionNonce.
11. ``createDutchAuction(nftDutchAuction: NFTDutchAuction, signature: Signature)``: execute ``associateToken`` contract method via Metamask. Return true when association went throught or false if occurs error.
12. ``convertZeroXDutchAuctionToOrderBookAuction(nftDutchAuction: ZeroXDutchAuction)``: execute ``getNFTDutchAuctionHash`` contract method via Metamask. Return hash to be signed with Metamask when preparing sell ``Dutch Auction`` order transaction.
#### MirrorNode
1. ``async fetchAccountInfo(accountId: string)``: fetch account info for Hedera account. [Mirror Node API - Accounts](https://docs.hedera.com/guides/docs/mirror-node-api/rest-api#api-v1-accounts-idoraliasorevmaddress)
2. ``async fetchTokenInfo(tokenId: string)``: fetch Hedera token info. [Mirror Node API - Token info](https://docs.hedera.com/guides/docs/mirror-node-api/rest-api#token-info)
3. ``async fetchCollectionNFTs(tokenId: string | TokenId, options: { fetchMetadata?: boolean, nextLink?: string | null, countOfNfts?: number, userAccountId?: string}))``: fetch all collection NFTs. Can sort via ``userAccountId``.
4. ``async fetchNFTInfo(tokenId: string | TokenId, serialNumber: number)``: fetch NFT data via given details.
5. ``async fetchNFTMetadata(cid: string)``: fetch metadata by given CID using ``IPFS`` service.
6. ``async fetchUserNFTs(accountId: string)``: fetch all NFTs for given ``accountId``.
7. ``async checkTokenAssociationStatus(tokenId: string, accountId: string)``: check association status of given ``tokenId`` by given ``accountId``. Return ``boolean``.
#### Connection Hooks (*src/utils/hooks*)
##### useMetamask
Inside this hook the logic for connecting client to Metamask is handled. Hook lisning for account changes. If exist, fetch ``Hedera account info`` associated with EVM wallet address and returns it with EVM wallet address, connection status, and connection method.
```js
const {
address,
isConnected,
connect,
hederaAccountInfo,
} = useMetamask();
```
#### URL (*src/routes/base.tsx*)
The application has:
- ``/`` which ties to **HomePage** Component
- ``/auctions`` which ties to **Auctions** Component
- ``/analytics`` which ties to **Analytics** Component
- ``/collection/{collectionId}`` which ties to **Collection** Component
- ``/collection/{collectionId}/{serialNumber}`` which ties to **NFT Details** Component
#### HTTP calls
**axios** library is used to make HTTP Calls. https://axios-http.com/
#### Hedera calls
- **@hashgraph/sdk**: to generate Hedera transactions. https://github.com/hashgraph/hedera-sdk-js
#### 0x/Metamask calls
- **web3** - interact with a local or remote ethereum node using HTTP, IPC or WebSocket. [Read more](https://web3js.readthedocs.io/en/v1.8.2/).
- **ethers** - interacting with the Ethereum Blockchain and its ecosystem. [Read more](https://docs.ethers.org/v5/)
## UI Resources
- **ReactJS** : Refer to https://reactjs.org/ to understand the concepts of ReactJS
- **classnames**: https://github.com/JedWatson/classnames#readme
- **lodash**: https://lodash.com/
- **formik**: Reactive forms with https://formik.org/
- **yup**: Easy form validation https://github.com/jquense/yup
- **daisyui** : https://daisyui.com/
- **react-toastify**: https://github.com/fkhadra/react-toastify#readme
- **react-icons**: https://react-icons.github.io/react-icons/
## Disclaimer
This is just a simple demo application. Please use responsibly.
[File an issue](/issues) if you see problems.
## Contributing
Contributions are welcome. Please see the
[contributing guide](https://github.com/hashgraph/.github/blob/main/CONTRIBUTING.md)
to see how you can get involved.
## Code of Conduct
This project is governed by the
[Contributor Covenant Code of Conduct](https://github.com/hashgraph/.github/blob/main/CODE_OF_CONDUCT.md). By
participating, you are expected to uphold this code of conduct. Please report unacceptable behavior
to [oss@hedera.com](mailto:oss@hedera.com).
## LICENSE
[Apache 2.0](LICENSE)