A full-stack Web3 dApp that allows users to mint, purchase, and auction NFTs using ETH or USDC. Chainlink oracles fetch real-time ETH/USD prices. NFT metadata is stored using Pinata (IPFS), and minting/purchasing is restricted to whitelisted users via Merkle trees.
-
Deployed on: https://nft-auction-web3-frontend.onrender.com
-
via CI/CD automation workflows
- Whitelist-based minting and purchasing
- Pay with ETH or USDC (Chainlink price feed for ETH)
- NFT metadata pinned to IPFS via Pinata
- English auction with escrowed bidding and refunds
- Role-based access control (Admin, Sales Manager)
- Full smart contract test suite with Foundry
- Smart Contracts: Solidity (using Foundry)
- Frontend: React.js
- Backend: Express.js
- Oracle: Chainlink ETH/USD
- Storage: Pinata (IPFS)
/src– NFT and Auction contracts/frontend– React-based frontend app/server– Express.js backend for whitelist verification, and future plans to be used to optimize data fetching from blockchain/script– Deployment scripts (for local and testnet)
Frontend:
cd frontend
npm install
Backend:
cd backend
npm installContracts:
forge installgit submodule sync
git submodule update --init --recursive- Use Foundry’s
anvilto spin up a local chain. - Run
DeployLocallyscript to deploy contracts with mocked Chainlink and USDC. - Frontend and backend will connect to this local setup.
- Inherits: OpenZeppelin ERC721 + RoleManager + MerkleWhitelist + PriceConsumer
safeMint(): Mint NFT if whitelistedpurchaseNFT(): Purchase minted NFT using ETH or USDC
createAuction(): List an NFT for auctionplaceBid(): Place bid with escrowwithdraw(): Withdraw bids after losingendAuction(): End auction and transfer NFT
Run all Foundry tests:
forge test -vvvGenerate coverage (ignoring script files):
forge coverage --no-match-coverage script- Smart contracts deployed to Sepolia using Forge scripts
- Frontend hosted on Render
- https://dev.to/jamiescript/design-patterns-in-solidity-1i28
- https://www.cyfrin.io/blog/what-is-a-reentrancy-attack-solidity-smart-contracts
- https://docs.ipfs.tech/how-to/best-practices-for-nft-data/
- forge script .... Deploy the NFT contract
- node script/CopyABI.js to update the abi contract in the frontend
- update the .env's with the new contract address (frontend/foundry)
- mint NFT's again since they are all losted
- (0): I use for deployment (DEFAULT_ADMIN) -> Account 2 in metamask
- (9): I use for WhitelistManager -> Account 4 in metamask
- Backend was hashing addresses with just keccak256(address) — a plain string hash — while smart contract likely expected keccak256(abi.encodePacked(address)) like Solidity does. That mismatch is why the proofs were invalid (resulting in false in cast call).
- solidityPackedKeccak256(...) = mimics abi.encodePacked + keccak256 from Solidity
- If the hash of your leaf in JS doesn’t match the one Solidity expects, the Merkle proof won’t validate — ever.