owned this note
owned this note
Published
Linked with GitHub
# encode club challenges
## challenge 1 - deploy an NFT contract
### Tools used
- Node.js, version 16
- NPM, version 7
- HardHat - ethereum development framework & blockchain simulator
- https://hardhat.org
- OpenZeppelin Contracts - base Solidity contracts
- https://docs.openzeppelin.com/contracts/4.x
### Steps
1. Make a new directory for the project and enter it
```bash
mkdir nft-challenge
cd nft-challenge
```
1. Start a new NPM project with default settings
```bash
npm init -y
```
1. Install HardHat and OpenZeppelin contracts as development dependencies
```bash
npm install --save-dev hardhat @openzeppelin/contracts
```
1. Use hardhat to generate a project scaffold
```bash
npx hardhat
```
Accept the defaults when prompted about installing dependencies. At the end, you should see something like this:
```
✨ Project created ✨
Try running some of the following tasks:
npx hardhat accounts
npx hardhat compile
npx hardhat test
npx hardhat node
node scripts/sample-script.js
npx hardhat help
```
And there will be some new files in the directory:
```bash
ls
contracts node_modules package.json test
hardhat.config.js package-lock.json scripts
```
1. (optional) Checkpoint your work with a git commit
```bash
git init .
git add .
git commit -m 'solidity boilerplate'
```
1. Open your favorite editor and open the project directory
```bash
code .
```
Click into the `contracts` directory and open `Greeter.sol` to see a "hello world" smart contract.
1. Make a new file in the contracts dir called 'GameItem.sol' and paste this in:
Source: https://docs.openzeppelin.com/contracts/4.x/erc721
```solidity
// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract GameItem is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721("GameItem", "ITM") {}
function awardItem(address player, string memory tokenURI)
public
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(player, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
```
1. Compile the contract
```bash
npx hardhat compile
```
1. Open the sample script from the HardHat skeleton
Open `scripts/sample-script.js` in your editor.
Rename `Greeter` to `GameItem` and `greeter` to `gameItem`. Remove the argument to `GameItem.deploy()`.
The `main` function in the end result should look like this:
```js
async function main() {
// Hardhat always runs the compile task when running scripts with its command
// line interface.
//
// If this script is run directly using `node` you may want to call compile
// manually to make sure everything is compiled
// await hre.run('compile');
// We get the contract to deploy
const GameItem = await hre.ethers.getContractFactory("GameItem");
const gameItem = await GameItem.deploy();
await gameItem.deployed();
console.log("GameItem deployed to:", gameItem.address);
}
```
1. Run the script using the `hardhat` command:
```bash
npx hardhat run scripts/sample-script.js
GameItem deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
```
It says it's deployed and gives us an address! Great, so we're done, right?
Not quite... by default, HardHat uses an ephermeral blockhain simulator as it's target environment. This is useful for writing automated tests, but it's not much fun to play with interactively.
Next we'll start a local node and tell HardHat to use it.
1. Open a new terminal in the project directory and run a hardhat node
```bash
npx hardhat node
```
1. Back in the original terminal, set the HARDHAT_NETWORK environment variable to localhost and re-run the script
```bash
export HARDHAT_NETWORK=localhost
npx hardhat run scripts/sample-script.js
```
The output of the script should be about the same, but you'll see some information about the transaction in the output of the hardhat node if you look at the other terminal.
## Challenge 2
1. Open `scripts/sample-script.js` again in your editor.
After deploying the contract, add some code to call the `awardItem` function.
```js
const accounts = await hre.ethers.getSigners()
const player = accounts[0].address
const cid = 'a-fake-cid'
const tx = await gameItem.awardItem(player, `ipfs://${cid}`)
const receipt = await tx.wait()
for (const event of receipt.events) {
if (event.event !== 'Transfer') {
continue
}
console.log('token id: ', event.args.tokenId.toString())
console.log('owner: ', event.args.to)
}
const uri = await gameItem.tokenURI(1)
console.log('token uri:', uri)
```
2. Run the script
```bash
npx hardhat run scripts/sample-script.js
```
## Challenge 3
1. Install nft.storage client
```bash
npm install nft.storage
```
2. Open `scripts/sample-script.js` again in your editor.
Import the client package and File constructor, plus the built in `readFile` for node.js
```js
const { readFile } = require('fs/promises')
const { NFTStorage, File } = require('nft.storage')
```
3. Make a new function to load an image file and store it
```js
async function storeNFTData() {
const apiKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnaXRodWJ8Njc4NzE1IiwiaXNzIjoibmZ0LXN0b3JhZ2UiLCJpYXQiOjE2MTYwNzM2MjMxMTksIm5hbWUiOiJkZWZhdWx0In0.RJj_mR2zwTJ1_4gpAapGdkQcw3gSUz1SMmIHgr10Xng'
const client = new NFTStorage({ token: apiKey })
const filename = '../files/nft.jpg'
const data = await readFile(filename)
const file = new File([data], 'nft.jpg', { type: 'image/jpeg' })
console.log('sending data to nft.storage...')
const metadata = await client.store({
name: 'Encode Club Demo NFT',
description: 'Hello Encode Club!',
image: file
})
console.log('stored NFT data! metadata URL:', metadata.url)
return metadata.url
}
```
4. Call the function to get the metadata url before creating a token
In the `main` function:
```js
const metadataURI = await storeNFTData()
const tx = await gameItem.awardItem(player, metadataURI)
```