diff --git a/P2P/day01/README.md b/P2P/day01/README.md
new file mode 100644
index 0000000..12c13cd
--- /dev/null
+++ b/P2P/day01/README.md
@@ -0,0 +1,593 @@
+# P2P Pool 2023 - Day 01 - Solidity
+
+✔️ You'll learn how to create a smart contract and how to use variables and visibilities.
+
+✔️ You'll learn how to create and use functions and modifiers.
+
+✔️ You'll learn what wei, gwei and ether are and how to use it.
+
+✔️ You'll learn how to create and use hashes, events & errors.
+
+✔️ You'll learn how to test your smart contracts with foundry.
+
+## Introduction
+
+Solidity is a programming language for writing smart contracts.
+It is used for implementing smart contracts on various blockchain platforms, most notably, [Ethereum](https://ethereum.org/fr/).
+
+A smart contract is a program that is stored and executed on a blockchain.
+It's written in Solidity and compiled to [bytecode](https://docs.soliditylang.org/en/latest/metadata.html).
+This bytecode is then deployed on the blockchain and it's possible to interact with it by sending transactions.
+
+## Step 0 - Setup
+
+Please refer to the [SETUP.md](./SETUP.md) file.
+
+## Step 1 - Smart Contract
+
+### :bookmark_tabs: **Description**:
+
+In this first step, you will learn how to create a smart contract.
+A Solidity smart contract is formed like this :
+
+```solidity
+// SPDX-License-Identifier: MIT // License associated with the contract
+pragma solidity ^0.8.20; // Solidity compiler version
+
+contract SmartContract { // Smart contract declaration
+ // ...
+}
+```
+
+> 💡 The `^` symbol denotes the pragma directive, specifying the compiler version or range for compatibility, in this example the contract is compatible in versions 0.8.0 and later but not 0.9.0.
+
+### :pushpin: **Tasks**:
+
+- Remove the `Counter.sol` file from the `src` folder.
+
+- Create a new file `SmartContract.sol` in the `src` folder.
+
+- In this file, create a new smart contract.
+
+### :books: **Documentation**:
+
+- [Smart Contract Introduction](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html)
+- [Smart Contract example](https://solidity-by-example.org/hello-world/)
+
+## Step 2 - Variables types
+
+### :bookmark_tabs: **Description**:
+
+With Solidity, you have access to different types of variables :
+
+- Signed integers
+- Unsigned integers
+- Strings
+- Booleans
+- Addresses
+- And many more...
+
+You will have to create variables.\
+For this, take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a variable `halfAnswerOfLife` with value `21`
+
+- Create a variable `_youAreACheater` with value `-42`
+
+- Create a variable `PoCIsWhat` with value `PoC is good, PoC is life.`
+
+- Create a variable `_areYouABadPerson` with value `false`
+
+- Create a variable `myEthereumContractAddress` with value the current contract address
+
+- Create a variable `myEthereumAddress` with value the current user address
+
+### :books: **Documentation**:
+
+- [Variables types](https://docs.soliditylang.org/en/latest/types.html#value-types)
+- [Variables example](https://solidity-by-example.org/variables/)
+- [Members of addresses](https://docs.soliditylang.org/en/latest/types.html#members-of-addresses)
+
+## Step 3 - Visibility
+
+### :bookmark_tabs: **Description**:
+
+In Solidity, you can define the visibility of your variables and functions.
+
+There are 4 types of visibility :
+
+- `public` : The variable or function is accessible from everywhere
+ > 💡 The compiler automatically generates getter functions for public variables
+- `private` : The variable or function is accessible only from the current contract
+- `internal` : The variable or function is accessible only from the current contract and from contracts that inherit it
+- `external` : The function is only accessible outside the contract, variables can't be `external`
+ > 💡 By default, variables are `internal`
+
+You will have to modify the visibility of your variables created in the previous step.
+For this, take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Modify the visibility to `public` for:
+
+ - `halfAnswerOfLife`
+ - `myEthereumContractAddress`
+ - `myEthereumAddress`
+ - `PoCIsWhat`
+
+- Modify the visibility to `internal` for:
+
+ - `_areYouABadPerson`
+
+- Modify the visibility to `private` for:
+
+ - `_youAreACheater`
+
+A good practice is to start the name of private and internal variables or functions with a `_`. It allows you to quickly know the visibility of a variable or function.
+
+### :books: **Documentation**:
+
+- [Visibility documentation](https://docs.soliditylang.org/en/latest/contracts.html#visibility-and-getters)
+- [Visibility example](https://solidity-by-example.org/visibility/)
+- [Getter functions](https://docs.soliditylang.org/en/latest/contracts.html#getter-functions)
+
+## Step 4 - Variables types #2
+
+### :bookmark_tabs: **Description**:
+
+There are other types of variables that you can use in Solidity:
+
+- `bytes` : Store a sequence of bytes
+- `mapping` : Store data in a key-value format
+- `array` : Store data in a list format
+- `struct` : Store data in a structure format
+- `enum` : Store data in a list format with a name for each value
+
+You will have to create variables.\
+For this, take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a variable `whoIsTheBest` with value `0x4c75636173206327657374206c65206265737400000000000000000000000000`
+
+- Create a variable `myGrades`
+
+ - This variable is a mapping with key `string` and value `uint256`
+
+- Create a variable `myPhoneNumber` with value `06`, `65`, `70`, `67`, `61`
+
+ - This variable is an array of `string`
+ - This variable has a length of `5`
+
+- Create an enum `roleEnum` with values `STUDENT`, `TEACHER`
+
+- Create a structure `informations` with values `firstName`, `lastName`, `age`, `city`, `role`
+
+ - `firstname` is a `string`
+ - `lastName` is a `string`
+ - `age` is a `uint8`
+ - `city` is a `string`
+ - `role` is a `roleEnum`
+
+- Create a variable `myInformations` with your personal informations
+
+### :books: **Documentation**:
+
+- [Variables types documentation](https://docs.soliditylang.org/en/latest/types.html#value-types)
+- [Bytes documentation](https://docs.soliditylang.org/en/latest/types.html#fixed-size-byte-arrays)
+- [Mapping Types documentation](https://docs.soliditylang.org/en/latest/types.html#mapping-types)
+- [Arrays documentation](https://docs.soliditylang.org/en/latest/types.html#arrays)
+- [Enums documentation](https://docs.soliditylang.org/en/latest/types.html#enums)
+- [Structs documentation](https://docs.soliditylang.org/en/latest/types.html#structs)
+- [Examples](https://solidity-by-example.org/)
+
+## Step 5 - Functions
+
+### :bookmark_tabs: **Description**:
+
+Create variables is cool, but you can also create functions.
+
+A function is a block of code that is executed when it is called.\
+You can pass data to a function, and the function will return data as a result.\
+A function can also modify your contract (its variables/balance) or the balance of the user that interacts with it.
+
+There are 4 types of functions :
+
+- `view` : The function is read-only
+- `pure` : The function is read-only and does not even read the state or the environment
+- `payable` : The function can receive ethers
+- No type: The function can modify the state
+
+You will have to create functions.\
+For this, take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a function `getHalfAnswerOfLife` that returns `halfAnswerOfLife`
+
+ - This function is `public`
+
+- Create a function `_getMyEthereumContractAddress` that returns `myEthereumContractAddress`
+
+ - This function is `internal`
+
+- Create a function `getPoCIsWhat` that returns `PoCIsWhat`, use `string memory` as return type, we will see why later
+
+ - This function is `external`
+
+- Create a function `_setAreYouABadPerson` that returns nothing
+ - This function is `internal`
+ - This function takes a `bool` as parameter
+ - This function modifies `_areYouABadPerson` with the parameter
+
+Another good practice is to put a `_` at the beginning of the parameter name.
+
+> :warning: Don't forget to define the type of your functions
+
+### :books: **Documentation**:
+
+- [Functions documentation](https://docs.soliditylang.org/en/latest/contracts.html#functions)
+- [Functions type](https://docs.soliditylang.org/en/latest/contracts.html#state-mutability)
+- [Functions example](https://solidity-by-example.org/function/)
+
+## Step 6 - Testing with Foundry
+
+### :bookmark_tabs: **Description**:
+
+Now that you have created your smart contract, you will have to test it. For this, you will use [Foundry](https://book.getfoundry.sh/forge/writing-tests). Foundry is a tool that allows you to test your smart contract. It is very useful to test your smart contract before deploying it on the blockchain because once it is deployed, it is impossible to modify it.
+
+### :pushpin: **Tasks**:
+
+- Remove the `Counter.t.sol` file from the `test` folder.
+- Create a new file `SmartContract.t.sol` in the `test` folder.
+ - This file will contain the tests of your smart contract
+- Create a contract `SmartContractTest` inherit from `Test` contract.
+ - You have to import `Test` contract, this one is contained in lib/forge-std folder.
+- Create a `setUp` function which will be executed before each test.
+ - Call your smart contract in this one.
+- Create the next functions to test your smart contract:
+ - `testGetHalfAnswerOfLife` : This function will test the function `getHalfAnswerOfLife`
+ - `testGetMyEthereumContractAddress` : This function will test the function `_getMyEthereumContractAddress`
+ - `testMyEthereumAddress` : This function will test the variable `myEthereumAddress`
+ - `testSetAreYouABadPerson` : This function will test the function `_setAreYouABadPerson`
+ - `testMyInformations` : This function will test the variable `myInformations`
+- Execute the command [`forge test`](https://book.getfoundry.sh/reference/forge/forge-test) to run the tests.
+ - You can use `forge test -vvvv` to show more information.
+
+> 💡 You can create contract helper to test internal variables or functions.
+
+Correct your smart contract, if you have errors.
+
+### :books: **Documentation**:
+
+- [Foundry testing documentation](https://book.getfoundry.sh/forge/writing-tests)
+- [Forge test documentation](https://book.getfoundry.sh/reference/forge/forge-test)
+- [Test internal function](https://book.getfoundry.sh/tutorials/best-practices#test-harnesses)
+
+## Step 7 - Data Location
+
+### :bookmark_tabs: **Description**:
+
+In Solidity, you can define the location of your variables. There are 3 types of location:
+
+- `storage` : The variable is stored on the blockchain, by default, variables in the contract are `storage`
+- `memory` : The variable is stored in memory
+- `calldata` : The variable is stored in memory and it is read-only
+
+Choose the correct data location is very important because it can have an impact on the cost of the transaction. For example, if you use `memory` for a variable that you don't need to edit use instead `calldata`, it will cost less gas.
+
+You will have to create functions to correctly understand data location. For this, take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a function `editMyCity` that returns nothing
+
+ - This function is `public`
+ - This function takes a `string` as parameter
+ - This function modifies your city in `myInformations` with the parameter
+
+- Create a function `getMyFullName` that returns my full name
+ - This function is `public`
+ - This function returns a `string`
+ - This function returns the concatenation of `firstName` and `lastName` with a space between them
+
+> :warning: Choose the correct data location for parameters and return values
+
+Create 2 tests functions for these functions.
+
+### :books: **Documentation**:
+
+- [Data location documentation](https://docs.soliditylang.org/en/latest/types.html#data-location)
+- [Data location example](https://solidity-by-example.org/data-locations/)
+
+## Step 8 - Modifier
+
+### :bookmark_tabs: **Description**:
+
+A modifier is a function that is executed before a function.\
+For example, you can use a modifier to check if the user is allowed to execute a function.
+
+You will have to create a modifier.\
+For this, take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a function `completeHalfAnswerOfLife` that returns nothing
+
+ - This function is `public`
+ - This function modifies `halfAnswerOfLife` by adding `21`
+
+- Create a modifier `onlyOwner`
+
+ - This modifier checks if the caller of the function is the owner of the contract
+
+- Add the modifier `onlyOwner` to the function `completeHalfAnswerOfLife`
+
+Create 2 tests functions for this function, one which will pass and the other which will fail.
+
+> 💡 Take a look at the vm.startPrank() and vm.expectRevert()
+
+### :books: **Documentation**:
+
+- [Modifiers documentation](https://docs.soliditylang.org/en/latest/contracts.html#function-modifiers)
+- [Modifiers example](https://solidity-by-example.org/function-modifier/)
+- [Start prank](https://book.getfoundry.sh/cheatcodes/start-prank)
+- [Expect revert](https://book.getfoundry.sh/cheatcodes/expect-revert)
+
+## Step 9 - Hashes
+
+### :bookmark_tabs: **Description**:
+
+Hashes are used to encrypt data in order to make it unreadable.\
+Hashes are very useful to secure data.
+
+Take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a function `hashMyMessage` that returns a `bytes32`
+ - This function is `public`
+ - This function takes a `string` as parameter
+ - This function hashes the parameter with `keccak256` and returns the result
+
+Create a test function to test this function.
+
+### :books: **Documentation**:
+
+- [Keccak256 documentation](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions)
+- [Keccak256 example](https://solidity-by-example.org/hashing/)
+
+## Step 10 - Gas, wei, gwei and ether
+
+### :bookmark_tabs: **Description**:
+
+Gas is the unit used to measure the cost of a transaction. It is used to pay, in ETH, the miners for the execution of the transaction. The more there is gas, the more the transaction will be executed quickly. The gas was introduced to prevent spamming the network. The more the network is used, the more the gas will be expensive.
+
+Wei, gwei and ether are the unit used to measure the value of a transaction. There are used to pay the transaction fees. A transaction can be anything: money transfer, smart contract interaction, etc...
+
+Take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Add a variable `balances`
+
+ - This variable is `public`
+ - This variable is a mapping with key `address` and value `uint256`
+ - This mapping will store the balances of each address
+
+- Create a function `getMyBalance` that returns a `uint256`
+
+ - This function is `public`
+ - This function returns the balance of the user who calls the function
+
+- Create a function `addToBalance`
+
+ - This function is `public`
+ - This function takes no parameter
+ - This function adds the value send with the transaction to the balance of the user who calls the function
+
+- Create a function `withdrawFromBalance`
+ - This function is `public`
+ - This function takes a `uint256` as parameter
+ - This function withdraws the value of the parameter from the balance of the user who calls the function
+
+> :warning: Don't forget to define the type of your functions
+
+> :warning: Don't forget to verifie that the transfer was successful
+
+Create 2 tests to test the `addToBalance` and `withdrawFromBalance` functions.
+
+### :books: **Documentation**:
+
+- [Ether units documentation](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#ether-units)
+- [Ether units example](https://solidity-by-example.org/ether-units/)
+- [Receive ether function documentation](https://docs.soliditylang.org/en/latest/contracts.html#receive-ether-function)
+- [Sending ether example](https://solidity-by-example.org/sending-ether/)
+
+## Step 11 - Events
+
+### :bookmark_tabs: **Description**:
+
+Events are used to log data.\
+They are useful to know what happened in the smart contract.
+
+Take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create an event `BalanceUpdated`
+
+ - This event takes a `address indexed` as parameter
+ - This event takes a `uint256` as parameter
+
+- Add the event `BalanceUpdated` to the function `addToBalance` and `withdrawFromBalance`
+
+The `indexed` keyword is used to allow filtering of the event. It is useful to filter events by address. You can add up to 3 `indexed` parameters. You can't filter events by `string` or `bytes`
+
+Edit your 2 previous tests to test if the event was correctly emitted.
+
+### :books: **Documentation**:
+
+- [Events documentation](https://docs.soliditylang.org/en/latest/contracts.html#events)
+- [Events example](https://solidity-by-example.org/events/)
+- [Expect emit documentation](https://book.getfoundry.sh/cheatcodes/expect-emit)
+
+## Step 12 - Errors
+
+### :bookmark_tabs: **Description**:
+
+Errors are used to return an error message.\
+They are useful to know why a transaction failed.
+
+There is two ways to throw an error :
+
+- With the usage of `require`, `assert` or `revert`
+- With the usage of `error`
+
+Take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create an error `InsufficientBalance`
+
+ - This error takes a `uint256` as parameter of the quantity of ethers available in the balance of the user
+ - This error takes a `uint256` as parameter of the quantity of ethers requested by the user
+
+- Add the error `InsufficientBalance` to the function `withdrawFromBalance`
+ - This error is thrown if the balance of the user is inferior to the value requested
+
+Create a test to test if the function `withdrawFromBalance` throws the error `InsufficientBalance` if the balance of the user is inferior to the value requested.
+
+### :books: **Documentation**:
+
+- [Error handling documentation](https://docs.soliditylang.org/en/latest/control-structures.html#error-handling-assert-require-revert-and-exceptions)
+- [Errors revert documentation](https://docs.soliditylang.org/en/latest/contracts.html#errors-and-the-revert-statement)
+- [Errors example](https://solidity-by-example.org/error/)
+
+## Step 13 - Inheritance
+
+### :bookmark_tabs: **Description**:
+
+Inheritance is used to reuse code.\
+It is useful to avoid code duplication. It is also useful to create a contract that inherits from another contract. This contract will have access to the variables and functions (not the private ones) of the contract that it inherits.
+
+There are certain types of contracts that must be inherited to be deployed. We call them `interface` and `abstract` contracts.
+
+- `interface` : This contract is used to define the functions (their prototype), the events, the errors and the structures that must be implemented in the contract that inherits it. It can define only functions that are not `private` or `internal`.
+ > The function prototype must be defined as `external` and can't have a body.
+- `abstract` : This contract is used to define the functions, the events, the errors, the structures and also the variables that must be implemented in the contract that inherits it.
+ > The function can have any visibility and can have a body.
+
+Take your smart contract from the previous step.
+
+### :pushpin: **Tasks**:
+
+- Create a folder `interfaces` in the `src` folder.
+- Create an `interface` contract `ISmartContract` in the `interfaces` folder.
+ - This contract must define events, errors, structures, enums and functions of `SmartContract`
+ - `SmartContract` must inherit from `ISmartContract`
+ - You can remove the events, errors, structures and enums of `SmartContract` because they are already defined in `ISmartContract`
+
+### :books: **Documentation**:
+
+- [Inheritance documentation](https://docs.soliditylang.org/en/latest/contracts.html#inheritance)
+- [Interface documentation](https://docs.soliditylang.org/en/latest/contracts.html#interfaces)
+- [Abstract documentation](https://docs.soliditylang.org/en/latest/contracts.html#abstract-contracts)
+- [Inheritance example](https://solidity-by-example.org/inheritance/)
+- [Interface example](https://solidity-by-example.org/interface/)
+
+## Step 14 (BONUS) - Storage & Assembly
+
+### :bookmark_tabs: **Description**:
+
+Now that you have the basics you will deep dive into Solidity. In this task you will learn about the storage layout. You will learn how to use the assembly block to access to the storage directly and to store data in the blockchain.
+
+In Solidity, you can use assembly block to write assembly code. Assembly code is a low-level programming language. It is used to write code that is executed directly by the EVM (Ethereum Virtual Machine). It is useful to optimize your smart contract.
+
+### :pushpin: **Tasks**:
+
+- Create a new solidity contract, with theses variables:
+
+ ```solidity
+ address mat;
+
+ uint eo;
+
+ bool m;
+
+ address a;
+
+ uint[] mmm;
+
+ mapping(string => mapping (uint => uint)) chall;
+
+ string[5] mateo;
+ ```
+
+- Your contract must have 2 functions:
+
+ - ```solidity
+ function get(uint256 slot, uint256 offset) public view returns (bytes32 value)
+ ```
+
+ This function must return the value of the storage at the slot `slot` and the offset `offset`.
+
+ - ```solidity
+ function set(uint256 slot, uint256 offset, bytes32 value) public
+ ```
+ This function must set the value of the storage at the slot `slot` and the offset `offset` to the value `value`.
+
+Those 2 functions must be able to get/set the value of any variables of your contract generically.
+
+To test your implementation, try to:
+
+- set the value of `a` to your address.
+- set the second element of `mateo` to 20.
+- and finally set the variable of `chall["PoC"][2]` to 999.
+
+### :books: **Documentation**:
+
+- [Storage layout](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html)
+- [Assembly block](https://docs.soliditylang.org/en/latest/assembly.html)
+- [Yul](https://docs.soliditylang.org/en/latest/yul.html)
+- [EVM dialect](https://docs.soliditylang.org/en/latest/yul.html#evm-dialect)
+
+## Conclusion
+
+Well done ! You've accomplished a lot with this first day of P2P pool, and there is so much more to discover.
+Refer to the [official documentation](https://docs.soliditylang.org/en/latest/) to deep-dive into it.
+
+Hope you enjoyed this day !
+
+## Authors
+
+| [
!LUK](https://github.com/lucas-louis) | [
Nathan](https://github.com/Nfire2103) |
+| :------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------: |
+
+
+ + + +
+ +> :rocket: Follow us on our different social networks, and put a star 🌟 on `PoC's` repositories. diff --git a/P2P/day01/SETUP.md b/P2P/day01/SETUP.md new file mode 100644 index 0000000..a703576 --- /dev/null +++ b/P2P/day01/SETUP.md @@ -0,0 +1,77 @@ +# Setup - Foundry & VSCode extension + +[Foundry](https://book.getfoundry.sh/) is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. We will need it throughout the pool. + +## Download foundry + +- Open your terminal and type + +```bash +curl -L https://foundry.paradigm.xyz | bash +``` + +. This will download foundryup. + +- Then, you can download foundry by running `foundryup` +- If everything went fine you should be able to use `forge`, `anvil`, `chisel` and `cast`. +- If you are on macos you will need to install `libusb` with + +```bash +brew install libusb +``` + +After the installation, run the following command to ensure it has been properly installed on your computer: + +```bash +forge --version +``` + +It should print your current version. + +If you have some troubles during the installation, you can refer to the [official documentation](https://book.getfoundry.sh/getting-started/installation). + +## Create a foundry project + +Once everything is done, you can create a new project using + +```bash +forge init new_project +cd new_project +``` + +This should create a new directory with a brand new foundry project + +If you already have a repository, you might need to add + +```bash +--no-commit +``` + +The first thing you wants to do is set the solidity version of this project in the `foundry.toml` file wich is the configuration file of foundry. + +You can do this by adding in the "[profile.default]" section: + +```toml +solc_version = "0.8.20" +``` + +## VSCode Integration + +I recommand you to install [solidity vscode extension](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity), it is an extension that simplifies development in Solidity. + +Also, I recommand you to use the extension formatter. It will format your code on save, which allows you to have a clean codebase. To do so: + +- Create a `.vscode/settings.json` file with this content + +```json +{ + "editor.formatOnSave": true, + "[solidity]": { + "editor.defaultFormatter": "NomicFoundation.hardhat-solidity" + } +} +``` + +## Back to the workshop + +[Jump !](./README.md) diff --git a/P2P/day02/IERC721.sol b/P2P/day02/IERC721.sol new file mode 100644 index 0000000..05c86b1 --- /dev/null +++ b/P2P/day02/IERC721.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer( + address indexed from, + address indexed to, + uint256 indexed tokenId + ); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval( + address indexed owner, + address indexed approved, + uint256 indexed tokenId + ); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll( + address indexed owner, + address indexed operator, + bool approved + ); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address); + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the address zero. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll( + address owner, + address operator + ) external view returns (bool); +} diff --git a/P2P/day02/IERC721Metadata.sol b/P2P/day02/IERC721Metadata.sol new file mode 100644 index 0000000..4233f7c --- /dev/null +++ b/P2P/day02/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "./IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} diff --git a/P2P/day02/README.md b/P2P/day02/README.md new file mode 100644 index 0000000..c613948 --- /dev/null +++ b/P2P/day02/README.md @@ -0,0 +1,648 @@ +# PoC p2p Pool 2023 - Day 02 - Solidity + +✔️ Advance solidty notion. + +✔️ Create a pet that can be minted. + +✔️ Feed the pet to upgrade it. + +✔️ Turn the pet into an NFT, and make it tranferable. + +✔️ Deploy the NFT on the blockchain. + +✔️ Add metadata to the NFT. + +## Introduction + +Now that you are familiar with solidity, let's build a more complex project such as creating our own NFT (Non-fungible token). If you need to learn more about NFTs, check out these links [NFT by Wikipedia](https://en.wikipedia.org/wiki/Non-fungible_token) and [NFT by Cryptoast](https://cryptoast.fr/non-fungible-token-nft-ou-token-non-fongible/). + +I think by now that you are familiar with the concept of an NFT, the ability to own a unique digital asset. + +If you are new to smart contract development you may think that an NFT is a complex piece of code but in reality it is a program running on a blockchain. Just as any other contract. + +First, you may wonder : what will this NFT do ? + +We will create an NFT representing a Pet. It can be minted (created) by any wallet and be fed to upgrade its level. To feed a Pet, you will need to pay a certain price. + +## Step 0 - Setup + +Please refer to the [SETUP.md](./SETUP.md) file, it is the same as the previous day. + +## Step 1: Pet Factory Contract + +### :bookmark_tabs: **Description**: + +Let's start by creating a contract which: + +- Makes every user able to mint (create) a pet +- Stores each user's ownership of their pets + +Each pet must have a: + +- Name +- Id +- Level +- Feed time + +### :pushpin: **Tasks**: + +- ### **Task 0: Init the contract** + + Let's start by creating a file in `src` called `PetFactory.sol`. + + Add these lines at the top of your file: + + ```solidity + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + ``` + + And create the contract `PetFactory`. + + In this contract create a `struct` `myPet` which contains a: + + - `name` which corresponds to the pet name + - `level` which corresponds to the pet level + - `toFeed` which corresponds to the time when the pet will be able to be fed (timestamp) + + To make work the contract, we need also a: + + - `uint8` called `cooldownTime` which is set to `1 minutes`. + - `array` of `myPet` called `_myPets`. + - `mapping` with key `uint256` (the pet's id) and value `address` called `_owners` to know who is the pet owner. + - `mapping` with key `address` (owner address) and value `uint256` called `_petCount` to keep track of how many pet are owned by a person. + + > :warning: Becareful about the visibily of the variables + + If you encounter difficulties creating variables, you can go back and take a look at [Step 4](../day01/README.md#step-4---variables-types-2) of Day1. + +- ### **Task 1: Create Pet** + + Now that we created the contract, we need to add a function to call to mint (create) a pet and return its id. This function will be limited to be only called five times per wallet (if the wallet already own five pets, they can't get a new pet). + + Here is the expected function's prototype: + + ```solidity + function _createPet(string memory _name) internal returns (uint256) {} + ``` + + At the beginning of this function, you need to use `require` to check if the owner has less than five pets and if the pet already exists. + + When creating a pet set its `level` to `1`, and its `toFeed` attribute to the `current timestamp`. + + > 💡 Don't forget to update the mappings :grin: + + ### :books: **Documentation**: + + - [Array example](https://solidity-by-example.org/array) + - [Mapping example](https://solidity-by-example.org/mapping) + - [Require example](https://solidity-by-example.org/error) + - [Timestamp documentation](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties) + +- ### **Task 2: Get info** + + Now that we are able to create a Pet, we need one method to view who owns which pet, a second one to view which pet we currently own and a third one to get my pet's info. + + Implement a function called `getPetsIdFromAddress` which returns an array of the indexes of pets owned by a giving adress. + + ```solidity + function getPetsIdFromAddress(address _owner) public view returns (uint256[] memory) {} + ``` + + Implement a function called `getMyPetsId` which returns an array of the indexes of pets owned by the caller of the function. + + ```solidity + function getMyPetsId() public view returns (uint256[] memory) {} + ``` + + Implement a function called `getMyPet` which returns my pet's info. + + ```solidity + function getMyPet(uint256 _petId) public view returns (myPet memory) {} + ``` + + > :warning: Don't forget to check if the pet is yours. + +- ### **Task 3: Testing** + + Let's test our contract. For testing our contracts we will use [Foundry](https://book.getfoundry.sh/forge/writing-tests), like we did in the previous day. If you encounter difficulties creating tests, you can go back and take a look at [Step 6](../day01/README.md#step-6---testing-with-foundry) of Day1. + + - Create a new file `PetFactory.t.sol` in the `test` folder. + - This file will contain the tests of your smart contract. + - Create a contract `PetFactoryTest` inherit from `Test` contract. + - You have to import `Test` contract, this one is contained in lib/forge-std folder. + - Create a `setUp` function which will be executed before each test. + - Call your smart contract in this one. + - Create the next functions to test your smart contract: + - `testCreatePet` : This function will test the function `_createPet`. + - `testCreatePetIfCallerHasAlreadyFivePets` : This function will test the function `_createPet` if the caller has already five pets. + - `testGetMyPetIfCallerIsNotTheOwner` : This function will test the function `getMyPet` if the caller is not the owner of the pet. + - `testGetMyPetsId` : This function will test the function `getMyPetsId`. + - Execute the command [`forge test`](https://book.getfoundry.sh/reference/forge/forge-test) to run the tests. + - You can use `forge test -vvvv` to show more information. + + > 💡 You can create contract helper to call internal variables or functions. + > 💡 Take a look at the vm.startPrank() and vm.expectRevert() + + It is very important to test correctly your smart contract, because when it is deployed on the blockchain, you can't modify it. If you have a bug in it, you can't fix it. That's why it is important to test every case and every line of your smart contract. + + ### :books: **Documentation**: + + - [Foundry testing documentation](https://book.getfoundry.sh/forge/writing-tests) + - [Forge test documentation](https://book.getfoundry.sh/reference/forge/forge-test) + - [Test internal fonction](https://book.getfoundry.sh/tutorials/best-practices#test-harnesses) + - [Start prank](https://book.getfoundry.sh/cheatcodes/start-prank) + - [Expect revert](https://book.getfoundry.sh/cheatcodes/expect-revert) + +## Step 2: Feeding Contract + +### :bookmark_tabs: **Description**: + +Now let's feed our pet. When a user will want to feed his pet, the user will have to pay a certain amount to be able to feed the pet. + +### :pushpin: **Tasks**: + +- ### **Task 0: Init the contract** + + Let's start by creating a new contract, create a new file called `PetFeeding.sol` and create the contract called `PetFeeding`. + + Add these lignes at the top of your file: + + ```solidity + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + ``` + + Your contract will have to inherit the contract `PetFactory` to have access to the previous contract. + + We need a `uint256` called `levelFee` which is set to `0.000001 ether`, this fee will be the price each user must pay to upgrade their pet. + + ### :books: **Documentation**: + + - [Inheritance documentation](https://docs.soliditylang.org/en/latest/contracts.html#inheritance) + - [Inheritance example](https://solidity-by-example.org/inheritance/) + +- ### **Task 1: Feed a Pet** + + We now need to create a function to feed our pet. As said in the introduction, the user will need to pay a fee to feed his pet. + + Below is the function's prototype: + + ```solidity + function feedMe(uint256 _petId) external payable onlyPetOwner(_petId) {} + ``` + + As you can see, we use the `payable` keyword indicating that the calling the function will trigger a payment. + + We also have `onlyPetOwner(_petId)` which is a `modifer` that you are going to write, in the `PetFactory` contract. + + ```solidity + modifier onlyPetOwner(uint256 _petId) {} + ``` + + Quick remember: `Modifier` is an element that will check if it can execute the function.\ + For example, check if the pet belongs to the one who wants the feed. :eyes: + + Don't forget to check if the pet can be fed (by checking its `toFeed` variable), and if the user has payed the right amount with `require`. + + If the pet can be fed, raise its level by one, and change the `toFeed` variable to the `current time` + `cooldownTime` (defined in `PetFactory.sol`). + + Your turn :grin: + + ### :books: **Documentation**: + + - [Modifier documentation](https://docs.soliditylang.org/en/latest/contracts.html#function-modifiers) + - [Modifier example](https://solidity-by-example.org/function-modifier/) + - [Payable documentation](https://cryptomarketpool.com/payable-modifier-in-solidity-smart-contracts/) + +- ### **Task 2: Change the feeding price** + + There is an issue with our implementation: that the price to feed a pet is constant. This means that if you want to change the price, you need to upload a new contract with the new value. If your contract needs to last on the long term on the blockchain, you need to be able to change values, such as the price. + + Create a function to set a new value to `levelFee`: + + ```solidity + function setPrice(uint256 _levelFee) external {} + ``` + +- ### **Task 3: Role based contract** + + This function works fine but a big problem is that anyone can call this function and they can set the price to zero. This isn't the desired behaviour. Only the contract owner should be able to change the price to feed a pet. + + Create the following modifier, and apply it on `setPrice`: + + ```solidity + modifier onlyContractOwner() {} + ``` + + ### :books: **Documentation**: + + - [Modifier documentation](https://docs.soliditylang.org/en/latest/contracts.html#function-modifiers) + - [Modifier example](https://solidity-by-example.org/function-modifier/) + +- ### **Task 4: Testing** + + It's time to test our contract. Let's testing our contract like we did in the previous step. + + - Create a new file `PetFeeding.t.sol` in the `test` folder. + - Create a contract `PetFeedingTest` inherit from `Test` contract. + - Create the next functions to test your smart contract: + - `testFeedMe` : This function will test the function `feedMe`. + - `testFeedMeIfCallerIsNotTheOwner` : This function will test the function `feedMe` if the caller is not the owner of the pet. + - `testFeedMeNotEnoughMoney` : This function will test the function `feedMe` if the caller doesn't have enough money to feed the pet. + - `testFeedMeCanNotBeFeed` : This function will test the function `feedMe` if the pet can't be feed right now. + - `testSetPrice` : This function will test the function `setPrice`. + - `testSetPriceIfCallerIsNotTheOwner` : This function will test the function `setPrice` if the caller is not the owner of the contract. + - Execute the command `forge test` to run the tests. + + > 💡 Think to test every case and every line of your smart contract. + + ### :books: **Documentation**: + + - [Foundry testing documentation](https://book.getfoundry.sh/forge/writing-tests) + - [Forge test documentation](https://book.getfoundry.sh/reference/forge/forge-test) + +## Step 3: Pet NFT Contract + +### :bookmark_tabs: **Description**: + +Until now we haven't really used the word NFT to describe the pet, we could have described it as an NFT because a pet can only be owned by a single wallet, thus it's **non-fungible**. But we aren't able to transfert it, this is a main feature of an NFT, it can be sent and exchange between wallets. + +Your next step is to create a contract which makes possible for wallets to transfert pet and to approve a transaction. + +Approving a transaction means that you approve a given wallet to transfer your pet to himself at any time, unless if you remove the approval. + +### :pushpin: **Tasks**: + +- ### **Task 0: Init the contract** + + Let's start by copying the `IERC721.sol` file in your `src` folder, we will detail its usefulness later. + + Continue by creating a contract called `PetNFT`. + + Add these lignes at the top of your file: + + ```solidity + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + ``` + + Your contract will have to inherit the contract `PetFeeding`, and `IERC721`. + + You may have seen the `IERC721.sol` file from the start of the day. `ERC721` is the technical name for an NFT contract. This contract contains an `interface`. It is the skeleton of a contract, it contains the function prototype which much be implemented in the contract. + [Learn more about ERC721 here.](https://eips.ethereum.org/EIPS/eip-721) + + ### :books: **Documentation**: + + - [Interface documentation](https://docs.soliditylang.org/en/latest/contracts.html#interfaces) + - [Interface example](https://solidity-by-example.org/interface/) + - [Inheritance documentation](https://docs.soliditylang.org/en/latest/contracts.html#inheritance) + - [Inheritance example](https://solidity-by-example.org/inheritance/) + +- ### **Task 1: Copy prototypes** + + To simplify implementation, we will copy the prototypes of the functions from `IERC721.sol` to `PetNFT.sol`. Replace `external` visibility with `public` visibility and add the `override` keyword. + + ### :books: **Documentation**: + + - [Visibility documentation](https://docs.soliditylang.org/en/latest/contracts.html#visibility-and-getters) + - [Override documentation](https://docs.soliditylang.org/en/latest/contracts.html#function-overriding) + +- ### **Task 2: Implement basics function** + + We have now the prototypes of the functions, we need to implement them. Let's start with the `balanceOf` and `ownerOf` functions. + + ```solidity + function balanceOf(address owner) public view override returns (uint256) + ``` + + This function returns the number of ERC721 tokens owned by the given address. + + ```solidity + function ownerOf(uint256 tokenId) public view override returns (address) + ``` + + This function returns the address that owns the given ERC721 token. + + > :warning: Don't forget to check if the token exists. + +- ### **Task 3: Implement approve functions** + + We now need to implement the `setApprovalForAll`, `isApprovedForAll`, `approve` and `getApproved` functions. These functions are used to approve a transaction. It means that you approve a given wallet to transfer your pet to himself at any time, unless if you remove the approval. + + ```solidity + function setApprovalForAll(address operator, bool approved) public override + ``` + + This function allows the owner of an ERC721 token to approve or remove the approval of another address to transfer all their tokens on their behalf. + + ```solidity + function isApprovedForAll(address owner, address operator) public view override returns (bool) + ``` + + This function returns if the given operator is approved to transfer all the tokens of the given owner. + + ```solidity + function approve(address to, uint256 tokenId) public override + ``` + + This function allows the owner of an ERC721 token to approve another address to transfer the token on their behalf. + + ```solidity + function getApproved(uint256 tokenId) public view override returns (address) + ``` + + This function returns the address that was approved for the given ERC721 token. + + > 💡 For these implementations we need to implement two mappings. + + > :warning: Don't forget to take a look of the requirements of each function. + +- ### **Task 4: Implement transferFrom function** + + Finally, we now need to implement the `transferFrom` function. This function is used to transfer a pet from one wallet to another. + + ```solidity + function transferFrom(address from, address to, uint256 tokenId) public override + ``` + + This function allows the owner of an ERC721 token to transfer the token to another address. + + > :warning: Don't forget to take a look of the requirements of this function. + +- ### **Task 5: Implement mint function** + + We have now implemented all the functions from the `IERC721.sol` file. But we still need to implement the `mint` function to create a new ERC721 token (a new pet). + + ```solidity + function mint(string memory name) public + ``` + + This function allows the caller of the function to mint a new token. + + > 💡 We have already implemented a function to create a pet in the `PetFactory.sol` file, you can use it. + + > :warning: Don't forget to emit the `Transfer` event. + +- ### **Task 6: Testing** + + Before deploy our contract on the blockchain, we need to test it. Let's testing our contract like we did in the previous steps. This time, I don't help you, you need to create the tests by yourself. Just keep in mind that you need to test every case and every line of your smart contract. + + > 💡 Don't forget to test event emitted. + + ### :books: **Documentation**: + + - [Foundry testing documentation](https://book.getfoundry.sh/forge/writing-tests) + - [Forge test documentation](https://book.getfoundry.sh/reference/forge/forge-test) + - [Expect emit documentation](https://book.getfoundry.sh/cheatcodes/expect-emit) + +## Step 4: Deploy the contracts + +### :bookmark_tabs: **Description**: + +Now that we have implemented all the functions, we need to deploy the contracts on the blockchain. We will deploy our contracts on the [Sepolia testnet](https://www.alchemy.com/overviews/sepolia-testnet). `Sepolia` is a testnet on the Ethereum blockchain, it is a copy of the Ethereum blockchain but with fake ETH. This means that you can deploy your contracts and test them without spending real money. + +- ### **Task 0: Install tools** + + - Download [Metamask](https://metamask.io) and create an account, if you don't already have one. + + MetaMask is a cryptocurrency wallet and a browser extension. It allows you to interact with the Ethereum blockchain. + + - Create your API key on [Alchemy](https://dashboard.alchemy.com/apps). + - Sign in. + - Click on `Create new app`. + - Enter a name for your API key. + - Select `Ethereum` chain and `Ethereum Sepolia` network. + - Click on `Create app`. + - Now, click on `API Key` and you can see your API key as well as your RPC URL in `HTTPS`. + + Alchemy is a blockchain developer platform. It provides a set of tools to interact with the blockchain. We will use it to deploy our contracts. + + A RPC is a Remote Procedure Call, it is a protocol that allows a program to call a function on another program located on another computer. In our case, we will use it to deploy our contracts on the blockchain. We will use the `Alchemy` RPC to deploy our contracts on the `Sepolia testnet`. [Learn more about RPC here.](https://www.alchemy.com/overviews/rpc-node) + + - Go to [Sepolia faucet](https://sepoliafaucet.com/), enter your wallet address and send you ETH. + + The faucet is a website that allows you to get fake cryptocurrency, in our case, ETH on the `Sepolia testnet`. You need to have ETH to deploy your contracts. + + - Go to `MetaMask`, click on the top left corner, click on show test networks and select `Sepolia`. + + You should normally have 0.5 ETH in your wallet. + + ## :books: **Documentation**: + + - [Sepolia documentation](https://www.alchemy.com/overviews/sepolia-testnet) + - [MetaMask website](https://metamask.io/) + - [Alchemy dashboard](https://dashboard.alchemy.com/apps) + - [RPC documentation](https://www.alchemy.com/overviews/rpc-node) + - [Sepolia faucet](https://sepoliafaucet.com/) + +- ### **Task 1: Create the environment file** + + Now that we have all the tools, we need to create an environment file to store our variables needed to deploy our contracts. + + Create a `.env` file at the root of your project and add the following variables: + + ```env + PRIVATE_KEY= + ADMIN_WALLET= + RPC_URL= + CONTRACT_ADDRESS= + ``` + + - `PRIVATE_KEY` is the private key of your wallet. You can find it in `MetaMask` by clicking on the top right corner, then `Account details` and `Show private key`. + + - `ADMIN_WALLET` is the address of your wallet. You can find it in `MetaMask` by clicking on the top right corner, then `Account details` and `Copy address to clipboard`. + + - `RPC_URL` is the RPC URL of `Alchemy`. You can find it in `Alchemy` by clicking on `API Key` and you can see your RPC URL in `HTTPS`. + + - `CONTRACT_ADDRESS` is the address of your contract. You will get it after deploying your contract. + + Source your environment file: + + ```bash + source .env + ``` + +- ### **Task 2: Let's deploy our contracts** + + We have now all the tools and the variables needed to deploy our contracts. Let's start to deploy our contracts. We will use [Foundry](https://book.getfoundry.sh/forge/deploying) to deploy our contracts. Foundry can be used to test contracts but also to deploy them on the blockchain. + + - Use [`forge create`](https://book.getfoundry.sh/reference/forge/forge-create) command to deploy your `PetNFT` contract with your RPC URL. + + ### ✔️ **Validation**: + + If you have correctly deployed your contract, you should see something like this: + + ``` + Deployer: 0x8F5a1Ccf3D0DE62a25bf594c14e0967fF66461DD + Deployed to: 0x84D4606b29ee8167190B5c1eD621D9f5a4aAB43f + Transaction hash: 0x5dffd2a389a322c7af30f8cf9bcb54713ff432bb530a2590e4966fb77598e976 + ``` + + Put the address of your contract, `Deployed to`, in the `CONTRACT_ADDRESS` variable in your `.env` file. + + > :warning: Don't forget to source again your environment file. + + ### :books: **Documentation**: + + - [Foundry deploying documentation](https://book.getfoundry.sh/forge/deploying) + - [Forge create documentation](https://book.getfoundry.sh/reference/forge/forge-create) + +- ### **Task 3: Let's use our contracts** + + Congratulations! You have deployed your first contract on the blockchain. Now, we will interact with our contracts to create a pet and to feed it. To do this, we will use... Foundry again, with the [`cast`](https://book.getfoundry.sh/cast/) command. + + - Use the `cast` command to do the following actions: + - Create a pet with the name `PoC's pet`. + - Get your balance to verify that you have one pet. + - Feed the pet. + - Get the info of the pet to verify that its level has increased. + + ### :books: **Documentation**: + + - [Cast overview documentation](https://book.getfoundry.sh/cast/) + - [Cast call documentation](https://book.getfoundry.sh/reference/cast/cast-call) + - [Cast send documentation](https://book.getfoundry.sh/reference/cast/cast-send) + +- ### **Task 4: Collect your Pet in Metamask** + + We have interacted with our contract, but we don't see our NFT. Let's add it to `MetaMask` to see it. + + - Go to `MetaMask`, click on the `NFTs` tab. + - Click on `Import NFT`. + - Enter the address of your contract and the id of your pet. + + You should now see your pet in `MetaMask`. Well play! You have your own NFT in your wallet. + +## Step 5: Pet NFT Metadata Contract + +### :bookmark_tabs: **Description**: + +We have deployed our contract and we can see our pet in `MetaMask`. But we can't see the name and the image of our pets, because we don't have add metadata to our NFTs. An NFT metadata is a file which contains information about the NFT. It can be the name, the image, the description, etc. This file is stored on a server and can be accessed by a link. This link is stored in the smart contract. + +To save time, I already upload metadatas for 100 pets on `IPFS`. `IPFS` is a protocol and a peer-to-peer network for storing and sharing data in a distributed file system. [Learn more about IPFS here.](https://docs.ipfs.io/concepts/what-is-ipfs/) + +Let's add metadata to our NFTs to be able to see the name and the image of our pets. + +- ### **Task 0: Init the contract** + + Let's start by copying the `IERC721Metadata.sol` file in your `src` folder, we will detail its usefulness later. + + Continue by creating a contract called `PetNFTMetadata`. + + Add these lignes at the top of your file: + + ```solidity + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; + ``` + + Your contract will have to inherit the contract `PetNFT`, and `IERC721Metadata`. + + You may have seen the `IERC721Metadata.sol` file from the start of the day. `ERC721Metadata` is the interface which contains the function prototype to get the metadata of an ERC721 token. + +- ### **Task 1: Named our NFTs** + + Let's start by named our NFTs. + + - Create the following variables with the correct visibility: + - `name`: which corresponds to the name of your NFTs. + - `symbol`: which corresponds to the abbreviation of the name. + +- ### **Task2: Implement the link of the metadata** + + We now need to implement the `tokenURI` function. This function returns the link of the metadata of the ERC721 token. + + ```solidity + function tokenURI(uint256 tokenId) public view override returns (string memory) + ``` + + The base URI of the metadata is `ipfs://QmVmTDg5sNBtt62r3ksQBKHVZK9mqJ4sH4Vyfgd6c3KDL9/`. You need to concatenate the base URI with the id of the token. + +- ### **Task 3: Implement supports interface** + + In order that the application can know if the contract supports the `ERC721Metadata` interface, we need to implement the `supportsInterface` function. This function returns if the contract supports the given interface. + + ```solidity + function supportsInterface(bytes4 interfaceId) public pure returns (bool) + ``` + + This function must return `true` if the interfaceId corresponds to the `ERC721` or `ERC721Metadata` interface. + + > 💡 You can use type(Interface).interfaceId to get the interfaceId of an interface. + +- ### **Task 4: Testing** + + Let's test our contract, like we did in the previous step I don't help you, you need to create the tests by yourself. Just keep in mind that you need to test every case and every line of your smart contract. + + ### :books: **Documentation**: + + - [Foundry testing documentation](https://book.getfoundry.sh/forge/writing-tests) + - [Forge test documentation](https://book.getfoundry.sh/reference/forge/forge-test) + +- ### **Task 5: Deploy the contract** + + We have now implemented all the functions to get the metadata of our NFTs. We need to deploy our contract. + + - Use `forge create` command to deploy your `PetNFTMetadata` contract with your RPC URL, like you did in the previous step. + + - Use the `cast` command to do the following actions: + - Create deux pets with the name `PoC's pet with metadata` and `PoC's pet gift`. + - Get your balance to verify that you have two pets. + - Get the tokenURI of the first pet and convert it to an human readable link. + - Transfer the second pet to a friend. + + ### :books: **Documentation**: + + - [Foundry deploying documentation](https://book.getfoundry.sh/forge/deploying) + - [Forge create documentation](https://book.getfoundry.sh/reference/forge/forge-create) + - [Cast overview documentation](https://book.getfoundry.sh/cast/) + - [Cast call documentation](https://book.getfoundry.sh/reference/cast/cast-call) + - [Cast send documentation](https://book.getfoundry.sh/reference/cast/cast-send) + +- ### **Task 6: Collect your Pet in Metamask** + + Let's add our pet in `MetaMask`, to see its name and image. + + - Go to `MetaMask`, click on the `NFTs` tab. + - Click on `Import NFT`. + - Enter the address of your contract and the id of your pet. + + You should now see your pet in `MetaMask` with its name and image. + + > 💡 Also whith the implementation of the `supportsInterface` function you can now send your NFT with `Metamask`. + +## Conclusion + +Congratulations! You have created your first NFT. You have learned how to create an NFT with its metadata. You have also learned how to deploy a contract on the blockchain and how to interact with it. You can now create your own NFTs and sell them on the blockchain 😉. + +## Authors + +| [+ + + +
+ +> :rocket: Follow us on our different social networks, and put a star 🌟 on `PoC's` repositories. diff --git a/P2P/day02/SETUP.md b/P2P/day02/SETUP.md new file mode 100644 index 0000000..a703576 --- /dev/null +++ b/P2P/day02/SETUP.md @@ -0,0 +1,77 @@ +# Setup - Foundry & VSCode extension + +[Foundry](https://book.getfoundry.sh/) is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. We will need it throughout the pool. + +## Download foundry + +- Open your terminal and type + +```bash +curl -L https://foundry.paradigm.xyz | bash +``` + +. This will download foundryup. + +- Then, you can download foundry by running `foundryup` +- If everything went fine you should be able to use `forge`, `anvil`, `chisel` and `cast`. +- If you are on macos you will need to install `libusb` with + +```bash +brew install libusb +``` + +After the installation, run the following command to ensure it has been properly installed on your computer: + +```bash +forge --version +``` + +It should print your current version. + +If you have some troubles during the installation, you can refer to the [official documentation](https://book.getfoundry.sh/getting-started/installation). + +## Create a foundry project + +Once everything is done, you can create a new project using + +```bash +forge init new_project +cd new_project +``` + +This should create a new directory with a brand new foundry project + +If you already have a repository, you might need to add + +```bash +--no-commit +``` + +The first thing you wants to do is set the solidity version of this project in the `foundry.toml` file wich is the configuration file of foundry. + +You can do this by adding in the "[profile.default]" section: + +```toml +solc_version = "0.8.20" +``` + +## VSCode Integration + +I recommand you to install [solidity vscode extension](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity), it is an extension that simplifies development in Solidity. + +Also, I recommand you to use the extension formatter. It will format your code on save, which allows you to have a clean codebase. To do so: + +- Create a `.vscode/settings.json` file with this content + +```json +{ + "editor.formatOnSave": true, + "[solidity]": { + "editor.defaultFormatter": "NomicFoundation.hardhat-solidity" + } +} +``` + +## Back to the workshop + +[Jump !](./README.md)