Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch 1 #115

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
> Update: You should use `ipfs://` instead of `https://ipfs.io/` for your tokenURI
> Update: The code has been modified to use Sepolia as Rinkeby Testnet is not supported anymore.

> Update: You should use `ipfs://` instead of `https://ipfs.io/` for your tokenURI.


# nft-mix

Expand Down Expand Up @@ -57,7 +60,7 @@ Set your `WEB3_INFURA_PROJECT_ID`, and `PRIVATE_KEY` [environment variables](htt

You can get a `WEB3_INFURA_PROJECT_ID` by getting a free trial of [Infura](https://infura.io/). At the moment, it does need to be infura with brownie. You can find your `PRIVATE_KEY` from your ethereum wallet like [metamask](https://metamask.io/).

You'll also need testnet rinkeby ETH and LINK. You can get LINK and ETH into your wallet by using the [rinkeby faucets located here](https://faucets.chain.link/rinkeby). If you're new to this, [watch this video.](https://www.youtube.com/watch?v=P7FX_1PePX0)
You'll also need testnet Sepolia ETH and LINK. You can get LINK and ETH into your wallet by using the [Sepolia faucets located here](https://faucets.chain.link/sepolia). If you're new to this, [watch this video.](https://www.youtube.com/watch?v=P7FX_1PePX0)

You can add your environment variables to the `.env` file:

Expand Down Expand Up @@ -88,30 +91,30 @@ They each deploy unique dogs. The advanced version gives you a random breed (out

The advanced collection uses a [Chainlink VRF](https://docs.chain.link/docs/get-a-random-number) to deploy the random dog.

You can 100% use the rinkeby testnet to see your NFTs rendered on opensea, but it's suggested that you test and build on a local development network so you don't have to wait as long for transactions.
You can 100% use the Sepolia testnet to see your NFTs rendered on opensea, but it's suggested that you test and build on a local development network so you don't have to wait as long for transactions.

### Running Scripts

The simple collectibles work on a local network, however the advanced requires a testnet. We default to rinkeby since that seems to be the testing standard for NFT platforms. You will need testnet rinkeby ETH and testnet Rinkeby LINK. You can find faucets for both in the [Chainlink documentation](https://docs.chain.link/docs/link-token-contracts#rinkeby).
The simple collectibles work on a local network, however the advanced requires a testnet. When the video tutorial was launched, Rinkeby was used, but ever since it was discountinued we have switched to Sepolia as it is the testing standard for NFT platforms. You will need testnet Sepolia ETH and testnet Sepolia LINK. You can find faucets for both in the [Chainlink documentation](https://docs.chain.link/resources/link-token-contracts).

# For the Simple ERC721
```
brownie run scripts/simple_collectible/deploy_simple.py --network rinkeby
brownie run scripts/simple_collectible/create_collectible.py --network rinkeby
brownie run scripts/simple_collectible/deploy_simple.py --network sepolia
brownie run scripts/simple_collectible/create_collectible.py --network sepolia
```

# For the Advanced ERC721

You'll need [testnet Rinkeby](https://faucet.rinkeby.io/) and [testnet LINK](https://rinkeby.chain.link/) in the wallet associated with your private key.
You'll need [testnet ETH](https://sepoliafaucet.com/) and [testnet LINK](https://faucets.chain.link/sepolia/) in the wallet associated with your private key.

```
brownie run scripts/advanced_collectible/deploy_advanced.py --network rinkeby
brownie run scripts/advanced_collectible/create_collectible.py --network rinkeby
brownie run scripts/advanced_collectible/deploy_advanced.py --network sepolia
brownie run scripts/advanced_collectible/create_collectible.py --network sepolia
```
Then:
```
brownie run scripts/advanced_collectible/create_metadata.py --network rinkeby
brownie run scripts/advanced_collectible/set_tokenuri.py --network rinkeby
brownie run scripts/advanced_collectible/create_metadata.py --network sepolia
brownie run scripts/advanced_collectible/set_tokenuri.py --network sepolia
```

# Verify on Etherscan
Expand All @@ -137,22 +140,22 @@ Set `export IPFS_URL=http://127.0.0.1:5001` and `export UPLOAD_IPFS=true` enviro
Run the IPFS daemon: `ipfs daemon`
Then Run
```
brownie run scripts/advanced_collectible/create_metadata.py --network rinkeby
brownie run scripts/advanced_collectible/create_metadata.py --network sepolia
```

Alternatively, you could upload the uri manually:
Add the file created in `metadata/rinkeby/NAME.json` to [IPFS](https://ipfs.io/) or [Pinata](https://pinata.cloud/).
Add the file created in `metadata/sepolia/NAME.json` to [IPFS](https://ipfs.io/) or [Pinata](https://pinata.cloud/).
### If you want to use the metadata from this repo

Just run:
```
brownie run scripts/advanced_collectible/create_metadata.py --network rinkeby
brownie run scripts/advanced_collectible/create_metadata.py --network sepolia
```

2. Set the tokenURI
Run
```
brownie run scripts/advanced_collectible/set_tokenuri.py --network rinkeby
brownie run scripts/advanced_collectible/set_tokenuri.py --network sepolia
```
And after some time, (you may have to wait up to 20 minutes for it to render on opensea), you should see your NFT on opensea! [It'll look something like this.](https://testnets.opensea.io/assets/0x8acb7ca932892eb83e4411b59309d44dddbc4cdf/0)

Expand Down
16 changes: 12 additions & 4 deletions brownie-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@ reports:
exclude_contracts:
- SafeMath
dependencies:
- smartcontractkit/chainlink[email protected]
- OpenZeppelin/openzeppelin-contracts@3.4.0
- smartcontractkit/chainlink@2.0.0
- OpenZeppelin/openzeppelin-contracts@4.1.0
compiler:
solc:
remappings:
- '@chainlink=smartcontractkit/chainlink[email protected]'
- '@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0'
- "@chainlink=smartcontractkit/chainlink@2.0.0"
- "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.1.0"
# automatically fetch contract sources from Etherscan
autofetch_sources: True
dotenv: .env
# set a custom mnemonic for the development network
networks:
default: development
sepolia:
vrf_coordinator: "0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625"
link: "0x779877A7B0D9E8603169DdbD7836e478b4624789"
keyHash: "0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c"
#Add your own subscriptionId - https://docs.chain.link/vrf/v2/subscription/
subscriptionId: "3690"
fee: 100000000000000000
verify: False
kovan:
vrf_coordinator: '0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9'
link_token: '0xa36085F69e2889c224210F603D836748e7dC0088'
Expand Down
40 changes: 21 additions & 19 deletions contracts/AdvancedCollectible.sol
Original file line number Diff line number Diff line change
@@ -1,53 +1,55 @@
pragma solidity 0.6.6;
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";

contract AdvancedCollectible is ERC721, VRFConsumerBase {
contract AdvancedCollectible is VRFConsumerBaseV2, ERC721URIStorage {
uint256 public tokenCounter;
enum Breed{PUG, SHIBA_INU, ST_BERNARD}
// add other things
mapping(bytes32 => address) public requestIdToSender;
mapping(bytes32 => string) public requestIdToTokenURI;
mapping(uint256 => address) public requestIdToSender;
mapping(uint256 => string) public requestIdToTokenURI;
mapping(uint256 => Breed) public tokenIdToBreed;
mapping(bytes32 => uint256) public requestIdToTokenId;
event RequestedCollectible(bytes32 indexed requestId);
mapping(uint256 => uint256) public requestIdToTokenId;
event RequestedCollectible(uint256 indexed requestId);
// New event from the video!
event ReturnedCollectible(bytes32 indexed requestId, uint256 randomNumber);
event ReturnedCollectible(uint256 indexed newItemId, Breed breed);


bytes32 internal keyHash;
uint256 internal fee;
uint64 subscriptionId;
VRFCoordinatorV2Interface COORDINATOR;

constructor(address _VRFCoordinator, address _LinkToken, bytes32 _keyhash)
public
VRFConsumerBase(_VRFCoordinator, _LinkToken)
constructor(address _VRFCoordinator, uint64 _subscriptionId, bytes32 _keyhash)
VRFConsumerBaseV2(_VRFCoordinator)
ERC721("Dogie", "DOG")
{
tokenCounter = 0;
keyHash = _keyhash;
fee = 0.1 * 10 ** 18;
COORDINATOR = VRFCoordinatorV2Interface(_VRFCoordinator);
subscriptionId = _subscriptionId;
}

function createCollectible(string memory tokenURI)
public returns (bytes32){
bytes32 requestId = requestRandomness(keyHash, fee);
function createCollectible(string memory tokenURI) public returns (uint256) {
uint256 requestId = COORDINATOR.requestRandomWords(keyHash, subscriptionId, 3, 1000000, 1);
requestIdToSender[requestId] = msg.sender;
requestIdToTokenURI[requestId] = tokenURI;
emit RequestedCollectible(requestId);
}

function fulfillRandomness(bytes32 requestId, uint256 randomNumber) internal override {
function fulfillRandomWords(uint256 requestId, uint256[] memory randomNumber) internal override {
address dogOwner = requestIdToSender[requestId];
string memory tokenURI = requestIdToTokenURI[requestId];
uint256 newItemId = tokenCounter;
_safeMint(dogOwner, newItemId);
_setTokenURI(newItemId, tokenURI);
Breed breed = Breed(randomNumber % 3);
Breed breed = Breed(randomNumber[0] % 3);
tokenIdToBreed[newItemId] = breed;
requestIdToTokenId[requestId] = newItemId;
tokenCounter = tokenCounter + 1;
emit ReturnedCollectible(requestId, randomNumber);
emit ReturnedCollectible(newItemId, breed);
}

function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
Expand Down
5 changes: 3 additions & 2 deletions contracts/SimpleCollectible.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.6;
pragma solidity 0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract SimpleCollectible is ERC721 {
contract SimpleCollectible is ERC721URIStorage {
uint256 public tokenCounter;
constructor () public ERC721 ("Dogie", "DOG"){
tokenCounter = 0;
Expand Down
1 change: 1 addition & 0 deletions metadata/sepolia/0-ST_BERNARD.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "ST_BERNARD", "description": "An adorable ST_BERNARD pup!", "image": "https://ipfs.io/ipfs/QmUPjADFGEKmfohdTaNcWhp7VGk26h5jXDA7v3VtTnTLcW?filename=st-bernard.png", "attributes": [{"trait_type": "cuteness", "value": 100}]}
1 change: 1 addition & 0 deletions metadata/sepolia/1-SHIBA_INU.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "SHIBA_INU", "description": "An adorable SHIBA_INU pup!", "image": "https://ipfs.io/ipfs/QmYx6GsYAKnNzZ9A6NvEKV9nf1VaDzJrqDR23Y8YSkebLU?filename=shiba-inu.png", "attributes": [{"trait_type": "cuteness", "value": 100}]}
1 change: 1 addition & 0 deletions metadata/sepolia/2-PUG.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "PUG", "description": "An adorable PUG pup!", "image": "https://ipfs.io/ipfs/QmSsYRx3LpDAb1GZQm7zZ1AuHZjfbPkD6J7s9r41xu1mf8?filename=pug.png", "attributes": [{"trait_type": "cuteness", "value": 100}]}
13 changes: 6 additions & 7 deletions scripts/advanced_collectible/create_collectible.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@
def main():
dev = accounts.add(config["wallets"]["from_key"])
advanced_collectible = AdvancedCollectible[len(AdvancedCollectible) - 1]
fund_with_link(advanced_collectible.address)

transaction = advanced_collectible.createCollectible("None", {"from": dev})
print("Waiting on second transaction...")
# wait for the 2nd transaction
transaction.wait(1)
# time.sleep(35)
listen_for_event(
print("Waiting on randomWords VRFCoordinator fullfillment...")
event = listen_for_event(
advanced_collectible, "ReturnedCollectible", timeout=200, poll_interval=10
)
requestId = transaction.events["RequestedCollectible"]["requestId"]
token_id = advanced_collectible.requestIdToTokenId(requestId)
breed = get_breed(advanced_collectible.tokenIdToBreed(token_id))
breed_id = event.args.breed
token_id = event.args.newItemId
breed = get_breed(breed_id)
print("Dog breed of tokenId {} is {}".format(token_id, breed))
5 changes: 2 additions & 3 deletions scripts/advanced_collectible/deploy_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ def main():
print(network.show_active())
advanced_collectible = AdvancedCollectible.deploy(
config["networks"][network.show_active()]["vrf_coordinator"],
config["networks"][network.show_active()]["link_token"],
config["networks"][network.show_active()]["keyhash"],
config["networks"][network.show_active()]["subscriptionId"],
config["networks"][network.show_active()]["keyHash"],
{"from": dev},
publish_source=get_publish_source(),
)
fund_with_link(advanced_collectible.address)
return advanced_collectible