Welcome to the GitHub repository of CryptoKazakh, a unique digital marketplace designed to foster global appreciation and preservation of Kazakh culture. This decentralized application (dApp) leverages blockchain technology to provide a platform for artists and cultural enthusiasts to create, buy and explore Kazakh-themed Non-Fungible Tokens (NFTs).
- How to run the DApp?
- Smartcontract Explanation
- Financial Analysis
- Interfaces
- Designs
- Developers
- Contributing
To set up the repository and run the marketplace locally, run the below
git clone https://github.com/aBacoding/CryptoKazakh
cd frontend
npm install
npm start
To set up and run the smartcontracts, run the below
git clone https://github.com/aBacoding/CryptoKazakh
cd hardhat
npx hardhat compile
npx hardhat run --network sepolia scripts/deploy.ts
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
// Importing OpenZeppelin's ERC721URIStorage and Counters contracts.
// ERC721URIStorage is an ERC721 token with storage for a URI.
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
// Contract declaration for ArtCollectiveMarket, inheriting from ERC721URIStorage.
contract ArtCollectiveMarket is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds; // Counter for token IDs.
Counters.Counter private _itemsSold; // Counter for items sold.
address payable owner; // Address of the contract owner.
uint256 listingFee = 0.01 ether; // Listing fee for minting an artwork.
// Struct to represent an artwork.
struct Artwork {
uint256 tokenId; // Unique ID of the artwork.
address payable owner; // Owner of the artwork.
address payable seller; // Seller of the artwork.
uint256 price; // Price of the artwork.
bool currentlyListed; // Whether the artwork is listed for sale.
}
// Mapping from token ID to its respective Artwork.
mapping(uint256 => Artwork) private idToArtwork;
// Constructor sets the name and symbol of the token and initializes the contract owner.
constructor() ERC721("ArtCollective", "ARTC") {
owner = payable(msg.sender);
}
// Function to retrieve the listing fee.
function getListingFee() public view returns (uint256) {
return listingFee;
}
// Function to mint new artwork. Requires the payment of listing fee.
function mintArtwork(string memory tokenURI, uint256 price) public payable returns (uint) {
require(msg.value == listingFee, "You gotta pay the gallery fee to list your artwork.");
require(price > 0, "This piece of art must have value!");
_tokenIds.increment(); // Incrementing the token ID counter.
uint256 newTokenId = _tokenIds.current(); // Getting the new token ID.
_safeMint(msg.sender, newTokenId); // Minting the token.
_setTokenURI(newTokenId, tokenURI); // Setting the token URI.
// Creating and mapping the new Artwork struct.
idToArtwork[newTokenId] = Artwork(newTokenId, payable(address(this)), payable(msg.sender), price, true);
_transfer(msg.sender, address(this), newTokenId); // Transferring the token.
return newTokenId;
}
// Function to browse listed artworks in the gallery.
function browseGallery() public view returns (Artwork[] memory) {
uint itemCount = _tokenIds.current(); // Total number of items minted.
uint listedItemCount = _tokenIds.current() - _itemsSold.current(); // Number of items currently listed.
Artwork[] memory items = new Artwork[](listedItemCount); // Array to store listed items.
uint currentIndex = 0;
for (uint i = 0; i < itemCount; i++) {
if (idToArtwork[i + 1].currentlyListed) {
uint currentId = i + 1;
Artwork storage currentItem = idToArtwork[currentId];
items[currentIndex] = currentItem; // Adding the item to the array.
currentIndex++;
}
}
return items; // Returning the array of listed items.
}
// Function to purchase an artwork.
function purchaseArtwork(uint256 tokenId) public payable {
uint price = idToArtwork[tokenId].price; // Price of the artwork.
require(msg.value == price, "The price must be equal to the artwork's listed price.");
address seller = idToArtwork[tokenId].seller; // Seller's address.
idToArtwork[tokenId].currentlyListed = false; // Marking the artwork as not listed.
idToArtwork[tokenId].owner = payable(msg.sender); // Setting the new owner.
_itemsSold.increment(); // Incrementing the sold items counter.
_transfer(address(this), msg.sender, tokenId); // Transferring the token to the buyer.
payable(owner).transfer(listingFee); // Transferring the listing fee to the owner.
payable(seller).transfer(msg.value); // Transferring the payment to the seller.
}
// Function to view the user's collection (both owned and sold items).
function myCollection() public view returns (Artwork[] memory) {
uint totalItemCount = _tokenIds.current(); // Total number of items minted.
uint itemCount = 0; // Counter for items belonging to the user.
uint currentIndex = 0;
// Counting items belonging to the user.
for (uint i = 0; i < totalItemCount; i++) {
if (idToArtwork[i + 1].owner == msg.sender || idToArtwork[i + 1].seller == msg.sender) {
itemCount++;
}
}
Artwork[] memory items = new Artwork[](itemCount); // Array to store the user's items.
for (uint i = 0; i < totalItemCount; i++) {
if (idToArtwork[i + 1].owner == msg.sender || idToArtwork[i + 1].seller == msg.sender) {
uint currentId = i + 1;
Artwork storage currentItem = idToArtwork[currentId];
items[currentIndex] = currentItem; // Adding the item to the array.
currentIndex++;
}
}
return items; // Returning the user's collection.
}
}
- Cost: The cost for a client to mint a new artwork is the
listingFee
, set at0.01 ether
. This fee is mandatory to list the artwork in the gallery. Additionally, users should consider the gas fees required for executing this function on the Ethereum network.
- Cost: The buyer must pay the price of the artwork, as determined by the seller at the time of minting. This price is a fixed amount for each artwork. Gas fees are also applicable for the transaction.
- Earnings: The owner earns the
listingFee
(0.01 ether) for each artwork minted and listed. This represents a direct income source. - Losses: There are no direct losses from this function for the owner. However, costs associated with deploying and maintaining the smart contract should be considered.
- Earnings: For each artwork purchased, the owner earns the
listingFee
again. These fees are the primary revenue source for the owner. - Losses: There are no direct losses from artwork purchases. However, ongoing maintenance and potential updates to the smart contract may incur costs.
- The owner does not receive a percentage of the artwork's sale price; their earnings are solely from the listing fees.
- The contract currently lacks a mechanism for secondary sales or royalties, which could be a potential revenue stream in other NFT platforms.
- Purpose: The primary landing page for users to engage with the NFT marketplace.
- Interactions:
- Explore available NFTs
- Create new NFTs
- Connect to MetaMask wallet
- Subscribe to NFT drop notifications
- Navigation: Users can move from the homepage to explore, create, or manage their NFTs and wallet.
- Purpose: Allows users to mint new NFTs by providing necessary details.
- Interactions:
- Input NFT details (title, image, price)
- Submit to create the NFT
- Navigation: Post-creation, users may view their NFTs or return to the marketplace to browse.
- Purpose: Enables users to browse and purchase NFTs in the marketplace.
- Interactions:
- Place bids or purchase NFTs
- Navigation: Users can go on to purchase NFTs or return to the homepage.
- Purpose: A personal dashboard for users to view their owned NFTs.
- Interactions:
- View owned NFTs
- Navigation: Access detailed views of owned NFTs or navigate back to explore more NFTs.
- Purpose: Informs users that the page they are trying to access does not exist.
- Interactions:
- Link to return to the homepage
- Navigation: Redirects users back to a functioning part of the website.
- Abdurakhim Bakytzhan
- main frontend developer
- main blockchain developer
- Temirlan Torebekov
- main blockchain developer
- Azat Bekturganov
- secondary blockchain developer
- Nursultan Tynyshbay
- secondary frontend developer
Interested in contributing to the CryptoKazakh NFT Marketplace? We welcome contributions of all kinds.
Developed with ❤️ by Abdurakhim Bakytzhan, Temirlan Torebekov, Azat Bekturganov, Nursultan Tynyshbay/CryptoKazakh Developers Team