Skip to content

Commit

Permalink
- Basecamp docs improved; (#339)
Browse files Browse the repository at this point in the history
Put code solutions to questions in dropdowns to improve the learning experience.
  • Loading branch information
Martijncvv authored Apr 2, 2024
1 parent bd14205 commit 1e5c794
Show file tree
Hide file tree
Showing 16 changed files with 482 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ For a production app, you'll want to use a more robust implementation of `onlyOw

The address of the deployer of a contract is **not** included as an accessible property. To make it available, add it as a state variable and assign `msg.sender` in the `constructor`.

<details>

<summary>Reveal code</summary>

```solidity
contract Modifiers {
address owner;
Expand All @@ -42,12 +46,20 @@ contract Modifiers {
}
```

</details>

<br />

### Creating an `onlyOwner` Modifier

[Modifiers] are very similar to functions and are declared with the `modifier` keyword. The modifier can run any Solidity code, including functions, and is allowed to modify state. Modifiers must have a special `_` character, which serves as a placeholder for where the code contained within the modified function will run.

Create a simple `onlyOwner` modifier, which returns an `error` of `NotOwner` with the sending address if the sender is not the owner.

<details>

<summary>Reveal code</summary>

```solidity
error NotOwner(address _msgSender);
```
Expand All @@ -61,14 +73,26 @@ modifier onlyOwner {
}
```

</details>

<br/>

Test your `modifier` by adding a function that uses it:

<details>

<summary>Reveal code</summary>

```solidity
function iOwnThis() public view onlyOwner returns (string memory) {
return "You own this!";
}
```

</details>

<br/>

To test, deploy your contract and call the `iOwnThis` function. You should see the message "You own this!".

Next, switch the _Account_, and try the function again. You should see an error in the console:
Expand Down
40 changes: 40 additions & 0 deletions apps/base-docs/base-camp/docs/arrays/filtering-an-array-sbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ Go ahead and write it on your own. It needs to:

You should end up with something like:

<details>

<summary>Reveal code</summary>

```solidity
function _countEvenNumbers() internal view returns(uint) {
uint result = 0;
Expand All @@ -66,6 +70,10 @@ function _countEvenNumbers() internal view returns(uint) {
}
```

</details>

<br/>

The `_` in front of the function name is a practice used by some developers, in Solidity and in other languages, to indicate visually that this function is intended for internal use only.

### Returning Only Even Numbers
Expand All @@ -79,6 +87,10 @@ Finish the function on your own. It needs to:

You should end up with something like:

<details>

<summary>Reveal code</summary>

```solidity
function getEvenNumbers() external view returns(uint[] memory) {
Expand All @@ -98,6 +110,10 @@ function getEvenNumbers() external view returns(uint[] memory) {
```

</details>

<br/>

Did you catch the compiler warning about `view`? You aren't modifying state, so you should mark it as such.

### Testing the Function
Expand All @@ -116,6 +132,10 @@ Only one way to find out.

Add a contract-level variable called `numEven`, and initialize it with **5**, the number of even numbers in the array. Modify `getEvenNumbers()` to use `numEven` instead of the `_countEvenNumbers()` function. It should now look like:

<details>

<summary>Reveal code</summary>

```solidity
function getEvenNumbers() external view returns(uint[] memory) {
uint resultsLength = numEven; // <- Changed here
Expand All @@ -133,6 +153,10 @@ function getEvenNumbers() external view returns(uint[] memory) {
}
```

</details>

<br/>

Redeploy and test again. Success, the function now only costs about 57,484 gas to run! Except there is a catch. Remember, it's going to cost about 5000 gas to update `numEven` **each time** the array adds an even number.

### A More Realistic Accounting
Expand All @@ -148,6 +172,10 @@ uint numEven;

Add a new function called `debugLoadArray` that takes a `uint` called `_number` as an argument, and fills the array by looping through `_numbers` times, pushing each number into the array. **For now, _don't_ update `numEven`**.

<details>

<summary>Reveal code</summary>

```solidity
function debugLoadArray(uint _number) external {
for(uint i = 0; i < _number; i++) {
Expand All @@ -156,8 +184,16 @@ function debugLoadArray(uint _number) external {
}
```

</details>

<br/>

Test out the function by loading in **10** numbers. It costs about 249,610 gas to load the array. Now, add functionality to **also** increment `numEven` when the number added is even. We can't just calculate it, because although the numbers are sequential in the debug function, they might not be in real world use.

<details>

<summary>Reveal code</summary>

```solidity
function debugLoadArray(uint _number) external {
for(uint i = 0; i < _number; i++) {
Expand All @@ -169,6 +205,10 @@ function debugLoadArray(uint _number) external {
}
```

</details>

<br/>

**Be sure to redeploy** and try again with **10** numbers. This time, the cost was about 275,335 gas. That's almost 26,000 more gas in an effort to save the 5,000 gas needed to run `_countEvenNumbers()`.

### Looking at the Big Picture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ Redeploy. Without you needing to do anything, you should find that the `totalSup

You can also use this to mint to other users. Go ahead and add the second and third accounts:

<details>

<summary>Reveal code</summary>

```solidity
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
_mint(msg.sender, 1 * 10**18);
Expand All @@ -89,6 +93,11 @@ constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
}
```

</details>

<br/>


**Switch back** to the first account and redeploy. Test to confirm that each account has the appropriate amount of tokens.

### Testing the Transfer Function
Expand Down
32 changes: 32 additions & 0 deletions apps/base-docs/base-camp/docs/erc-721-token/erc-721-sbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ JPGs may be all the rage right now but in the future, the selfie you post on soc

Start by opening the [OpenZeppelin] ERC-721 in Github. Copy the link and use it to import the ERC-721 contract. Create your own contract, called `MyERC721`, that inherits from `ERC721Token`. Add a constructor that initializes the `_name` and `_symbol`.

<details>

<summary>Reveal code</summary>

```solidity
// SPDX-License-Identifier: MIT
Expand All @@ -44,6 +48,10 @@ contract MyERC721Token is ERC721 {
}
```

</details>

<br/>

### Minting NFTs

The minting function that is provided by OpenZeppelin, `_safeMint`, is `internal`. To use it to let your customers mint NFTs, you'll need to implement a function in your contract that calls the one in the imported contract.
Expand All @@ -67,13 +75,21 @@ To implement ID generation, simply add a `uint` called `counter` to storage and

Now, you can add a function called `redeemNFT` that calls `safeMint` using the `msg.sender` and `counter`, and then increments the `counter`:

<details>

<summary>Reveal code</summary>

```solidity
function redeemNFT() external {
_safeMint(msg.sender, counter);
counter++;
}
```

</details>

<br/>

:::danger

As a programmer, you've probably gone through great pains to internalize the idea of zero-indexing. Arrays start at 0. The pixel in the top-left corner of your screen is located at 0, 0.
Expand Down Expand Up @@ -148,6 +164,10 @@ The metadata for [BAYC] is [stored on IPFS], but some projects even use centrali

Start by saving the IPFS metadata bases as constants, at the contract level. Add an enum to enable selection between these two choices, and an instance of that enum.

<details>

<summary>Reveal code</summary>

```solidity
string constant BAYC = "https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/";
string constant DOODLES = "https://ipfs.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/";
Expand All @@ -156,8 +176,16 @@ Start by saving the IPFS metadata bases as constants, at the contract level. Add
NFTMetadata nftMetadata = NFTMetadata.BAYC;
```

</details>

<br/>

Finally, add an override of `_baseURI` that returns the appropriate selection based on which collection is active, and a function to swap the URI.

<details>

<summary>Reveal code</summary>

```solidity
function _baseURI() internal override view returns(string memory) {
if (nftMetadata == NFTMetadata.BAYC) {
Expand All @@ -175,6 +203,10 @@ function switchURI() public {
}
```

</details>

<br/>

Deploy, mint some NFTs, and call `tokenURI` to find the information for token number 1. You should get:

```text
Expand Down
45 changes: 45 additions & 0 deletions apps/base-docs/base-camp/docs/error-triage/error-triage.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,22 @@ TypeError: Type literal_string "One" is not implicitly convertible to expected t

Fix by correcting the type or value, as appropriate for your needs:

<details>

<summary>Reveal code</summary>


```solidity
function compilerTypeErrorFixed() public pure returns (string) {
string myNumber = "One";
return myNumber;
}
```

</details>

<br/>

### Conversion Errors

Conversion errors occur when you attempt to _implicitly_ convert one type to another. Solidity only allows this under very narrow circumstances where there is no possibility of ambiguous interpretation of the data.
Expand All @@ -74,6 +83,11 @@ TypeError: Return argument type int8 is not implicitly convertible to expected t

Fix by explicitly casting as necessary:

<details>

<summary>Reveal code</summary>


```solidity
function compilerConversionErrorFixed() public pure returns (uint) {
int8 first = 1;
Expand All @@ -82,6 +96,10 @@ function compilerConversionErrorFixed() public pure returns (uint) {
}
```

</details>

<br/>

:::tip

You'll commonly need to use multiple conversions to bridge from one type to another.
Expand Down Expand Up @@ -124,6 +142,11 @@ TypeError: Type int8 is not implicitly convertible to expected type uint256.

Resolve by explicitly converting to the final type:

<details>

<summary>Reveal code</summary>


```
function compilerOperatorErrorFixed() public pure returns (uint) {
int8 first = 1;
Expand All @@ -135,6 +158,10 @@ function compilerOperatorErrorFixed() public pure returns (uint) {
}
```

</details>

<br/>

### Stack Depth Limit

The [EVM stack] has 1024 slots, but only the top 16 slots are accessible. As a result, you can only have fewer than 16 variables in scope at one time.
Expand Down Expand Up @@ -195,6 +222,11 @@ CompilerError: Stack too deep. Try compiling with --via-ir (cli) or the equivale

Resolve this error by breaking up large functions and separating operations into different levels of scope.

<details>

<summary>Reveal code</summary>


```solidity
function stackDepthLimitFixed() public pure returns (uint) {
uint subtotalA;
Expand Down Expand Up @@ -241,6 +273,10 @@ function stackDepthLimitFixed() public pure returns (uint) {
}
```

</details>

<br/>

---

## Logical Errors
Expand Down Expand Up @@ -385,6 +421,11 @@ In this case, the error type is `11`, for overflow/underflow outside of an `unch

Fix by changing your code to handle the expected range of values.

<details>

<summary>Reveal code</summary>


```solidity
function badSubstractionFixed() public pure returns (int) {
int first = 1;
Expand All @@ -393,6 +434,10 @@ function badSubstractionFixed() public pure returns (int) {
}
```

</details>

<br/>

### Divide by Zero

Divide by zero errors also trigger a panic, with a code of `12`.
Expand Down
Loading

0 comments on commit 1e5c794

Please sign in to comment.