Skip to content

Commit

Permalink
UI improvements, contract changes in process
Browse files Browse the repository at this point in the history
  • Loading branch information
luloxi committed Sep 18, 2024
1 parent 9a17da9 commit 7d3c778
Show file tree
Hide file tree
Showing 10 changed files with 356 additions and 151 deletions.
23 changes: 17 additions & 6 deletions packages/foundry/contracts/SimpleMint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ contract SimpleMint is EIP712 {
address artist,
string name,
string symbol,
string tokenURI
string tokenURI,
uint256 usdPrice,
uint256 maxTokenId
);

bytes32 public constant TYPEHASH =
Expand All @@ -31,11 +33,17 @@ contract SimpleMint is EIP712 {
string memory _name,
string memory _symbol,
string memory _tokenURI,
address _artist
address _artist,
uint256 _usdPrice,
uint256 _maxTokenId
) public returns (address) {
SimpleMintNFT nft = new SimpleMintNFT(_name, _symbol, _tokenURI, _artist);
SimpleMintNFT nft = new SimpleMintNFT(
_name, _symbol, _tokenURI, _artist, _usdPrice, _maxTokenId
);
collections.push(address(nft));
emit CollectionStarted(address(nft), _artist, _name, _symbol, _tokenURI);
emit CollectionStarted(
address(nft), _artist, _name, _symbol, _tokenURI, _usdPrice, _maxTokenId
);
return address(nft);
}

Expand All @@ -45,6 +53,8 @@ contract SimpleMint is EIP712 {
string memory _symbol,
string memory _tokenURI,
address _artist,
uint256 _usdPrice,
uint256 _maxTokenId,
bytes memory signature
) external returns (address) {
// 1. Create a hash of the input data using the provided type hash
Expand All @@ -61,8 +71,9 @@ contract SimpleMint is EIP712 {
);

// 4. Start the collection using the verified artist's address
address collectionInstanceAddress =
startCollection(_name, _symbol, _tokenURI, _artist);
address collectionInstanceAddress = startCollection(
_name, _symbol, _tokenURI, _artist, _usdPrice, _maxTokenId
);

return collectionInstanceAddress;
}
Expand Down
23 changes: 16 additions & 7 deletions packages/foundry/contracts/SimpleMintNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,29 @@ import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract SimpleMintNFT is ERC721, ERC721Enumerable, ERC721URIStorage {
uint256 private _tokenIds; // Replaces the Counters.Counter
uint256 public maxTokenId;
uint256 public usdPrice;
string public collectionTokenURI;
address public artist;

constructor(
string memory _name,
string memory _symbol,
string memory _tokenURI,
address _artist
address _artist,
uint256 _usdPrice,
uint256 _maxTokenId
) ERC721(_name, _symbol) {
collectionTokenURI = _tokenURI;
artist = _artist;
usdPrice = _usdPrice;
maxTokenId = _maxTokenId;
}

// Mint an NFT
function mintItem() public returns (bool) {
require(_tokenIds < maxTokenId, "Max token limit reached");
// Add a way of checking if enough USDC has been received or it's ETH equivalent
_tokenIds++; // Increment the token ID manually
uint256 id = _tokenIds;

Expand All @@ -34,9 +42,12 @@ contract SimpleMintNFT is ERC721, ERC721Enumerable, ERC721URIStorage {
return true;
}

function tokenURI(
uint256 /* tokenId */
) public view override(ERC721, ERC721URIStorage) returns (string memory) {
function tokenURI(uint256 /* tokenId */ )
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
// return super.tokenURI(tokenId);
// This should be the IPFS URI when contract is live
return string(abi.encodePacked("https://ipfs.io/ipfs/", collectionTokenURI));
Expand All @@ -49,9 +60,7 @@ contract SimpleMintNFT is ERC721, ERC721Enumerable, ERC721URIStorage {

// The following functions are overrides required by Solidity.

function supportsInterface(
bytes4 interfaceId
)
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable, ERC721URIStorage)
Expand Down
15 changes: 12 additions & 3 deletions packages/foundry/test/SimpleMintTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ contract SimpleMintTest is Test {
string NAME = "Song Number Two";
string SYMBOL = "SONG2";
string TOKEN_URI = "QmTokenUri";
uint256 USD_PRICE = 10;
uint256 MAX_TOKEN_ID = 10;

// Variables for testing the EIP-712 signature
address ARTIST_ADDRESS;
Expand All @@ -32,8 +34,9 @@ contract SimpleMintTest is Test {

function testStartCollection() public {
// Start a collection
address newCollection =
simpleMint.startCollection(NAME, SYMBOL, TOKEN_URI, ARTIST_ADDRESS);
address newCollection = simpleMint.startCollection(
NAME, SYMBOL, TOKEN_URI, ARTIST_ADDRESS, USD_PRICE, MAX_TOKEN_ID
);
// Check that the collection was started
SimpleMintNFT newCollectionInstance = SimpleMintNFT(newCollection);
string memory completeTokenURI =
Expand All @@ -55,7 +58,13 @@ contract SimpleMintTest is Test {
vm.prank(gasPayer);
bytes memory signature = abi.encodePacked(r, s, v);
address newCollection = simpleMint.startCollectionBySig(
NAME, SYMBOL, TOKEN_URI, ARTIST_ADDRESS, signature
NAME,
SYMBOL,
TOKEN_URI,
ARTIST_ADDRESS,
USD_PRICE,
MAX_TOKEN_ID,
signature
);

// Assert the collection has been correctly initialized
Expand Down
56 changes: 0 additions & 56 deletions packages/local_db/firebase-debug.log

This file was deleted.

2 changes: 2 additions & 0 deletions packages/local_db/firestore-debug.log
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ If you are running a Firestore in Datastore Mode project, run:
Note: Support for Datastore Mode is in preview. If you encounter any bugs please file at https://github.com/firebase/firebase-tools/issues.
Dev App Server is now running.

*** shutting down gRPC server since JVM is shutting down
*** server shut down
94 changes: 72 additions & 22 deletions packages/nextjs/app/marketplace/_components/Marketplace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@

import { useEffect, useState } from "react";
import { NFTCard } from "./NFTCard";
// import { useAccount } from "wagmi";
import { useScaffoldContract, useScaffoldEventHistory } from "~~/hooks/scaffold-eth";
import { notification } from "~~/utils/scaffold-eth";
import { getMetadataFromIPFS } from "~~/utils/simpleNFT/ipfs-fetch";
import { NFTMetaData } from "~~/utils/simpleNFT/nftsMetadata";

export interface Collectible extends Partial<NFTMetaData> {
listingId: number;
listingId?: number; // For listed collectibles, optional
uri: string;
owner: string;
price: string;
payableCurrency: string;
isAuction: boolean;
date: string;
price?: string;
payableCurrency?: string;
isAuction?: boolean;
date?: string;
highestBidder?: string;
maxTokenId?: number; // New field for the maximum token ID (from CollectionStarted event)
}

export const Marketplace = () => {
// const { address: connectedAddress } = useAccount();
const [listedCollectibles, setListedCollectibles] = useState<Collectible[]>([]);

// Fetch the collectible contract
const { data: yourCollectibleContract } = useScaffoldContract({
contractName: "MockNFT",
});

// Fetch listing events from the Marketplace contract
// Fetch Marketplace ListingCreated events
const {
data: events,
isLoading: isLoadingEvents,
Expand All @@ -39,37 +39,50 @@ export const Marketplace = () => {
watch: true,
});

// Fetch SimpleMint CollectionStarted events
const {
data: simpleMintEvents,
isLoading: simpleMintIsLoadingEvents,
error: simpleMintErrorReadingEvents,
} = useScaffoldEventHistory({
contractName: "SimpleMint",
eventName: "CollectionStarted",
fromBlock: 0n,
watch: true,
});

useEffect(() => {
const fetchListedNFTs = async () => {
if (!events || !yourCollectibleContract) return;

const collectiblesUpdate: Collectible[] = [];

// Process Marketplace ListingCreated events
for (const event of events) {
try {
const { args } = event;
const listingId = args?.listingId;
// Display on the info tab and or add to the collectible interface
// const nftContract = args?.nftContract;
const nftId = args?.nftId;
const seller = args?.seller;
const price = args?.price;
const payableCurrency = args?.payableCurrency === 0 ? "ETH" : "USDC";
const payableCurrency = args?.payableCurrency === 0 ? "ETH" : "USDC"; // USDC for non-ETH
const isAuction = args?.isAuction;
const date = new Date(Number(args?.date) * 1000).toLocaleDateString(); // Convert timestamp to readable date
const date = new Date(Number(args?.date) * 1000).toLocaleDateString();
const highestBidder = args?.highestBidder;

// Fetch the tokenURI for the NFT
const tokenURI = await yourCollectibleContract.read.tokenURI([nftId ? BigInt(nftId) : 0n]);
const ipfsHash = tokenURI.replace("https://ipfs.io/ipfs/", "");
const nftMetadata: NFTMetaData = await getMetadataFromIPFS(ipfsHash);

// Add the NFT to the collectibles array
collectiblesUpdate.push({
listingId: parseInt(listingId ? listingId.toString() : ""),
listingId: listingId !== undefined ? parseInt(listingId.toString()) : 0, // Default to 0 or any other value
uri: tokenURI,
owner: seller ? seller : "",
price: price ? price.toString() : "",
payableCurrency,
isAuction: isAuction ? true : false,
owner: seller || "",
price: price?.toString(),
payableCurrency: payableCurrency,
isAuction: !!isAuction,
date,
highestBidder,
...nftMetadata,
Expand All @@ -80,22 +93,59 @@ export const Marketplace = () => {
}
}

// Process SimpleMint CollectionStarted events
for (const event of simpleMintEvents || []) {
try {
const { args } = event;
// This could be used to interact with the SimpleMinted contract
// const nftAddress = args?.nft;
const artist = args?.artist;
const tokenURI = args?.tokenURI;
const usdPrice = args?.usdPrice;
const maxTokenId = args?.maxTokenId;

// Ensure tokenURI is defined
if (!tokenURI) {
console.warn("Skipping event because tokenURI is undefined");
continue;
}

const ipfsHash = tokenURI.replace("https://ipfs.io/ipfs/", "");
const nftMetadata: NFTMetaData = await getMetadataFromIPFS(ipfsHash);

// Add the NFT collection to the collectibles array
collectiblesUpdate.push({
listingId: undefined, // Not applicable for SimpleMint NFTs
uri: tokenURI,
owner: artist || "",
price: usdPrice ? usdPrice.toString() : undefined, // Set price as USD price from the event
payableCurrency: usdPrice ? "USDC" : undefined, // Set payableCurrency to USDC if usdPrice is present
maxTokenId: maxTokenId ? Number(maxTokenId) : undefined, // Add maxTokenId
...nftMetadata,
});
} catch (e) {
notification.error("Error fetching collection started NFTs");
console.error(e);
}
}

// Update state with merged collectibles
setListedCollectibles(collectiblesUpdate);
};

fetchListedNFTs();
}, [events, yourCollectibleContract]);
}, [events, simpleMintEvents, yourCollectibleContract]);

if (isLoadingEvents) {
if (isLoadingEvents || simpleMintIsLoadingEvents) {
return (
<div className="flex justify-center items-center mt-10">
<span className="loading loading-spinner loading-lg"></span>
</div>
);
}

if (errorReadingEvents) {
return <div>Error fetching events: {errorReadingEvents.message}</div>;
if (errorReadingEvents || simpleMintErrorReadingEvents) {
return <div>Error fetching events: {errorReadingEvents?.message || simpleMintErrorReadingEvents?.message}</div>;
}

return (
Expand All @@ -107,7 +157,7 @@ export const Marketplace = () => {
) : (
<div className="flex flex-wrap gap-4 my-8 px-5 justify-center">
{listedCollectibles.map(item => (
<NFTCard nft={item} key={item.listingId} />
<NFTCard nft={item} key={item.uri} />
))}
</div>
)}
Expand Down
Loading

0 comments on commit 7d3c778

Please sign in to comment.