Skip to content

Commit

Permalink
Merge pull request #190 from Cyfrin/justin/upd-572-bug-images-arent-s…
Browse files Browse the repository at this point in the history
…howing-properly-even-if-the-static-file-is-follow-up

Replace line breaks and inline images with new syntax
  • Loading branch information
solhosty authored Sep 3, 2024
2 parents eae8a0a + dc2fa0c commit 50ae94a
Show file tree
Hide file tree
Showing 353 changed files with 816 additions and 920 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ If `EIPs` get enough traction to warrant genuine consideration they will often g
New `Improvement Proposals` and `Requests for Comments` are tracked on websites such as [**eips.ethereum.org**](https://eips.ethereum.org/), where you can watch these proposals go through the process real time and be adopted or rejected by the community.

<img src="/foundry-erc20s/1-erc20-basics/erc20-basics1.png" width="100%" height="auto">
::image{src='/foundry-erc20s/1-erc20-basics/erc20-basics1.png' style='width: 100%; height: auto;'}

### ERC20

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Completing these steps sets up a development environment with some convenient bo

Go ahead and delete our 3 `Counter` examples so we can start with a clean slate.

<img src="/foundry-erc20s/2-erc20-manual-creation/erc20-manual-creation1.png" width="100%" height="auto">
::image{src='/foundry-erc20s/2-erc20-manual-creation/erc20-manual-creation1.png' style='width: 100%; height: auto;'}

I'm going to show you 2 different ways to create our own token, first the hard way and then a much easier way!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Access [OpenZeppelin's documentation](https://docs.openzeppelin.com/contracts/4.

Additionally, OpenZeppelin offers a contract wizard, streamlining the contract creation process — perfect for tokens, governances, or custom contracts.

<img src="/foundry-erc20s/3-erc20-open-zeppelin/ERC20-open-zeppelin1.png" width="100%" height="auto">
::image{src='/foundry-erc20s/3-erc20-open-zeppelin/ERC20-open-zeppelin1.png' style='width: 100%; height: auto;'}

Let's leverage OpenZeppelin to create a new ERC20 Token. Create a new file within `src` named `OurToken.sol`. Once that's done, let's install the OpenZeppelin library into our contract.

Expand Down Expand Up @@ -70,7 +70,7 @@ For the purposes of simple examples like this, I like to mint the initialSupply

As always we can perform a sanity check to assure things are working as expected by running `forge build`.

<img src="/foundry-erc20s/3-erc20-open-zeppelin/ERC20-open-zeppelin2.png" width="100%" height="auto">
::image{src='/foundry-erc20s/3-erc20-open-zeppelin/ERC20-open-zeppelin2.png' style='width: 100%; height: auto;'}

Nailed it.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ verify:

Now, by running `make anvil` (open a new terminal once your chain has started!) followed by `make deploy`...

<img src="/foundry-erc20s/4-erc20-deploy-script/erc20-deploy-script1.png" width="100%" height="auto">
::image{src='/foundry-erc20s/4-erc20-deploy-script/erc20-deploy-script1.png' style='width: 100%; height: auto;'}

### Wrap Up

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,27 +98,27 @@ Let's run it!
forge test --mt testBobBalance
```

<img src="/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap1.png" width="100%" height="auto">
::image{src='/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap1.png' style='width: 100%; height: auto;'}

Easy pass. Let's write a couple more tests and then we'll see what AI can do to help us.

### Approvals and transferFrom

Next, let's test some approvals. The ERC20 standard contains an important function, `transferFrom`. It is often the case that a smart contract protocol may need to transfer tokens _on behalf_ of a user the way this access is controlled is through the `transferFrom` function.

<img src="/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap2.png" width="100%" height="auto">
::image{src='/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap2.png' style='width: 100%; height: auto;'}

In summary, an address needs to be approved by another in order to transfer tokens on their behalf, otherwise the transaction should revert with an error.

Approvals, naturally, are handled through the `approve` and allowance functionality within the ERC20 standard.

<img src="/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap3.png" width="100%" height="auto">
::image{src='/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap3.png' style='width: 100%; height: auto;'}

Through these methods a user is able to approve another address to spend, or otherwise interact with, a limited (or often unlimited) number of tokens.

The security risks associated with this are pretty clear, which is why we've seen services like Etherscan's Token Approval Checker pop up. These allow you to see at a glance which addresses possess approvals for tokens in your wallet.

<img src="/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap4.png" width="100%" height="auto">
::image{src='/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap4.png' style='width: 100%; height: auto;'}

While it costs a little gas, it's good practice to regularly assess your approvals and revoke them when no longer applicable or appropriate.

Expand Down Expand Up @@ -159,11 +159,11 @@ Let's run the test!
forge test --mt testAllowancesWork
```

<img src="/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap5.png" width="100%" height="auto">
::image{src='/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap5.png' style='width: 100%; height: auto;'}

Nice, another pass! However, if we run `forge coverage` ...

<img src="/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap6.png" width="100%" height="auto">
::image{src='/foundry-erc20s/5-erc20-ai-tests-and-recap/erc20-ai-tests-and-recap6.png' style='width: 100%; height: auto;'}

Abysmal. We have a long way to go!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ Welcome back! In this section of the course we'll be investigate Non-fungible To

As mentioned, we'll be learning two approaches to simple NFT development in this course. This first will be a basic implementation using these cute puppies!

<img src="/foundry-nfts/1-nfts/nfts1.png" width="100%" height="auto">
::image{src='/foundry-nfts/1-nfts/nfts1.png' style='width: 100%; height: auto;'}

In this first basic implementation our images are going to be stored in [**IPFS**](https://ipfs.tech/).

With our second NFT, the art is going to be stored _on-chain_ and dynamic, changing based on a criteria we set, setting our mood from happy to sad or vice versa!

<img src="/foundry-nfts/1-nfts/nfts2.png" width="100%" height="auto">
::image{src='/foundry-nfts/1-nfts/nfts2.png' style='width: 100%; height: auto;'}

And, perhaps most excitingly, by the end of this section you'll have you're very own NFTs imported into your own wallet/metamask. You can also view them on service like OpenSea which will allow you to sell, trade, view and collect all sorts of NFTs!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ In addition to the above, the `IPFS` network doesn't automatically distribute al

Fortunately, there are services available which developers can use to pin their data for them, decentralizing access to it. One such service is [**Pinata.cloud**](https://www.pinata.cloud/).

<img src="/foundry-nfts/10-ipfs-https/ipfs-https1.png" width="100%" height="auto">
::image{src='/foundry-nfts/10-ipfs-https/ipfs-https1.png' style='width: 100%; height: auto;'}

Once an account is created and you've logged in, the UI functions much like an `IPFS` node and you can simply upload any files you want the service to pin on your behalf.

<img src="/foundry-nfts/10-ipfs-https/ipfs-https2.png" width="100%" height="auto">
::image{src='/foundry-nfts/10-ipfs-https/ipfs-https2.png' style='width: 100%; height: auto;'}

Once uploaded, `Pinata` will provide a `CID`, just like `IPFS` itself will.

<img src="/foundry-nfts/10-ipfs-https/ipfs-https3.png" width="100%" height="auto">
::image{src='/foundry-nfts/10-ipfs-https/ipfs-https3.png' style='width: 100%; height: auto;'}

> **PROTIP**
> Whenever I work on a project, I will upload my images/data both to my local `IPFS` node as well as `Pinata` to assure the data is always pinned _somewhere_.
Expand All @@ -51,4 +51,4 @@ In the next lesson we'll discuss `Scalable Vector Graphics`, or `SVGs` and how i

See you there!

<img src="/foundry-nfts/10-ipfs-https/ipfs-https4.png" width="100%" height="auto">
::image{src='/foundry-nfts/10-ipfs-https/ipfs-https4.png' style='width: 100%; height: auto;'}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ To understand what an `SVG` is, we'll dive right into a helpful tutorial from ou
</html>
```

<img src="/foundry-nfts/11-what-is-svg/what-is-svg1.png" width="100%" height="auto">
::image{src='/foundry-nfts/11-what-is-svg/what-is-svg1.png' style='width: 100%; height: auto;'}

SVGs are awesome because they maintain their quality, no matter what size you make them. If you stretch a traditional image file like a .jpg or .png, they become pixelated and lose clarity. SVGs don’t suffer from this issue because they’re scalable. They’re defined within an exact parameter, thus maintaining their quality regardless of scale.

Expand All @@ -52,7 +52,7 @@ Let's look at how we can create our own simple SVG, right in our IDE. Create the
> **IMPORTANT**
> You will likely need to download a SVG preview extention to view the SVG in your IDE. I recommend trying [**SVG Preview**](https://marketplace.visualstudio.com/items?itemName=SimonSiefke.svg-preview).
<img src="/foundry-nfts/11-what-is-svg/what-is-svg2.png" width="100%" height="auto">
::image{src='/foundry-nfts/11-what-is-svg/what-is-svg2.png' style='width: 100%; height: auto;'}

Importantly, this SVG code **_is not_** a URI, but we can convert this into a URI that a browser can understand by passing all the necessary data through the URL of our browser.

Expand Down Expand Up @@ -86,7 +86,7 @@ Copy this whole string into your browser and you should see our SVG!
data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MDAiIGhlaWdodD0iNTAwIj4KPHRleHQgeD0iMjAwIiB5PSIyNTAiIGZpbGw9IndoaXRlIj5IaSEgWW91IGRlY29kZWQgdGhpcyEgPC90ZXh0Pgo8L3N2Zz4=
```

<img src="/foundry-nfts/11-what-is-svg/what-is-svg3.png" width="100%" height="auto">
::image{src='/foundry-nfts/11-what-is-svg/what-is-svg3.png' style='width: 100%; height: auto;'}

This same process can be applied to our SVG images for our NFTs. You can navigate to the [**GitHub Repo**](https://github.com/Cyfrin/foundry-nft-f23/blob/main/images/dynamicNft/happy.svg?short_path=224d82e) to see the code which represents our happy and sad SVGs.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Ok, we've gained lots of context and understand about data storage in general an

At the core of the NFT we'll build is a `flipMood` function which allows the owner to flip their NFT between happy and sad images.

<img src="/foundry-nfts/12-svg-nft/svg-nft1.png" width="100%" height="auto">
::image{src='/foundry-nfts/12-svg-nft/svg-nft1.png' style='width: 100%; height: auto;'}

Start with creating the file `src/MoodNft.sol` and filling out the usual boilerplate. We're definitely getting good at this by now.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,11 @@ Logs:

This looks pretty good! If we paste this into our browser we should see...

<img src="/foundry-nfts/13-svg-nft-encoding/svg-nft-encoding2.png" width="100%" height="auto">
::image{src='/foundry-nfts/13-svg-nft-encoding/svg-nft-encoding2.png' style='width: 100%; height: auto;'}

... That looks like a JSON to me! Now, let's copy that imageURI into our browser...

<img src="/foundry-nfts/13-svg-nft-encoding/svg-nft-encoding3.png" width="100%" height="auto">
::image{src='/foundry-nfts/13-svg-nft-encoding/svg-nft-encoding3.png' style='width: 100%; height: auto;'}

Close enough!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ All that's left is to run our test!
forge test --mt testConvertSvgToUri
```

<img src="/foundry-nfts/15-svg-deploy/svg-deploy1.png" width="100%" height="auto">
::image{src='/foundry-nfts/15-svg-deploy/svg-deploy1.png' style='width: 100%; height: auto;'}

Nailed it! Our solidity scripted encoding is working just like our command line.

Expand Down Expand Up @@ -178,7 +178,7 @@ Because we're now using a deployment script, our testing framework is changing a

Create the directories `test/integration` and `test/unit`. Within `test/integration` create a copy of our `MoodNftTest.t.sol` and name it something like `MoodNftIntegrationsTest.t.sol`, and move our `BasicNft.t.sol` file here as well (it uses a deployer too!).

<img src="/foundry-nfts/15-svg-deploy/svg-deploy2.png" width="100%" height="auto">
::image{src='/foundry-nfts/15-svg-deploy/svg-deploy2.png' style='width: 100%; height: auto;'}

We'll adjust `MoodNftIntegrationsTest.t.sol` to use our deployer next.

Expand Down Expand Up @@ -259,7 +259,7 @@ Let's run it!
forge test --mt testFlipMoodIntegration
```

<img src="/foundry-nfts/15-svg-deploy/svg-deploy3.png" width="100%" height="auto">
::image{src='/foundry-nfts/15-svg-deploy/svg-deploy3.png' style='width: 100%; height: auto;'}

Uh oh. That ain't right.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In the last lesson we left off with a gross error that hit us when running our n
forge test --mt testFlipMoodIntegration -vvv
```

<img src="/foundry-nfts/16-svg-debug/svg-debug1.png" width="100%" height="auto">
::image{src='/foundry-nfts/16-svg-debug/svg-debug1.png' style='width: 100%; height: auto;'}

Hmm, this gives us a little more information, detailing that our assertion failed as well as providing us an output of one of the SVG URIs, but I think we can do better.

Expand All @@ -33,7 +33,7 @@ Let's run it again.
forge test --mt testFlipMoodIntegration -vvv
```

<img src="/foundry-nfts/16-svg-debug/svg-debug2.png" width="100%" height="auto">
::image{src='/foundry-nfts/16-svg-debug/svg-debug2.png' style='width: 100%; height: auto;'}

Well, our hashes are definitely different. We can import console and log out some variables to see what's going wrong.

Expand Down Expand Up @@ -62,11 +62,11 @@ Running this now, should output our tokenURI, which we can verify in our browser

Pasting this into our browser and checking the imageUri we should be able to verify that this _is_ the Sad tokenUri.. so what's going on?

<img src="/foundry-nfts/16-svg-debug/svg-debug3.png" width="100%" height="auto">
::image{src='/foundry-nfts/16-svg-debug/svg-debug3.png' style='width: 100%; height: auto;'}

Let's check the other side of the assertion. We have the SAD_SVG_URI as a constant variable, let's toss it into our browser.

<img src="/foundry-nfts/16-svg-debug/svg-debug4.png" width="100%" height="auto">
::image{src='/foundry-nfts/16-svg-debug/svg-debug4.png' style='width: 100%; height: auto;'}

Wait a minute! One of these is returning our **_tokenURI_** and the other is our **_imageURI_**! This is why it's important to be explicit in our naming conventions! Let's adjust these constants, and our test, right away. We can define a variable with what we expect the **_tokenURI_** to be and assert versus that.

Expand All @@ -88,7 +88,7 @@ function testFlipMoodIntegration() public {

With these adjustments, we can run our test again...

<img src="/foundry-nfts/16-svg-debug/svg-debug5.png" width="100%" height="auto">
::image{src='/foundry-nfts/16-svg-debug/svg-debug5.png' style='width: 100%; height: auto;'}

Beautiful!

Expand All @@ -102,4 +102,4 @@ I highly encourage you to try to write this script for MoodNFT. It should be abl

Your second call to action is going to be increasing the coverage of our contracts. Write some tests and try to get MoodNFT and our scripts closer to 100%!

<img src="/foundry-nfts/16-svg-debug/svg-debug6.png" width="100%" height="auto">
::image{src='/foundry-nfts/16-svg-debug/svg-debug6.png' style='width: 100%; height: auto;'}
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@ deployMood:

Looks great! Remember, you can add anvil as at network to Metamask by navigating to your network selector and choosing `+ Add network`.

<img src="/foundry-nfts/17-svg-anvil/svg-anvil2.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil2.png' style='width: 100%; height: auto;'}

Choose to add a network manually and enter the details as shown below:

<img src="/foundry-nfts/17-svg-anvil/svg-anvil3.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil3.png' style='width: 100%; height: auto;'}

If you need to import an anvil account, this is simple as well. When an anvil chain is spun up, it provides you with public and private keys for a number of default accounts. In your Metamask account selector, choose `+ add account or hardware wallet`

<img src="/foundry-nfts/17-svg-anvil/svg-anvil4.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil4.png' style='width: 100%; height: auto;'}

Select `import account` and enter one of the default private keys offered by the anvil chain.

<img src="/foundry-nfts/17-svg-anvil/svg-anvil5.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil5.png' style='width: 100%; height: auto;'}

Once everything is set up, we should be able to run `make deployMood`...

<img src="/foundry-nfts/17-svg-anvil/svg-anvil1.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil1.png' style='width: 100%; height: auto;'}

With the contract address, we should be able to use a cast command to interact with it.

Expand All @@ -52,7 +52,7 @@ When that transaction completes, what we can _finally_ do, is take that contract

Once imported ...

<img src="/foundry-nfts/17-svg-anvil/svg-anvil6.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil6.png' style='width: 100%; height: auto;'}

LETS GOOOO! Now we need to flip it. We should be able to use largely the same `cast` command, let's just adjust the function to `flipMood`

Expand All @@ -66,7 +66,7 @@ rpc-url http://localhost:8545
Once we reimport our NFT however...

<img src="/foundry-nfts/17-svg-anvil/svg-anvil7.png" width="100%" height="auto">
::image{src='/foundry-nfts/17-svg-anvil/svg-anvil7.png' style='width: 100%; height: auto;'}

### Wrap Up

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Alison Haire brings us her expert take from the Filecoin Foundation, providing a

### Filecoin

<img src="/foundry-nfts/18-filecoin-arweave/filecoin-arweave1.png" width="100%" height="auto">
::image{src='/foundry-nfts/18-filecoin-arweave/filecoin-arweave1.png' style='width: 100%; height: auto;'}

Filecoin, since its launch in 2020, has been working tirelessly towards decentralizing the data infrastructure for the internet. Their layer one solution, Filecoin Virtual Machine (FVM), has launched some impressive functionalities.

Expand All @@ -38,7 +38,7 @@ And many more use cases are being developed, showcased in the [Filecoin docs](ht

To get started with Filecoin, try deploying a smart contract to FVM, or use the storage helper - [**Web3 Storage**](https://web3.storage/) or [**NFT Storage**](https://nft.storage/), to engage with the technology directly.

<img src="/foundry-nfts/18-filecoin-arweave/filecoin-arweave2.png" width="100%" height="auto">
::image{src='/foundry-nfts/18-filecoin-arweave/filecoin-arweave2.png' style='width: 100%; height: auto;'}

### Wrap Up

Expand Down
Loading

0 comments on commit 50ae94a

Please sign in to comment.