You will be using the Truffle suite for Ethereum, using Ganache to run a local blockchain. The frontend uses React, and the React Truffle box to interact with deployed smart contracts on the Ethereum blockchain.
You must first install Node.js >= v14.0.0 and npm >= 6.12.0
-
Install Truffle and Ganache globally
npm i -g truffle ganache
-
Install the MetaMask chrome extension
-
[Optional] Download Ganache Desktop which makes it easier to copy private keys to import accounts to MetaMask
-
Check the port that Ganache is running on (7545 if Ganache Desktop or 8545 if Ganache CLI, by default)
ganache-cli --defaultBalanceEther 10 --networkId 1337
Then edit
truffle-config.js
(networks/development
) to match the port -
On MetaMask, set up a new wallet or import an existing one
Click on the network selection dropdown at the top right > Add Network > Add a network manually.
Fill in the network details:
- Network Name: development
- New RPC URL: http://127.0.0.1:8545 (if you are using port 8545)
- Chain ID: 1337 (you can find this from running
ganache-cli
) - Currency Symbol: ETH
You have now connected to your local blockchain (localhost:8545) on Ganache
-
Import the Ganache account to MetaMask
Click on your account at the top right > Import account
Copy the private key from Ganache (you can find this from running
ganache-cli
, or if you are on Ganache Desktop,Show Key
inAccounts
tab) -
Deploy the smart contracts to the local blockchain. You can double check that the contracts are deployed, in Ganache Desktop >
Contracts
tabcd truffle npm ci # install the @openzeppelin/contracts npm dependency truffle migrate --network development
-
Start the React web app
cd .. cd client npm ci npm run dev
-
In another terminal, seed the app with dummy auctions
cd truffle/scripts truffle exec seed.js
If you don't see any auctions, refresh the page
-
At the top right, connect to Metamask and make sure you use the correct account that is tied to your local Ganache blockchain. It should have 2000 ETH
-
Click Open on any of the auctions. Find one that is in progress (Auction Started Yes but Auction Ended No) and submit your bid. It must be higher than the current highest bid.
-
Upload an image, fill in the name and description, and click
Upload
. Confirm the Metamask transaction. -
Copy the NFT Address and NFT Token ID, and click
Create New Auction
. Follow the steps and once you're finished, confirm the Metamask transaction. -
You should see details of your newly created auction under
Your Latest Auction
. ClickingGo to Auction
will bring you to the NFT image and more auction details. -
Using the same NFT Address and NFT Token ID, fill in the
Approve Auction Contract to Own NFT
section and clickApprove
. Confirm the Metamask transaction.
- NFT seller starts an auction
- User first deploys the auction contract
- User approves the auction contract to transfer his NFT from the ERC721 contract
- User starts the auction via
start()
function, and supplies:- NFT address
- NFT ID
- Starting bid
- Bid increment limit
- Duration of auction
- User joins the auction
- User views the auction details by calling
info()
- User participates in the auction by calling
bid()
, and supplies:- Bid amount
- Which must be higher than the existing bid
- For the second bid onwards, the amount is treated as a bid increment, and must be higher than the increment limit
- Bid amount
- User can only withdraw bid amount if he is not the highest bidder
- User views the auction details by calling
- NFT seller ends the auction
- User views the auction details by calling
info()
- User ends the auction by calling
end()
- If the timer has not yet run out, the function will revert
- If the timer has run out, the function will transfer the NFT to the highest bidder, and transfer the funds to the NFT seller
- User views the auction details by calling
- Auction participants who are not the highest bidder can withdraw their bid amount
- User views the auction details by calling
info()
- User withdraws the bid amount by calling
withdraw()
- User views the auction details by calling
What is a reentrancy attack?
A reentrancy attack occurs when a function makes an external call to another untrusted contract. Then the untrusted contract makes a recursive call back to the original function in an attempt to drain funds.
How to prevent reentrancy attack?
To prevent a reentrancy attack in a Solidity smart contract, you should:
- Ensure all state changes happen before calling external contracts, i.e., update balances or code internally before calling external code
- Use function modifiers that prevent reentrancy
Resources:
- Hack Solidity: Reentrancy Attack
- Re-Entrancy Attacks. How to avoid smart contract hacks and loss of funds
Mathematical operations in Solidity are subject to overflow and underflow bugs. These bugs can be exploited to drain funds from a contract.
One possible solution is to use the SafeMath library. However, the SafeMath library is not used in this project as stated in the comment:
- @dev Wrappers over Solidity's arithmetic operations.
- NOTE:
SafeMath
is generally not needed starting with Solidity 0.8, since the compiler now has built in overflow checking.
Our auction contract uses Solidity 0.8.0, which has built-in overflow checking. Therefore, we do not need to use the SafeMath library.