diff --git a/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/6-erc20-ai-tests-and-recap/+page.md b/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/6-erc20-ai-tests-and-recap/+page.md index 2c733f0bd..5e63c1876 100644 --- a/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/6-erc20-ai-tests-and-recap/+page.md +++ b/courses/advanced-foundry/1-How-to-create-an-erc20-crypto-currency/6-erc20-ai-tests-and-recap/+page.md @@ -359,7 +359,7 @@ contract OurTokenTest is StdCheats, Test { I'll caution you against blindly copying and pasting AI responses and to use what's generated intelligently. Some things will make more sense for your situation that others. -When you've implemented your AI suggestsion, run `forge test -vvvv` and see what happens! +When you've implemented your AI suggestion, run `forge test -vvvv` and see what happens! ### Wrap Up diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/11-what-is-svg/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/11-what-is-svg/+page.md index c06217235..17d5822d4 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/11-what-is-svg/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/11-what-is-svg/+page.md @@ -50,7 +50,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). +> You will likely need to download a SVG preview extension to view the SVG in your IDE. I recommend trying [**SVG Preview**](https://marketplace.visualstudio.com/items?itemName=SimonSiefke.svg-preview). ::image{src='/foundry-nfts/11-what-is-svg/what-is-svg2.png' style='width: 100%; height: auto;'} diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/15-svg-deploy/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/15-svg-deploy/+page.md index 731221611..c6d14938c 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/15-svg-deploy/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/15-svg-deploy/+page.md @@ -8,7 +8,7 @@ _Follow along the course with this video._ ### SVG NFT Deploy Script -In this lesson, we'll jump right into creating the script to deploy our MoodNFT collection. We'll look at how this can be used to upgrade our tests, making them more dynamic and we'll discuss the value of integration tesing. +In this lesson, we'll jump right into creating the script to deploy our MoodNFT collection. We'll look at how this can be used to upgrade our tests, making them more dynamic and we'll discuss the value of integration testing. To begin, we'll need to create the file `script/DeployMoodNft.s.sol` and fill it with our script boilerplate. @@ -24,7 +24,7 @@ contract DeployMoodNft is Script { } ``` -Looks great! Now we should consider how we're mention to deploy MoodNft.sol. We know that the constructor arguments for this contract take a sadSvgImagUri and a happySvgImageUri, so much like we did in `MoodNftTest.t.sol`, we _could_ hardcode these values. A better approach however may be to write our deploy script to read this data itself from our workspace. Our script can even do all the encoding for us. +Looks great! Now we should consider how we're mention to deploy MoodNft.sol. We know that the constructor arguments for this contract take a sadSvgImageUri and a happySvgImageUri, so much like we did in `MoodNftTest.t.sol`, we _could_ hardcode these values. A better approach however may be to write our deploy script to read this data itself from our workspace. Our script can even do all the encoding for us. Let's start with creating this encoding function. @@ -56,7 +56,7 @@ contract DeployMoodNft is Script { } ``` -The above function is taking the svg string parameter, encoding it with the OpenZeppeling Base64.encode function, and then prepends the encoded value with our baseURL. Great job! +The above function is taking the svg string parameter, encoding it with the OpenZeppelin Base64.encode function, and then prepends the encoded value with our baseURL. Great job! > ❗ **PROTIP** > You can replace `abi.encodePacked` with the more up-to-date `string.concat`! diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/18-filecoin-arweave/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/18-filecoin-arweave/+page.md index 48e6ebe8d..817b3768f 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/18-filecoin-arweave/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/18-filecoin-arweave/+page.md @@ -44,6 +44,6 @@ To get started with Filecoin, try deploying a smart contract to FVM, or use the With this brief aside complete, we have one major concept I want to add context to in this lesson. Repeatedly we've been using `abi.encode` and `abi.encodePacked` to concatenate strings basically. It's about time we learnt what's actually going on under-the-hood. -In the next lesson we're gunna get a little more low-level. I'm sure you're ready for it. +In the next lesson we're gonna get a little more low-level. I'm sure you're ready for it. See you soon! diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/2-what-is-a-nft/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/2-what-is-a-nft/+page.md index 3fb4f0148..1e0a78b06 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/2-what-is-a-nft/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/2-what-is-a-nft/+page.md @@ -21,7 +21,7 @@ Fungible tokens, like ERC20s are similar to a dollar. Any single dollar can be s ### What's an NFT do? -Because of their unique nature, NFTs have been widely adopted as a medium for art and a means to trade and collect digital art. Sometimes this gets a bad rap, but NFTs are only a standard on which a tonne of use case functionality can be built. Some protocol turn them into representations of game assets, or into tradeble metaverse items, sometimes they're used as means to keep record, or grant access to services or events. +Because of their unique nature, NFTs have been widely adopted as a medium for art and a means to trade and collect digital art. Sometimes this gets a bad rap, but NFTs are only a standard on which a tonne of use case functionality can be built. Some protocol turn them into representations of game assets, or into tradable metaverse items, sometimes they're used as means to keep record, or grant access to services or events. The use cases of NFTs grow each day, but the easiest way to think of them currently is as unique digital assets, or unique digital art. diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/22-evm-signatures-selectors/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/22-evm-signatures-selectors/+page.md index ff7e1f3aa..03a3e9bfb 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/22-evm-signatures-selectors/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/22-evm-signatures-selectors/+page.md @@ -247,7 +247,7 @@ contract CallAnything { } ``` -One last thing I want to point out is that we're not limited to this kind of interaction. Through this low-level calling method, two contracts are able to interact without possessing all the information associated with eachother. Consider this second contract `CallFunctionWithoutContract`. +One last thing I want to point out is that we're not limited to this kind of interaction. Through this low-level calling method, two contracts are able to interact without possessing all the information associated with each other. Consider this second contract `CallFunctionWithoutContract`. CallFunctionWithoutContract diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/5-using-ipfs/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/5-using-ipfs/+page.md index 69711e388..20758a5ed 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/5-using-ipfs/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/5-using-ipfs/+page.md @@ -34,7 +34,7 @@ In a [**previous lesson**](https://updraft.cyfrin.io/courses/advanced-foundry/ho "value": "Headband" } ], - "description": "A collection 8888 Cute Chubby Pudgy Penquins sliding around on the freezing ETH blockchain.", + "description": "A collection 8888 Cute Chubby Pudgy Penguins sliding around on the freezing ETH blockchain.", "image": "ipfs://QmNf1UsmdGaMbpatQ6toXSkzDpizaGmC9zfunCyoz1enD5/penguin/420.png", "name": "Pudgy Penguin #420" } @@ -49,9 +49,9 @@ When this course was originally filmed, the Pudgy Penguins collection had been u "https://ipfs.io/ipfs/QmNf1UsmdGaMbpatQ6toXSkzDpizaGmC9zfunCyoz1enD5/penguin/420.png"; ``` -This works, and is often leveraged due to browser compatibily with IPFS, but it's worth noting that this is pointing to a centralized server. If that server goes down, the image data will be unretrievable via the tokenURI call! +This works, and is often leveraged due to browser compatibility with IPFS, but it's worth noting that this is pointing to a centralized server. If that server goes down, the image data will be unretrievable via the tokenURI call! -A more decentralized way to retrieve the image data is by pointing to the IPFS netwok itself. +A more decentralized way to retrieve the image data is by pointing to the IPFS network itself. ```js "ipfs://QmNf1UsmdGaMbpatQ6toXSkzDpizaGmC9zfunCyoz1enD5/penguin/420.png"; @@ -84,7 +84,7 @@ If you view this in your browser or through the IPFS Desktop App, you should see } ``` -Now, we could just paste the about tokenURI as a return value of our tokenUri function, but this would mint every Doggie identical to eachother. Let's spice things up a little bit and allow the user to choose what their NFT looks like. We'll do this by allowing the user to pass a tokenUri to the mint function and mapping this URI to their minted tokenId. +Now, we could just paste the about tokenURI as a return value of our tokenUri function, but this would mint every Doggie identical to each other. Let's spice things up a little bit and allow the user to choose what their NFT looks like. We'll do this by allowing the user to pass a tokenUri to the mint function and mapping this URI to their minted tokenId. ```js contract BasicNFT is ERC721 { diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/7-basic-nft-tests/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/7-basic-nft-tests/+page.md index 985d978fe..b56fb672d 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/7-basic-nft-tests/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/7-basic-nft-tests/+page.md @@ -113,7 +113,7 @@ contract BasicNftTest is Test { basicNft.mintNft(PUG); assert(basicNft.balanceOf(USER) == 1); - assert(keccask256(abi.encodePacked(PUG)) == keccak256(abi.encodePacked(basicNft.tokenURI(0)))); + assert(keccak256(abi.encodePacked(PUG)) == keccak256(abi.encodePacked(basicNft.tokenURI(0)))); } } ``` diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/8-basic-interactions/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/8-basic-interactions/+page.md index 3a34302c4..8edb43642 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/8-basic-interactions/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/8-basic-interactions/+page.md @@ -13,7 +13,7 @@ Alright, with our tests passing we're going to want a way to interact with our c ```js // SPDX-License-Identifier: MIT -pragme solidity ^0.8.18; +pragma solidity ^0.8.18; import {Script} from "forge-std/Script.sol"; diff --git a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/9-testnet-demo/+page.md b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/9-testnet-demo/+page.md index 10f6705e3..b0ac3deca 100644 --- a/courses/advanced-foundry/2-how-to-create-an-NFT-collection/9-testnet-demo/+page.md +++ b/courses/advanced-foundry/2-how-to-create-an-NFT-collection/9-testnet-demo/+page.md @@ -14,7 +14,7 @@ So let's do that. Before we get started, I'll mention you don't _have_ to do this yourself. This process will cost testnet funds, so it's fine to just follow along if needed. An alternative way to view your NFT would be to import your Anvil chain into Metamask and continue to use your local blockchain. If that works for you, great! Otherwise, let's continue with deploying this on an actual testnet. -We'll be leveraging a Makefile for this again, I'll just be copying mine from the GitHub repo associated with this course, I've also provided it below for your conveninence. +We'll be leveraging a Makefile for this again, I'll just be copying mine from the GitHub repo associated with this course, I've also provided it below for your convenience. Makefile: @@ -83,7 +83,7 @@ Assuming our `.env` is ready to go, we should be able to run the following... > Remember to add the required environment variables if necessary. You should need a `sepolia RPC-URL`, an `account private key` and an `etherscan api key`. ```bash -make deploy ARGS="--netwok sepolia" +make deploy ARGS="--network sepolia" ``` After a brief wait... diff --git a/courses/advanced-foundry/3-develop-defi-protocol/12-defi-deposit-and-mint/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/12-defi-deposit-and-mint/+page.md index 287ffbebc..f22bf4270 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/12-defi-deposit-and-mint/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/12-defi-deposit-and-mint/+page.md @@ -221,7 +221,7 @@ contract DSCEngine is ReentrancyGuard { return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION; } - function depositCollaterAndMintDsc() external {} + function depositCollateralAndMintDsc() external {} function redeemCollateralForDsc() external {} diff --git a/courses/advanced-foundry/3-develop-defi-protocol/16-defi-leveling-up-testing/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/16-defi-leveling-up-testing/+page.md index 5c4e4e8da..9c8d2481f 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/16-defi-leveling-up-testing/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/16-defi-leveling-up-testing/+page.md @@ -100,13 +100,13 @@ Alternatively to this, we have static analysis as a tool available to us. In sta function withdraw() external { uint256 balance = balances[msg.sender]; require(balance > 0); - (bool successs, ) = msg.sender.call{value:balance}(""); + (bool success, ) = msg.sender.call{value:balance}(""); require(success, "Failed to send Ether"); balances[msg.sender] = 0; } ``` -The above withdraw function has a classic reentrancy attack. We know an issue like this arrises from not following the CEI pattern! A static analysis tool like Slither will be able to pick up on this quite easily. +The above withdraw function has a classic reentrancy attack. We know an issue like this arises from not following the CEI pattern! A static analysis tool like Slither will be able to pick up on this quite easily. ::image{src='/foundry-defi/16-defi-leveling-up-testing/defi-leveling-up-testing3.png' style='width: 100%; height: auto;'} diff --git a/courses/advanced-foundry/3-develop-defi-protocol/3-defi-stablecoins-but-actually/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/3-defi-stablecoins-but-actually/+page.md index 1760f36fd..82df5e8f0 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/3-defi-stablecoins-but-actually/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/3-defi-stablecoins-but-actually/+page.md @@ -28,7 +28,7 @@ That's really it, at the end of the day. More accurately put: ::image{src='/foundry-defi/3-defi-stablecoins-but-actually/defi-stablecoins-but-actually1.png' style='width: 100%; height: auto;'} -[**Investopedia**](https://www.investopedia.com/terms/s/stablecoin.asp) describes `stablecoins` as - Cryptocurriencies the value of which is pegged, or tied, to that of another currency, commondity or financial instrument. +[**Investopedia**](https://www.investopedia.com/terms/s/stablecoin.asp) describes `stablecoins` as - Cryptocurrencies the value of which is pegged, or tied, to that of another currency, commodity or financial instrument. Aaand this is the first place I diverge from conventional media. @@ -178,7 +178,7 @@ DAI is: DAI is one of the most influential DeFi projects ever created. -Effectively how DAI works is, a user deposits some form of crypto collateral, such as ETH, and based on the currect value of that collateral in US Dollars, some value of DAI is minted the user. It's only possible to mint _less_ DAI than the value of collateral a user has deposited. In this way the stablecoin is said to be over-collateralized. +Effectively how DAI works is, a user deposits some form of crypto collateral, such as ETH, and based on the current value of that collateral in US Dollars, some value of DAI is minted the user. It's only possible to mint _less_ DAI than the value of collateral a user has deposited. In this way the stablecoin is said to be over-collateralized. > ❗ **NOTE** > DAI also has an annual stability fee on deposited collateral ~2% @@ -285,7 +285,7 @@ So, to summarize a bit: **_Why are stablecoins minted?_** -- Investers like to make leveraged bets. +- Investors like to make leveraged bets. ### Wrap Up diff --git a/courses/advanced-foundry/3-develop-defi-protocol/4-defi-decentralized-stablecoin/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/4-defi-decentralized-stablecoin/+page.md index 9852fac7f..12ed069ae 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/4-defi-decentralized-stablecoin/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/4-defi-decentralized-stablecoin/+page.md @@ -55,7 +55,7 @@ Alright, with things scoped out a bit, let's dive into writing some code. Start ```js // SPDX-License-Identifier: MIT -// This is considered an Exogenous, Decentralized, Anchored (pegged), Crypto Collateralized low volitility coin +// This is considered an Exogenous, Decentralized, Anchored (pegged), Crypto Collateralized low volatility coin // Layout of Contract: // version @@ -115,7 +115,7 @@ libs = ["lib"] remappings = ["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts"] ``` -Rather than importing a standard ERC20 contract, we'll be leveraging the ERC20Burnable extention of this standard. ERC20Burnable includes `burn` functionality for our tokens which will be important when we need to take the asset out of circulation to support stability. +Rather than importing a standard ERC20 contract, we'll be leveraging the ERC20Burnable extension of this standard. ERC20Burnable includes `burn` functionality for our tokens which will be important when we need to take the asset out of circulation to support stability. ```js // SPDX-License-Identifier: MIT @@ -138,7 +138,7 @@ contract DecentralizedStableCoin is ERC20Burnable { } ``` -Because we're inheriting ERC20Burnable, and it inherits ERC20, we needs to satify the standard ERC20 constructor parameters within our contracts constructor. We've set the name `DecentralizedStableCoin` and the symbol `DSC`. +Because we're inheriting ERC20Burnable, and it inherits ERC20, we need to satisfy the standard ERC20 constructor parameters within our contracts constructor. We've set the name `DecentralizedStableCoin` and the symbol `DSC`. All of the properties of our protocol are going to be governed ultimately by the DSCEngine.sol contract. Functionality like the stability mechanism, including minting and burning, need to be controlled by the DSCEngine to maintain the integrity of the stablecoin. @@ -149,7 +149,7 @@ In order to accomplish this, we're going to also inherit `Ownable` with Decentra > in the constructor. We have to modify our code to account for this when > running `forge build` so that our project will not error. Like this: > `constructor(address initialOwner) ERC20("DecentralizedStableCoin", "DSC") -Ownerable(initialOwner) {}` +Ownable(initialOwner) {}` ```js import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/courses/advanced-foundry/3-develop-defi-protocol/5-defi-dscengine-setup/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/5-defi-dscengine-setup/+page.md index f3c79eec5..3d0b66421 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/5-defi-dscengine-setup/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/5-defi-dscengine-setup/+page.md @@ -17,7 +17,7 @@ Begin with creating a new file, `src/DSCEngine.sol`. I'll bring over my contract ```js // SPDX-License-Identifier: MIT -// This is considered an Exogenous, Decentralized, Anchored (pegged), Crypto Collateralized low volitility coin +// This is considered an Exogenous, Decentralized, Anchored (pegged), Crypto Collateralized low volatility coin // Layout of Contract: // version @@ -111,7 +111,7 @@ contract DSCEngine { /////////////////////////// // External Functions // /////////////////////////// - function depositCollaterAndMintDsc() external {} + function depositCollateralAndMintDsc() external {} function depositCollateral() external {} diff --git a/courses/advanced-foundry/3-develop-defi-protocol/6-defi-deposit-collateral/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/6-defi-deposit-collateral/+page.md index 5faf7ec85..1e9fa2320 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/6-defi-deposit-collateral/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/6-defi-deposit-collateral/+page.md @@ -495,7 +495,7 @@ contract DSCEngine is ReentrancyGuard { } } - function depositCollaterAndMintDsc() external {} + function depositCollateralAndMintDsc() external {} function redeemCollateralForDsc() external {} diff --git a/courses/advanced-foundry/3-develop-defi-protocol/7-defi-mint-dsc/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/7-defi-mint-dsc/+page.md index 46a79f5cc..2d9212e75 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/7-defi-mint-dsc/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/7-defi-mint-dsc/+page.md @@ -10,7 +10,7 @@ _Follow along the course with this video._ Now that we've a way to deposit collateral, the next logical step would be to mint DSC. -The `mintDsc` function is likely going to be surprisely complex. There are a number of things we'll need to accomplish when minting our stablecoin. Primarily we'll need to check if the account's collateral value supports the amount of `DSC` being minted. To do this we'll need to engage `Chainlink` price feeds, do value conversions and more. Let's get started. +The `mintDsc` function is likely going to be surprisingly complex. There are a number of things we'll need to accomplish when minting our stablecoin. Primarily we'll need to check if the account's collateral value supports the amount of `DSC` being minted. To do this we'll need to engage `Chainlink` price feeds, do value conversions and more. Let's get started. ```js /////////////////////////// @@ -475,7 +475,7 @@ contract DSCEngine is ReentrancyGuard { return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION; } - function depositCollaterAndMintDsc() external {} + function depositCollateralAndMintDsc() external {} function redeemCollateralForDsc() external {} diff --git a/courses/advanced-foundry/3-develop-defi-protocol/8-defi-health-factor/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/8-defi-health-factor/+page.md index 415420687..5bb560141 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/8-defi-health-factor/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/8-defi-health-factor/+page.md @@ -107,7 +107,7 @@ uint256 private constant LIQUIDATION_PRECISION = 100; uint256 private constant MIN_HEALTH_FACTOR = 1e18; ``` -We're ready to put our `_healthFactor` function and our `MIN_HEALTH_FACTOR` constant to work. We can use these to declare a conditional statemment within `_revertIfHealthFactorIsBroken`, which will revert with a custom error if the conditional fails to pass. +We're ready to put our `_healthFactor` function and our `MIN_HEALTH_FACTOR` constant to work. We can use these to declare a conditional statement within `_revertIfHealthFactorIsBroken`, which will revert with a custom error if the conditional fails to pass. ```js function _revertIfHealthFactorIsBroken(address user) internal view { @@ -342,7 +342,7 @@ contract DSCEngine is ReentrancyGuard { return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION; } - function depositCollaterAndMintDsc() external {} + function depositCollateralAndMintDsc() external {} function redeemCollateralForDsc() external {} diff --git a/courses/advanced-foundry/3-develop-defi-protocol/9-defi-finishing-mint-dsc/+page.md b/courses/advanced-foundry/3-develop-defi-protocol/9-defi-finishing-mint-dsc/+page.md index a634570e4..a00125085 100644 --- a/courses/advanced-foundry/3-develop-defi-protocol/9-defi-finishing-mint-dsc/+page.md +++ b/courses/advanced-foundry/3-develop-defi-protocol/9-defi-finishing-mint-dsc/+page.md @@ -275,7 +275,7 @@ contract DSCEngine is ReentrancyGuard { return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION; } - function depositCollaterAndMintDsc() external {} + function depositCollateralAndMintDsc() external {} function redeemCollateralForDsc() external {} diff --git a/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md b/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md index d112365fc..a8fc07d58 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/19-create-claiming-script/+page.md @@ -1,5 +1,5 @@ --- -title: Create Claming Script +title: Create Claiming Script --- _Follow along with the video_ diff --git a/courses/advanced-foundry/4-merkle-airdrop/2-project-setup/+page.md b/courses/advanced-foundry/4-merkle-airdrop/2-project-setup/+page.md index 4c35d947a..765f31e05 100644 --- a/courses/advanced-foundry/4-merkle-airdrop/2-project-setup/+page.md +++ b/courses/advanced-foundry/4-merkle-airdrop/2-project-setup/+page.md @@ -66,7 +66,7 @@ function claim(address account) external { } ``` -However, looping through an array that can grow indefinately can lead to **performance issues** and calling this function. If there are for example, hundreds of claimers, will become cost prohibitive and will cause a Denial Of Service (DOS). Merkle trees will help solving this issue. +However, looping through an array that can grow indefinitely can lead to **performance issues** and calling this function. If there are for example, hundreds of claimers, will become cost prohibitive and will cause a Denial Of Service (DOS). Merkle trees will help solving this issue. ### Merkle Trees and Proofs diff --git a/courses/advanced-foundry/5-upgradeable-smart-contracts/3-eip-1967/+page.md b/courses/advanced-foundry/5-upgradeable-smart-contracts/3-eip-1967/+page.md index aef663411..7848be6f2 100644 --- a/courses/advanced-foundry/5-upgradeable-smart-contracts/3-eip-1967/+page.md +++ b/courses/advanced-foundry/5-upgradeable-smart-contracts/3-eip-1967/+page.md @@ -135,7 +135,7 @@ This virtual function is returning the implementation address and showcases the [**Ethereum Improvement Proposal (now ERC)-1967**](https://eips.ethereum.org/EIPS/eip-1967). -The need to regularly utilize storage to reference things in implementation (specifically the implementation address) led to the desire for EIP-1967: Standard Proxy Storage Slots. This proposal would allocate standardardized slots in storage specifically for use by proxies. +The need to regularly utilize storage to reference things in implementation (specifically the implementation address) led to the desire for EIP-1967: Standard Proxy Storage Slots. This proposal would allocate standardized slots in storage specifically for use by proxies. In our minimalistic example, we're assigning our \_IMPLEMENTATION_SLOT to a constant value for this purpose. diff --git a/courses/advanced-foundry/5-upgradeable-smart-contracts/4-uups/+page.md b/courses/advanced-foundry/5-upgradeable-smart-contracts/4-uups/+page.md index 522ab391b..111564d05 100644 --- a/courses/advanced-foundry/5-upgradeable-smart-contracts/4-uups/+page.md +++ b/courses/advanced-foundry/5-upgradeable-smart-contracts/4-uups/+page.md @@ -83,7 +83,7 @@ contract BoxV2 { } ``` -In order to implement the UUPS functionality, we're going to leverage an OpenZeppelin library. This one is actually different from the OpenZeppelin/Contracts we're used to and is tailered specifically for upgradeability. Let's install this library. +In order to implement the UUPS functionality, we're going to leverage an OpenZeppelin library. This one is actually different from the OpenZeppelin/Contracts we're used to and is tailored specifically for upgradeability. Let's install this library. ```bash forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit @@ -175,7 +175,7 @@ uint256[50] private __gap; ::image{src='/foundry-upgrades/4-UUPS/UUPS2.png' style='width: 100%; height: auto;'} -If you recall to previous lessons, when values are assigned by a function, the variable name doesn't ultimately matter as the value is assigned to a storage slot. We saw that storage clashes were possible when an upgraded implementation contract made changes to the order of storage variable assignements, leading to some funky behaviours. +If you recall to previous lessons, when values are assigned by a function, the variable name doesn't ultimately matter as the value is assigned to a storage slot. We saw that storage clashes were possible when an upgraded implementation contract made changes to the order of storage variable assignments, leading to some funky behaviours. Storage gaps are an effort to get ahead of this problem by pre-allocating an array of slots to account for future protocol changes. This effectively creates a buffer of available storage slots to be used by subsequent implementation contracts for new variables and functionality. @@ -203,7 +203,7 @@ contract BoxV1 is UUPSUpgradeable { } ``` -BoxV1 as written above is deployable and could be upgraded, BoxV2 can't be upgraded, but we'll cross that bridge later. If you look at the examples of OpenZepplin UUPS contract on their Contract Wizard, you'll see that they are importing far more than we are however. One of which is the Initializable.sol library. Let's import this into BoxV1 and discuss it's importance here. +BoxV1 as written above is deployable and could be upgraded, BoxV2 can't be upgraded, but we'll cross that bridge later. If you look at the examples of OpenZeppelin UUPS contract on their Contract Wizard, you'll see that they are importing far more than we are however. One of which is the Initializable.sol library. Let's import this into BoxV1 and discuss it's importance here. ```js import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; diff --git a/courses/advanced-foundry/6-account-abstraction/1-introduction/+page.md b/courses/advanced-foundry/6-account-abstraction/1-introduction/+page.md index cd545d8c7..9f9f79bbe 100644 --- a/courses/advanced-foundry/6-account-abstraction/1-introduction/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/1-introduction/+page.md @@ -26,7 +26,7 @@ Another challenge is that traditional transactions are validated by the sender's ::image{src='/foundry-account-abstraction/1-introduction/trade-eth-trans.png' style='width: 100%; height: auto;'} -The traditional Ethereum transactions consists of first the signing of the transaction by the sender's private key, and then sending it to an Ethereum node. The node verifies that the signature is valid and if so, adds it to its mempool for later inclusion in a block. Account Absctraction, as we have already mentioned add improvemnts to this process. There are two entry points that we need to understand - Ethereum's `EntryPoint.sol` and zkSync's native integration. +The traditional Ethereum transactions consists of first the signing of the transaction by the sender's private key, and then sending it to an Ethereum node. The node verifies that the signature is valid and if so, adds it to its mempool for later inclusion in a block. Account Abstraction, as we have already mentioned add improvements to this process. There are two entry points that we need to understand - Ethereum's `EntryPoint.sol` and zkSync's native integration. ### Ethereum – EntryPoint.sol Ethereum implements account abstraction using a smart contract called `EntryPoint.sol`. This contract acts as a gateway for handling user operations and transactions in a more flexible manner. diff --git a/courses/advanced-foundry/6-account-abstraction/11-signed-user-op/+page.md b/courses/advanced-foundry/6-account-abstraction/11-signed-user-op/+page.md index ee067e693..85cbc407f 100644 --- a/courses/advanced-foundry/6-account-abstraction/11-signed-user-op/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/11-signed-user-op/+page.md @@ -388,7 +388,7 @@ Just for the purpose of testing or working on a local chain, we are going to hav ### Questions for Review -> ❗ **NOTE** These questions may be a bit challenging. Take your time and don't stres too much. We learn one brick at a time. +> ❗ **NOTE** These questions may be a bit challenging. Take your time and don't stress too much. We learn one brick at a time. 1. In the testRecoverSignedOp function, what is the significance of using ECDSA.recover and what is being verified? diff --git a/courses/advanced-foundry/6-account-abstraction/15-advanced-debugging/+page.md b/courses/advanced-foundry/6-account-abstraction/15-advanced-debugging/+page.md index 6b262708b..2ebcc7c9b 100644 --- a/courses/advanced-foundry/6-account-abstraction/15-advanced-debugging/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/15-advanced-debugging/+page.md @@ -4,7 +4,7 @@ We left off of our previous lesson with a debugging challenge. If you weren't ab --- -### Degug with Forge +### Debug with Forge Forge has some great debugging tools. Let's check them out. Run the following in your terminal. diff --git a/courses/advanced-foundry/6-account-abstraction/23-zksync-simulations/+page.md b/courses/advanced-foundry/6-account-abstraction/23-zksync-simulations/+page.md index 6d3576d4a..20e1af9ff 100644 --- a/courses/advanced-foundry/6-account-abstraction/23-zksync-simulations/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/23-zksync-simulations/+page.md @@ -22,7 +22,7 @@ Let's start by making two updates to our code. --- ```js -foudryup - zksync; +foundryup - zksync; ``` ```js diff --git a/courses/advanced-foundry/6-account-abstraction/25-execute-tx/+page.md b/courses/advanced-foundry/6-account-abstraction/25-execute-tx/+page.md index 32e888e0d..ec0a6c3fb 100644 --- a/courses/advanced-foundry/6-account-abstraction/25-execute-tx/+page.md +++ b/courses/advanced-foundry/6-account-abstraction/25-execute-tx/+page.md @@ -14,7 +14,7 @@ Let's get started! ### Variables from Transaction Struct -We know that once the validation phase is done, it will send the transaction to the main node for execution. We aren't actually done with the validation phase just yet, as we haven't handled the acutal payment. But for this lesson, we will turn our attention to our executeTransaction function. We will be using some [variables from the `Transaction` struct:](https://github.com/Cyfrin/foundry-era-contracts/blob/3f99de4a37b126c5cb0466067f37be0c932167b2/src/system-contracts/contracts/libraries/MemoryTransactionHelper.sol) +We know that once the validation phase is done, it will send the transaction to the main node for execution. We aren't actually done with the validation phase just yet, as we haven't handled the actual payment. But for this lesson, we will turn our attention to our executeTransaction function. We will be using some [variables from the `Transaction` struct:](https://github.com/Cyfrin/foundry-era-contracts/blob/3f99de4a37b126c5cb0466067f37be0c932167b2/src/system-contracts/contracts/libraries/MemoryTransactionHelper.sol) - `uint256 to`: The callee (address or contract being called) - `uint256 value`: The value to pass with the transaction. diff --git a/courses/advanced-foundry/7-daos/1-intro/+page.md b/courses/advanced-foundry/7-daos/1-intro/+page.md index 003e5e484..5933b6b52 100644 --- a/courses/advanced-foundry/7-daos/1-intro/+page.md +++ b/courses/advanced-foundry/7-daos/1-intro/+page.md @@ -47,7 +47,7 @@ We can access their governance system, and view past and pending proposals, thro ::image{src='/foundry-daos/1-intro/intro1.png' style='width: 100%; height: auto;'} -If we navigate to one [**specific proposal**](https://compound.finance/governance/proposals/256), we can gain a lot of insight into how this process works. The proposal view breaks down the votes received, the number of particating addresses and importantly the Proposal History. We're able to see that every proposal begins with a transaction. +If we navigate to one [**specific proposal**](https://compound.finance/governance/proposals/256), we can gain a lot of insight into how this process works. The proposal view breaks down the votes received, the number of participating addresses and importantly the Proposal History. We're able to see that every proposal begins with a transaction. ::image{src='/foundry-daos/1-intro/intro2.png' style='width: 100%; height: auto;'} @@ -80,7 +80,7 @@ If voting succeeds, a proposal will be queued for execution. This queue period a - security checks - challenges to the proposal -- an exit opportunity for stakeholers who disagree with the proposal +- an exit opportunity for stakeholders who disagree with the proposal - preparation for execution Following this timelock period, the proposal is executed! @@ -100,7 +100,7 @@ One consideration that must be made is: **How do we identify stakeholders, or me Often this is handled via an ERC20 or an NFT of some kind, but this runs the risk of being _less_ fair if the tokens are more available to the wealthy than others. This is not dissimilar to Web2 companies and how the voting power of company shares works. -One methodology is the "Skin in the Game" method whereby voting records are recording and negative outcomes result in tokens/voting power being lost. This is beneficial in that it holds users accountable for the decisions they make. A downside to this approach is how difficult it can be to reach a concensus on what a _bad_ outcome is. +One methodology is the "Skin in the Game" method whereby voting records are recording and negative outcomes result in tokens/voting power being lost. This is beneficial in that it holds users accountable for the decisions they make. A downside to this approach is how difficult it can be to reach a consensus on what a _bad_ outcome is. A third approach is something called "Proof of Personhood Participation" and while potentially ideal, isn't something with a sound implementation yet. The idea would be a method by which someone can be verified as being a single human entity, but the logics of this are difficult and rub up against anonymity. Some projects like WorldCoin are trying to find solutions here! @@ -120,7 +120,7 @@ It's important to be careful the the implementation of any off-chain features, i ### Tools -There are a number of no-code/low-code tools that can fascilitate a DAO, services like [**DAO Stack**](https://www.alchemy.com/dapps/daostack), [**Aragon**](https://aragon.org/), [**Colony**](https://colony.io/) and [**DAO House**](https://www.daohouse.global/) can greatly assist in the operations side of running a DAO. +There are a number of no-code/low-code tools that can facilitate a DAO, services like [**DAO Stack**](https://www.alchemy.com/dapps/daostack), [**Aragon**](https://aragon.org/), [**Colony**](https://colony.io/) and [**DAO House**](https://www.daohouse.global/) can greatly assist in the operations side of running a DAO. Additional tools with more granular control and integrations include things like [**Snapshot**](https://snapshot.org/) which allows a team to glean sentiment of a community before execution while also including functionality to manage and execute proposals if desired. Other tools to check out include [**Zodiac**](https://github.com/gnosisguild/zodiac) a development library offered by Gnosis and our old friends [**OpenZeppelin**](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/governance). We'll be using the OZ library in our development for sure! diff --git a/courses/advanced-foundry/7-daos/3-setup/+page.md b/courses/advanced-foundry/7-daos/3-setup/+page.md index 6b0acfbef..15f67a55f 100644 --- a/courses/advanced-foundry/7-daos/3-setup/+page.md +++ b/courses/advanced-foundry/7-daos/3-setup/+page.md @@ -62,7 +62,7 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; contract Box is Ownable {} ``` -This contract is only going to serve as the contract which is managed by our DAO. In practice this contract could be quite complex, or multiple contracts could be managed by a single DAO, but for our purposes we'll keep things concise. The goal is to understanding how the voting mechanism allows the DAO to autonmously execute function calls. +This contract is only going to serve as the contract which is managed by our DAO. In practice this contract could be quite complex, or multiple contracts could be managed by a single DAO, but for our purposes we'll keep things concise. The goal is to understanding how the voting mechanism allows the DAO to autonomously execute function calls. Let's add the ability to store and retrieve a value from our contract. The ability to change this number will be modifier with `onlyOwner` such that only our DAO may call it. diff --git a/courses/advanced-foundry/7-daos/4-governance-tokens/+page.md b/courses/advanced-foundry/7-daos/4-governance-tokens/+page.md index 199c766e4..b674d8547 100644 --- a/courses/advanced-foundry/7-daos/4-governance-tokens/+page.md +++ b/courses/advanced-foundry/7-daos/4-governance-tokens/+page.md @@ -46,7 +46,7 @@ contract GovToken is ERC20, ERC20Permit, ERC20Votes { } ``` -Let's go over how this differs from a standard ERC20. Primarily it's the same base token contract with 2 extentions to the functionality, Permit and Votes. +Let's go over how this differs from a standard ERC20. Primarily it's the same base token contract with 2 extensions to the functionality, Permit and Votes. **ERC20Permit:** diff --git a/courses/advanced-foundry/7-daos/5-governor-contract/+page.md b/courses/advanced-foundry/7-daos/5-governor-contract/+page.md index eb78f9ad2..d10c10d2c 100644 --- a/courses/advanced-foundry/7-daos/5-governor-contract/+page.md +++ b/courses/advanced-foundry/7-daos/5-governor-contract/+page.md @@ -32,7 +32,7 @@ Timelock - Configuration related to delays and timelines for various parts of th Upgradeability - Our bells from last lesson should be going off! This includes proxy functionality within our DAO -We'll keep everything default for this excercise, let's just copy the provided Governor contract into our own file `src/MyGovernor.sol`. +We'll keep everything default for this exercise, let's just copy the provided Governor contract into our own file `src/MyGovernor.sol`. ```js // SPDX-License-Identifier: MIT @@ -294,11 +294,11 @@ This contract extracts voting weight from the ERC20 tokens used for a protocols **GovernorSettings.sol:** -An extension contract that allows configuration of things like voting delay, voting period and proposalThreshhold to the protocol. +An extension contract that allows configuration of things like voting delay, voting period and proposalThreshold to the protocol. **GovernorCountingSimple.sol:** -This extention implements a simplied vote counting mechanism by which each proposal is assigned a ProposalVote struct in which forVotes, againstVotes and abstainVotes are tallied. +This extension implements a simplified vote counting mechanism by which each proposal is assigned a ProposalVote struct in which forVotes, againstVotes and abstainVotes are tallied. ```js struct ProposalVotes { @@ -311,7 +311,7 @@ struct ProposalVotes { **GovernorVotesQuorumFraction:** -An extention which assists in token voting weight extraction. +An extension which assists in token voting weight extraction. **GovernorTimelockControl.sol:** diff --git a/courses/advanced-foundry/7-daos/6-tests/+page.md b/courses/advanced-foundry/7-daos/6-tests/+page.md index 81977b8ca..3d1ce9cb5 100644 --- a/courses/advanced-foundry/7-daos/6-tests/+page.md +++ b/courses/advanced-foundry/7-daos/6-tests/+page.md @@ -13,7 +13,7 @@ Let's jump right into writing our tests. Begin with creating `test/MyGovernorTes ```js // SPDX-License-Identifier: MIT -pragme solidity ^0.8.18; +pragma solidity ^0.8.18; import {Test} from "forge-std/Test.sol"; import {MyGovernor} from "../src/MyGovernor.sol"; @@ -163,7 +163,7 @@ function testGovernanceUpdatesBox() public {} The function we're going to call is store, of course, so we'll declare the value we expect to pass. Beyond this, the first thing we'll need to do to kick off a vote is submit a proposal. ```js -function propose(addresses[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory descrription) public virtual override returns (uint256){...} +function propose(addresses[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description) public virtual override returns (uint256){...} ``` Many of these parameters we should already know. The target of our proposed function call is going to be our Box contract address, the value we're passing with the function call is zero, and the calldata is going to be our function signature encoded with our data. All things we've done before! @@ -203,7 +203,7 @@ function testGovernanceUpdatesBox() public { It might be a good idea for our test to check the state of the proposal that's been submitted! We can do this by calling the `state` function with our proposalId. This call will return a uint256 which pertains to an index of the ProposalState enum. ```js -abstract constract IGovernor is IERC165 { +abstract contract IGovernor is IERC165 { enum ProposalState { Pending, Active, diff --git a/courses/advanced-foundry/8-security/4-top-tools/+page.md b/courses/advanced-foundry/8-security/4-top-tools/+page.md index a535c1133..cdcc44d6b 100644 --- a/courses/advanced-foundry/8-security/4-top-tools/+page.md +++ b/courses/advanced-foundry/8-security/4-top-tools/+page.md @@ -52,13 +52,13 @@ Technically, there's nothing wrong with this code. It would only be through read Let's talk about some of the tools security professionals and developers have in their toolbox. -1. **Test Suites:** This is the first line of defence and why we placed such an emphasis on them throughout the course. All of the most popular development frameworks include test suites, use them, use them often, catch those bugs. +1. **Test Suites:** This is the first line of defense and why we placed such an emphasis on them throughout the course. All of the most popular development frameworks include test suites, use them, use them often, catch those bugs. 2. **Static Analysis:** Static analysis is the process of checking code for issues without executing anything. Popular entries here include [**Aderyn**](https://github.com/Cyfrin/aderyn), [**Slither**](https://github.com/crytic/slither) and [**Mithril**](https://github.com/Consensys/mythril) 3. **Fuzz Testing:** a specific test suite methodology involving providing random data as inputs during testing. - Two variantions exist including stateless and stateful fuzz testing. Stateless fuzz tests abandon the result of a previous test before running a new test, with a new contract state. Stateful, conversely will remember the ending state of one run and use this as the starting start for the next fuzz run. + Two variations exist including stateless and stateful fuzz testing. Stateless fuzz tests abandon the result of a previous test before running a new test, with a new contract state. Stateful, conversely will remember the ending state of one run and use this as the starting start for the next fuzz run. -4. **Differential Testing:** We don't cover this in depth, but the idea is to write code in multiple ways and compare the results to eachother to ensure validity. +4. **Differential Testing:** We don't cover this in depth, but the idea is to write code in multiple ways and compare the results to each other to ensure validity. 5. **Formal Verification:** Formal Verification is a generic term for applying formal methods to verify the correctness of a system. Applying formal methods pertains to anything based on mathematical proofs, these are mathematical expressions that solve for the soundsness and validity of a system, a proof of correctness, or whether or not a bug _must_ exist. ie Symbolic Execution. @@ -67,7 +67,7 @@ Let's talk about some of the tools security professionals and developers have in There's a great article hosted by hackmd that compares many of these tools and how they work, I encourage you to [**check it out**](https://hackmd.io/@SaferMaker/EVM-Sym-Exec). -6. **AI Tools:** These can be hit or miss, but are absolutely evolving quickly. Any developer can find value in leveraging tools like Copilot, or state of the art models suchs a GPT4o, in their process. +6. **AI Tools:** These can be hit or miss, but are absolutely evolving quickly. Any developer can find value in leveraging tools like Copilot, or state of the art models such as GPT4o, in their process. These tools, I would say, aren't yet reliable enough to be depended upon, but they can go a long way towards helping to quickly understand the context of codebases or summarizing/clarifying documentation. Don't rely on them, but keep AI tooling on your radar. @@ -299,7 +299,7 @@ contract CaughtWithStatefulFuzzTest is StdInvariant, Test { } ``` -We can see here the running our stateful fuzz test `invariant_testMathDoesntReturnZero` indentifies the arguments to pass and order of functions to call which breaks our invariant. +We can see here the running our stateful fuzz test `invariant_testMathDoesntReturnZero` identifies the arguments to pass and order of functions to call which breaks our invariant. ::image{src='/foundry-security/3-top-tools/top-tools3.png' style='width: 100%; height: auto;'} diff --git a/courses/advanced-foundry/8-security/6-formal-verification/+page.md b/courses/advanced-foundry/8-security/6-formal-verification/+page.md index 57c652b76..e1c678e11 100644 --- a/courses/advanced-foundry/8-security/6-formal-verification/+page.md +++ b/courses/advanced-foundry/8-security/6-formal-verification/+page.md @@ -95,13 +95,13 @@ Alternatively to this, we have static analysis as a tool available to us. In sta function withdraw() external { uint256 balance = balances[msg.sender]; require(balance > 0); - (bool successs, ) = msg.sender.call{value:balance}(""); + (bool success, ) = msg.sender.call{value:balance}(""); require(success, "Failed to send Ether"); balances[msg.sender] = 0; } ``` -The above withdraw function has a classic reentrancy attack. We know an issue like this arrises from not following the CEI pattern! A static analysis tool like Slither will be able to pick up on this quite easily. +The above withdraw function has a classic reentrancy attack. We know an issue like this arises from not following the CEI pattern! A static analysis tool like Slither will be able to pick up on this quite easily. ::image{src='/foundry-defi/16-defi-leveling-up-testing/defi-leveling-up-testing3.png' style='width: 100%; height: auto;'} @@ -132,7 +132,7 @@ contract SmallSol { } ``` -In the above simple contract example, the obvious path is returning the `result of a + 1`. Another less obvious path would be this function `f` reverting due to overflow. Symbolic Execution, through it's mathetmatical modelling, would traverse all possible paths, looking for criteria that break our invariant. These paths might be represented something like this: +In the above simple contract example, the obvious path is returning the `result of a + 1`. Another less obvious path would be this function `f` reverting due to overflow. Symbolic Execution, through it's mathematical modelling, would traverse all possible paths, looking for criteria that break our invariant. These paths might be represented something like this: **Path 1:** `assert(a not 2**256 - 1); a:= a+1; return a;` diff --git a/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/4-building-an-erc721-contract/+page.md b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/4-building-an-erc721-contract/+page.md index 60f8c6d8f..93ef019d0 100644 --- a/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/4-building-an-erc721-contract/+page.md +++ b/courses/advanced-python-vyper-smart-contract-development/1-moccasin-nft/4-building-an-erc721-contract/+page.md @@ -47,7 +47,7 @@ We'll create a little basic NFT in here. Now, I know in that video we went over from snekmate.tokens import erc721 from snekmate.auth import ownable as ow initializes: ow -initializes: erc721(owmable := ow) +initializes: erc721(ownable := ow) @deploy def __init__(): ow.__init__() @@ -80,4 +80,3 @@ exports: erc721.interface ``` So, we get all the functions of the ERC721. Nice. - diff --git a/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md index b836faacd..4e0de67ff 100644 --- a/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md +++ b/courses/advanced-python-vyper-smart-contract-development/2-moccasin-portfolio-rebalance/8-juypter-notebook/+page.md @@ -7,21 +7,21 @@ Before we can use a Jupyter notebook, we'll need to create one. To do this, crea The next step is to select the kernel. We want to make sure we're using the correct Python environment. To do this, click on the kernel selector, and then select "Python Environments". We want to choose the ".venv" environment. If we haven't already added Mocassin to our ".venv", we can do this using the following terminal commands: ```bash -uv add moccasain +uv add moccasin uv sync ``` Now that we've selected our kernel, we'll go ahead and copy and paste the following code into the first cell. ```python -from moccasain import setup_notebook +from moccasin import setup_notebook setup_notebook() ``` To run this code, hit Shift Enter. Now, let's add a new code cell and copy the following code: ```python -from moccasain.config import get_active_network +from moccasin.config import get_active_network active_network = get_active_network() print(active_network.name) ``` diff --git a/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md index 5fe03fdfd..acaf3903a 100644 --- a/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md +++ b/courses/advanced-python-vyper-smart-contract-development/5-moccasin-upgrades/7-what-do-i-do-now_/+page.md @@ -1,6 +1,6 @@ ## What Do I Do Now? -We've finished the advanced Mochassin curriculum here. You should be proud of yourself! Now, we're going to scroll all the way down to the bottom because there's more to learn. +We've finished the advanced Mocassin curriculum here. You should be proud of yourself! Now, we're going to scroll all the way down to the bottom because there's more to learn. The most common question we get asked after these courses is "What do I do now?". There's always more to learn, so here are some resources on where to go next. @@ -39,8 +39,8 @@ Another great option is competitive audits. These are a great way to become a po CodeHawks also has a thing called "First Flights", which are beginner-friendly audit competitions. We've specifically placed some bugs in there that you should be able to find. -If you're looking at Cyfirn Updraft, they have a lot of curriculum, including one of our favorites, the Python and Vyper course. There are also more advanced courses, like Assembly and Formal Verification, Smart Contract DevOps, and Smart Contract Security. +If you're looking at Cyfrin Updraft, they have a lot of curriculum, including one of our favorites, the Python and Vyper course. There are also more advanced courses, like Assembly and Formal Verification, Smart Contract DevOps, and Smart Contract Security. We also have a course on Curve StableSwap, which is all in Vyper, which you've just learned. Curve is a multi-billion dollar protocol, and the codebase is used and forked by tons of other projects, so learning Curve will teach you more about other protocols. -In general, be sure to subscribe to anything Cyfirn puts out. We're dedicated to making the lives of developers and security researchers better! +In general, be sure to subscribe to anything Cyfrin puts out. We're dedicated to making the lives of developers and security researchers better! diff --git a/courses/blockchain-basics/1-basics/14-blockchain-fundamentals/+page.md b/courses/blockchain-basics/1-basics/14-blockchain-fundamentals/+page.md index 47c56a270..1abcd6296 100644 --- a/courses/blockchain-basics/1-basics/14-blockchain-fundamentals/+page.md +++ b/courses/blockchain-basics/1-basics/14-blockchain-fundamentals/+page.md @@ -57,7 +57,7 @@ Proof of work is a system of sybil resistance used in many blockchains, in its e Proof of Work needs to be combined with a `chain selection rule` to create `consensus`. -A `chain selection rule` is implemented as a means to determine which blockchain is the _real_ blockchain. Bitcoin (and prior to the merge, Ethereum), both use something called `Nakamoto Consensus`. This is a combination of Proof of Work (Etherum has since switched to Proof of Stake) and the `longest chain rule`. +A `chain selection rule` is implemented as a means to determine which blockchain is the _real_ blockchain. Bitcoin (and prior to the merge, Ethereum), both use something called `Nakamoto Consensus`. This is a combination of Proof of Work (Ethereum has since switched to Proof of Stake) and the `longest chain rule`. In the `longest chain rule`, the decentralized network decides that whichever chain has the most number of blocks will be the valid, or _real_ blockchain. When we saw `block confirmations` in Etherscan earlier, this was representing the number of blocks ahead of our transaction in the longest chain. diff --git a/courses/blockchain-basics/1-basics/15-l1s-l2s-and-rollups/+page.md b/courses/blockchain-basics/1-basics/15-l1s-l2s-and-rollups/+page.md index 04742fbb4..b1c3b0b43 100644 --- a/courses/blockchain-basics/1-basics/15-l1s-l2s-and-rollups/+page.md +++ b/courses/blockchain-basics/1-basics/15-l1s-l2s-and-rollups/+page.md @@ -40,7 +40,7 @@ This **fraud proof process** involves the operator engaging in a _call and respo ### Zero-Knowledge (ZK) Rollups -ZK rollups use validity proofs, known as _zk proofs_, to verify transaction batches. In this process, the **prover** (operator) generates a zk proof to show that their inputs (the transactions) satisfy this equation. A **verifier** (an L1 contract) then checks this proof to ensure that the output matches the expected result. The solution that the prover uses to demostrate that their input satisfies the mathematical equation in the zk proof is commonly referred as the **witness**. +ZK rollups use validity proofs, known as _zk proofs_, to verify transaction batches. In this process, the **prover** (operator) generates a zk proof to show that their inputs (the transactions) satisfy this equation. A **verifier** (an L1 contract) then checks this proof to ensure that the output matches the expected result. The solution that the prover uses to demonstrate that their input satisfies the mathematical equation in the zk proof is commonly referred as the **witness**. ### Conclusion diff --git a/courses/blockchain-basics/1-basics/2-best-practices/+page.md b/courses/blockchain-basics/1-basics/2-best-practices/+page.md index 1456ca5a4..ef1164063 100644 --- a/courses/blockchain-basics/1-basics/2-best-practices/+page.md +++ b/courses/blockchain-basics/1-basics/2-best-practices/+page.md @@ -16,7 +16,7 @@ In the top right corner of the lesson view, you'll find a link to the [**GitHub Next to the video lesson, there is a **written lesson** tab 📝. This tab provides the course content in text format, which is useful for reading along, copy-pasting code snippets or reviewing updates. -If you're watching on YouTube, links to these resources are available in the video description. However, watching this course on Cyphrin Updraft offers additional benefits like tracking your progress and accessing written lessons, which will enhance your learning experience. +If you're watching on YouTube, links to these resources are available in the video description. However, watching this course on Cyfrin Updraft offers additional benefits like tracking your progress and accessing written lessons, which will enhance your learning experience. ### Best Practices for Learning diff --git a/courses/blockchain-basics/1-basics/6-the-purpose-of-smart-contracts/+page.md b/courses/blockchain-basics/1-basics/6-the-purpose-of-smart-contracts/+page.md index 1f14dce85..dc9bdbd63 100644 --- a/courses/blockchain-basics/1-basics/6-the-purpose-of-smart-contracts/+page.md +++ b/courses/blockchain-basics/1-basics/6-the-purpose-of-smart-contracts/+page.md @@ -49,7 +49,7 @@ Smart contracts are _the_ solution to minimizing the reliance on trust based sys ### Under the Hood -Smart contracts are relatively new, but have already started transforming various markets. They do this by representing 'promises' as code on the blockchain. This code is executed by a decentralized collective, such that no single entity can alter the agreemeent in any way! The agreement and its terms are public knowledge and will automatically execute without human intervention. +Smart contracts are relatively new, but have already started transforming various markets. They do this by representing 'promises' as code on the blockchain. This code is executed by a decentralized collective, such that no single entity can alter the agreement in any way! The agreement and its terms are public knowledge and will automatically execute without human intervention. More industries are adopting smart contracts and blockchain due to the numerous advantages they offer. This results in trust-minimized agreements or what can be simply termed as unbreakable promises. diff --git a/courses/curve-v1/1-overview/4-setup-repo/+page.md b/courses/curve-v1/1-overview/4-setup-repo/+page.md index 684267809..305bf38da 100644 --- a/courses/curve-v1/1-overview/4-setup-repo/+page.md +++ b/courses/curve-v1/1-overview/4-setup-repo/+page.md @@ -17,7 +17,7 @@ cd advanced-defi-2024 The exercises are written in Foundry, so to do the exercises, we first need to install Foundry. If you have not done so, copy and paste this command to install Foundry: ```bash -curl -L https://foundry.paradigm.xyz | bash foundrysup +curl -L https://foundry.paradigm.xyz | bash foundryup ``` Now this command only works for Linux. diff --git a/courses/formal-verification/0-introduction/1-course-introduction/+page.md b/courses/formal-verification/0-introduction/1-course-introduction/+page.md index 54a5902f9..820523dca 100644 --- a/courses/formal-verification/0-introduction/1-course-introduction/+page.md +++ b/courses/formal-verification/0-introduction/1-course-introduction/+page.md @@ -42,7 +42,7 @@ The value of knowing how to formally verify a protocol can be seen regardless of ### Wrap Up -As I mentioned, this is going to be the most advanced content we've offered yet and it's specifically tailered to those of you who want to take their development or their security skills to the next level +As I mentioned, this is going to be the most advanced content we've offered yet and it's specifically tailored to those of you who want to take their development or their security skills to the next level A sincere thank you for taking this course. This is how we scale Web3 in a sustainable and secure way. diff --git a/courses/formal-verification/0-introduction/2-best-practices/+page.md b/courses/formal-verification/0-introduction/2-best-practices/+page.md index 1bc0ace57..0a505e3f5 100644 --- a/courses/formal-verification/0-introduction/2-best-practices/+page.md +++ b/courses/formal-verification/0-introduction/2-best-practices/+page.md @@ -32,7 +32,7 @@ This space moves quickly and things are always changing, because of this some re - **Code Along With Me:** Actually taking the steps and going through the motions is how you build the memory recall and skills necessary to actually use these methodologies in the real world. Follow along in your own editor by cloning the section repos and get the most out of each lesson. - **Take Breaks:** Too often do people try to rush through content and complete everything all at once. **Don't do this.** Your brain doesn't work this way! Your brain needs time to absorb information. Every 20-30 minutes consider taking 5 minutes of downtime to truly internalize the content. Rushing through things will not allow you to retain the information. - **Pace Yourself:** Go at the speed that makes sense for you. Everyone is going to have their own speed, their own level of experience and their own circumstances that all add up to a unique pace of learning. What makes sense for one person may not make sense for you, and that's ok. Find consistency without it feeling forced. -- **Customize Video Playback:** Updraft allows you to set the speed at which the video is played, so if I'm talking too quickly - slow me down! Addtionally, Updraft supports an ever growing list of closed caption languages, so customize your experience in a way that removes the friction from learning. +- **Customize Video Playback:** Updraft allows you to set the speed at which the video is played, so if I'm talking too quickly - slow me down! Additionally, Updraft supports an ever growing list of closed caption languages, so customize your experience in a way that removes the friction from learning. ::image{src='/formal-verification-0/best-practices/best-practices3.png' style='width: 100%; height: auto;'} diff --git a/courses/formal-verification/1-horse-store/14-shr/+page.md b/courses/formal-verification/1-horse-store/14-shr/+page.md index 09984ef2b..476d34639 100644 --- a/courses/formal-verification/1-horse-store/14-shr/+page.md +++ b/courses/formal-verification/1-horse-store/14-shr/+page.md @@ -10,7 +10,7 @@ The next part can be a little tough to grasp at first, and that's ok. Take your ### Slicing Bits -Our ultimate goal is to access the `function selector` of the `calldata` sent to our contract. This is reprented by the first 8 bytes of our `calldata`. +Our ultimate goal is to access the `function selector` of the `calldata` sent to our contract. This is represented by the first 8 bytes of our `calldata`. ``` 0xe026c0170000000000000000000000000000000000000000000000000000000000000001 @@ -58,4 +58,4 @@ cast --to-base 0b001000000 hex The output we receive is `0x40`! -I encourage you to test this out further yourself. Try shifting a variety of decimal places and experimeent with how this affects your output. +I encourage you to test this out further yourself. Try shifting a variety of decimal places and experiment with how this affects your output. diff --git a/courses/formal-verification/1-horse-store/16-shr-calldata/+page.md b/courses/formal-verification/1-horse-store/16-shr-calldata/+page.md index 9e7a06757..3d2920035 100644 --- a/courses/formal-verification/1-horse-store/16-shr-calldata/+page.md +++ b/courses/formal-verification/1-horse-store/16-shr-calldata/+page.md @@ -25,7 +25,7 @@ The `calldata` we've added to our stack is the first 32 bytes of the `calldata` We only need the `function selector`, or the first 4 bytes. In order to isolate this section of the `calldata` we will need to utilize `shr` to shift 28 bytes to the right. -> **Remember:** `shr` takes the number of _bits_ to shift. 28 x 8 = 224 bits. Use `cast --to-base 224 hex` to glean that this number is `0xe0` in hexidecimal format. +> **Remember:** `shr` takes the number of _bits_ to shift. 28 x 8 = 224 bits. Use `cast --to-base 224 hex` to glean that this number is `0xe0` in hexadecimal format. With that determined, let's add what we need to our contract. diff --git a/courses/formal-verification/1-horse-store/2-what-are-opcodes/+page.md b/courses/formal-verification/1-horse-store/2-what-are-opcodes/+page.md index 4eb6ee25b..6a7078f43 100644 --- a/courses/formal-verification/1-horse-store/2-what-are-opcodes/+page.md +++ b/courses/formal-verification/1-horse-store/2-what-are-opcodes/+page.md @@ -18,7 +18,7 @@ Each byte, which corresponds to two hex characters, essentially represents an op ### Understanding Opcodes -As humans, we're not wired to effortlessly comprehend machine-code or binary. Manually instructing thousands of transitors is just not something we're good at. Because of this, we turn to higher-level programming languages like Solidity that are easier for humans to understand! +As humans, we're not wired to effortlessly comprehend machine-code or binary. Manually instructing thousands of transistors is just not something we're good at. Because of this, we turn to higher-level programming languages like Solidity that are easier for humans to understand! However, it's crucial to remember that the EVM doesn't understand Solidity; it operates at the lowest level of code. It's a machine that needs explicit instructions to work with data, whether storing it, memorizing it, or stacking it. These instructions are the aforementioned op codes. diff --git a/courses/formal-verification/1-horse-store/23-read-number-of-horses/+page.md b/courses/formal-verification/1-horse-store/23-read-number-of-horses/+page.md index f3120ea69..541082237 100644 --- a/courses/formal-verification/1-horse-store/23-read-number-of-horses/+page.md +++ b/courses/formal-verification/1-horse-store/23-read-number-of-horses/+page.md @@ -43,6 +43,6 @@ So, what's happening in the code above? Continuing from where our code had previously left off, we're performing the same operations as before though with our new `function selector`. We `PUSH` `0xe026c017` to the stack and compare it to our duplicated `function selector`. This time, if a match is found, we jump to the location of the new macro we created `GET_NUMBER_OF_HORSES()`. -Notice how we didn't execute `DUP1` a second time. We've omitted it this time as we know we won't need to perform further checks. What's especially cool about this is you've just written a fuction dispatcher this is **_more gas efficient_** than Solidity's! Solidity's function dispatching process would have unnecessarily duplicated our `call data` bytecode a second time - wasting gas! +Notice how we didn't execute `DUP1` a second time. We've omitted it this time as we know we won't need to perform further checks. What's especially cool about this is you've just written a function dispatcher this is **_more gas efficient_** than Solidity's! Solidity's function dispatching process would have unnecessarily duplicated our `call data` bytecode a second time - wasting gas! In the next lesson, we'll look more closely at JUMPDEST in [**evm.codes**](https://www.evm.codes/?fork=shanghai). diff --git a/courses/formal-verification/1-horse-store/24-testing-jumpdest/+page.md b/courses/formal-verification/1-horse-store/24-testing-jumpdest/+page.md index 98425096a..fb5bb4aac 100644 --- a/courses/formal-verification/1-horse-store/24-testing-jumpdest/+page.md +++ b/courses/formal-verification/1-horse-store/24-testing-jumpdest/+page.md @@ -23,7 +23,7 @@ If we assure that the call data we're passing begins with the updateHorseNumber ::image{src='/formal-verification-1/24-testing-jumpdest/testing-jumpdest-2.png' style='width: 50%; height: auto;'} -We can see our first `JUMPI` code pertains to one of the JUMPDEST codes at the bottom of our list of operations. Because we're passing JUMPI this location, and a 1 (which represents a matching selector), we would expect our next step to jump our exectution to this location further in the code-bypassing the second check entirely. +We can see our first `JUMPI` code pertains to one of the JUMPDEST codes at the bottom of our list of operations. Because we're passing JUMPI this location, and a 1 (which represents a matching selector), we would expect our next step to jump our execution to this location further in the code-bypassing the second check entirely. ::image{src='/formal-verification-1/24-testing-jumpdest/testing-jumpdest-3.png' style='width: 50%; height: auto;'} diff --git a/courses/formal-verification/1-horse-store/25-revert/+page.md b/courses/formal-verification/1-horse-store/25-revert/+page.md index 23a91c20f..8a01ade24 100644 --- a/courses/formal-verification/1-horse-store/25-revert/+page.md +++ b/courses/formal-verification/1-horse-store/25-revert/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ## What Happens When We Don't "Jump"? -Now that we've accounted for each of our contract's function in our function dispatcher, we're done, right? Not exactly. Our code won't just stop executing if no valid `JUMPDEST` is found, it'll continue to the next operation (which in ourcase happens to be a `JUMPDEST`). +Now that we've accounted for each of our contract's function in our function dispatcher, we're done, right? Not exactly. Our code won't just stop executing if no valid `JUMPDEST` is found, it'll continue to the next operation (which in our case happens to be a `JUMPDEST`). We could easily imagine a scenario where `call data` is sent to our contract, no `function selector` matches are found, and arbitrary code is executed when we don't intend! diff --git a/courses/formal-verification/1-horse-store/27-storage-refresher/+page.md b/courses/formal-verification/1-horse-store/27-storage-refresher/+page.md index a7ee6162f..1dff7bd53 100644 --- a/courses/formal-verification/1-horse-store/27-storage-refresher/+page.md +++ b/courses/formal-verification/1-horse-store/27-storage-refresher/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Storage Refresher -With our function dispatcher and interfaces set up, we're finally ready to add some logic to our macros! We're going to bgin with `SET_NUMBER_OF_HORSES()` as one of our first steps will be assigning a storage slot to our `numberOfHorses` variable. +With our function dispatcher and interfaces set up, we're finally ready to add some logic to our macros! We're going to begin with `SET_NUMBER_OF_HORSES()` as one of our first steps will be assigning a storage slot to our `numberOfHorses` variable. When we think of storage, we can think of it as a giant, persistent array. When a transaction's execution completes, storage remains and is not cleared. diff --git a/courses/formal-verification/1-horse-store/32-testing-our-macro-in-evm-codes/+page.md b/courses/formal-verification/1-horse-store/32-testing-our-macro-in-evm-codes/+page.md index 05fd0d781..35f86031a 100644 --- a/courses/formal-verification/1-horse-store/32-testing-our-macro-in-evm-codes/+page.md +++ b/courses/formal-verification/1-horse-store/32-testing-our-macro-in-evm-codes/+page.md @@ -23,6 +23,6 @@ Here's an example of valid call data to set our number of horses to 7 and the ca I want to draw you attention to the `stop` op code I've added near the end. This code is an imperative aspect of handling functions in Huff. -Code doesn't know when you want it to start and stop, it'll keep running until the application runs out of code. The `stop` op code affords a developer the power to explicitly tell the EVM 'We're done here, this execution is complete. This will prevent our code from continuing to run sebsequent operations after completion our function call! +Code doesn't know when you want it to start and stop, it'll keep running until the application runs out of code. The `stop` op code affords a developer the power to explicitly tell the EVM 'We're done here, this execution is complete. This will prevent our code from continuing to run subsequent operations after completion our function call! This is amazing! What you'll find when we decompile our Solidity version of Horse Store, is that what we've just built out in Huff is effectively what Solidity is doing for us under the hood. Great work! Let's look at how to add the logic of our `getNumberOfHorses` function. diff --git a/courses/formal-verification/1-horse-store/34-get-number-of-horses-macro/+page.md b/courses/formal-verification/1-horse-store/34-get-number-of-horses-macro/+page.md index 5f3e96705..402020a10 100644 --- a/courses/formal-verification/1-horse-store/34-get-number-of-horses-macro/+page.md +++ b/courses/formal-verification/1-horse-store/34-get-number-of-horses-macro/+page.md @@ -33,7 +33,7 @@ Because we don't have anything in memory, we can just `PUSH0` to our stack for t You'll notice that our stack is empty after executing our `mstore` operation. This is where things can get tricky while working with Assembly and Huff. Our data structures can become difficult to keep track of when they scale. While our stack may be empty, we now have our value contained in memory. -When working with lots of data, it can be troublesome to keep track of 'what's in the stack?', 'what's in memory?', 'what's in storage?'. This is precisely why people choose to program in abstacted languages like Solidity. +When working with lots of data, it can be troublesome to keep track of 'what's in the stack?', 'what's in memory?', 'what's in storage?'. This is precisely why people choose to program in abstracted languages like Solidity. Alright, now that we have our data in memory - we need to return it, with the `return` op code. diff --git a/courses/formal-verification/1-horse-store/36-huff-&-opcodes-recap/+page.md b/courses/formal-verification/1-horse-store/36-huff-&-opcodes-recap/+page.md index a8fed5811..77341cfb1 100644 --- a/courses/formal-verification/1-horse-store/36-huff-&-opcodes-recap/+page.md +++ b/courses/formal-verification/1-horse-store/36-huff-&-opcodes-recap/+page.md @@ -16,7 +16,7 @@ A `function dispatcher` is a section of code which is responsible for checking t ### Op Codes -In addition to working with `function dispatachers`, we learnt how to manage storage slots via Huff's `FREE_STORAGE_POINTER()`! We also learnt a variety of op codes and they're uses. We learnt: +In addition to working with `function dispatchers`, we learnt how to manage storage slots via Huff's `FREE_STORAGE_POINTER()`! We also learnt a variety of op codes and they're uses. We learnt: - PUSH# - Adds items to the stack with # being representative of the number of bytes being pushed. - CALLDATALOAD - loads received `call data` into the stack for reference. @@ -25,10 +25,10 @@ In addition to working with `function dispatachers`, we learnt how to manage sto - MSTORE - add values to memory - JUMPI - routes code executing to a particular section of logic based on a conditional. - STOP - ends execution successfully -- REVERT - ends exectution with error, unsuccessfully +- REVERT - ends execution with error, unsuccessfully ### Wrap Up -This is heavy stuff, but you're doing great. If you're feeling a little overwhelmed - now's a great time to take a break. If things aren't quite clicking, I encourage you to come back and tinker with things. Make changes to our Huff contract, experiment with how the different op codes interact with eachother. Addtionally, the [Huff Documention](docs.huff.sh) does a great job helping to understand the EVM and I encourage you to give it a read as supplemental learnings. +This is heavy stuff, but you're doing great. If you're feeling a little overwhelmed - now's a great time to take a break. If things aren't quite clicking, I encourage you to come back and tinker with things. Make changes to our Huff contract, experiment with how the different op codes interact with each other. Additionally, the [Huff Documentation](docs.huff.sh) does a great job helping to understand the EVM and I encourage you to give it a read as supplemental learnings. -In the next lessons we're goihg to be diving into how to write Foundry tests which are compatible with Huff, allowing us to do all of our Huff debugging in Foundry. Let's go! +In the next lessons we're going to be diving into how to write Foundry tests which are compatible with Huff, allowing us to do all of our Huff debugging in Foundry. Let's go! diff --git a/courses/formal-verification/1-horse-store/37-differential-testing-base-test-V1/+page.md b/courses/formal-verification/1-horse-store/37-differential-testing-base-test-V1/+page.md index adae7cf78..fcb7c125f 100644 --- a/courses/formal-verification/1-horse-store/37-differential-testing-base-test-V1/+page.md +++ b/courses/formal-verification/1-horse-store/37-differential-testing-base-test-V1/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Where We're At -Let's take a moment to consider where exactly we're at right now. We've written our Huff contract, and we have our Solidity contract on which it was based. Looking at these two languages, it's clear to see we'd never want to write a whole contract op code by op code. It's incredibly tedius, sure you may be a little more gas efficient, but you're looking at 5x the effort to accomplish something a higher level language can achieve much more easily. +Let's take a moment to consider where exactly we're at right now. We've written our Huff contract, and we have our Solidity contract on which it was based. Looking at these two languages, it's clear to see we'd never want to write a whole contract op code by op code. It's incredibly tedious, sure you may be a little more gas efficient, but you're looking at 5x the effort to accomplish something a higher level language can achieve much more easily. ### Differential Testing diff --git a/courses/formal-verification/1-horse-store/38-deploying-huff-in-foundry/+page.md b/courses/formal-verification/1-horse-store/38-deploying-huff-in-foundry/+page.md index 951c23677..01fe1973c 100644 --- a/courses/formal-verification/1-horse-store/38-deploying-huff-in-foundry/+page.md +++ b/courses/formal-verification/1-horse-store/38-deploying-huff-in-foundry/+page.md @@ -32,7 +32,7 @@ Find more information on FFI **[here](https://book.getfoundry.sh/cheatcodes/ffi) > **Note:** Enabling FFI gives Foundry some pretty pervasive accesses include access to your shell and the ability to read and write from disk. Be very aware of this and use FFI with care. -Addtionally to the above, we'll need to add a remapping to our `foundry.toml` as well. +Additionally to the above, we'll need to add a remapping to our `foundry.toml` as well. ```toml remappings = ['foundry-huff/=lib/foundry-huff/src'] diff --git a/courses/formal-verification/1-horse-store/39-foundry-opcode-debugger/+page.md b/courses/formal-verification/1-horse-store/39-foundry-opcode-debugger/+page.md index 79e84df18..e9f75641b 100644 --- a/courses/formal-verification/1-horse-store/39-foundry-opcode-debugger/+page.md +++ b/courses/formal-verification/1-horse-store/39-foundry-opcode-debugger/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Foundry Op Code Debugger -Alright! All that we've done has lead to this! We've proved .. somehting fairly minor. Both our Huff and Solidity contracts inialize storage slot 0 with 0. This is just a start however, we've been able to verify that our contracts are both functioning the same way - this is great! +Alright! All that we've done has lead to this! We've proved .. something fairly minor. Both our Huff and Solidity contracts initialize storage slot 0 with 0. This is just a start however, we've been able to verify that our contracts are both functioning the same way - this is great! Often when coding in a low level language like Assembly or Huff it can be difficult to pinpoint where things are going wrong when errors are received. Foundry, fortunately, has a built in debugger we can use! @@ -20,9 +20,9 @@ forge test --debug testReadHuffValue This should launch Foundry's debugger. -The trickest part of the debugger could easily be navigation to the correct pieces of code. Foundry itself has a bunch of operations executing as a product of running its test suites, this muddies the waters a little bit in our debugger. +The trickiest part of the debugger could easily be navigation to the correct pieces of code. Foundry itself has a bunch of operations executing as a product of running its test suites, this muddies the waters a little bit in our debugger. -Utilize the commands along the bottom of the screen to navigate, you're looking for our `calldataload` or our `function selector` checks. These are clear inidicators that we're looking at our contracts implementation. +Utilize the commands along the bottom of the screen to navigate, you're looking for our `calldataload` or our `function selector` checks. These are clear indicators that we're looking at our contracts implementation. Foundry's debugger allows us to step through execution op code by op code very similarly to how the evm.codes playground works! We've seen this a few times before in our experiments learning about op codes, but I encourage you to play with this debugger until you're familiar with it. Trying things out is the best way to learn. @@ -44,7 +44,7 @@ abstract contract Base_TestV1 is Test{ } function testReadValue() public { - uint256 initalValue = horseStore.readNumberOfHorses(); + uint256 initialValue = horseStore.readNumberOfHorses(); assertEq(initialValue, 0); } @@ -58,7 +58,7 @@ abstract contract Base_TestV1 is Test{ Our test looks great! It's very simple, we're assigning 777 to a variable, updating the number of courses in horseStore, then our assert reads from the contract to verify that the updating number was in fact stored! -Let's run `forge test --debug testWriteValue` and see how it looks in the debugger. Before hand, it's good to get an idea of what you're looking out for admidst all the debugger op codes so as not to get lost. +Let's run `forge test --debug testWriteValue` and see how it looks in the debugger. Before hand, it's good to get an idea of what you're looking out for amidst all the debugger op codes so as not to get lost. ```bash cast to-base 777 hex diff --git a/courses/formal-verification/1-horse-store/40-updating-tests-to-fuzz-tests/+page.md b/courses/formal-verification/1-horse-store/40-updating-tests-to-fuzz-tests/+page.md index 6ecc177e4..ed3c6f89e 100644 --- a/courses/formal-verification/1-horse-store/40-updating-tests-to-fuzz-tests/+page.md +++ b/courses/formal-verification/1-horse-store/40-updating-tests-to-fuzz-tests/+page.md @@ -24,8 +24,8 @@ contract HorseStoreTestV1 is Base_TestV1 { } function testReadHuffValue() public { - uint256 initalValue = horseStoreHuff.readNumberOfHorses(); - assertEq(initalValue, 0); + uint256 initialValue = horseStoreHuff.readNumberOfHorses(); + assertEq(initialValue, 0); } function testStoreAndReadHorseNumberHuff() public { @@ -73,6 +73,6 @@ Boom. All there is to it to convert this simple function into a fuzz test. Working with op codes is POWERFUL, but as cliche as it is - *with great power, comes great responsibility*. Breaking the functionality of code written in such a low level is very easy. -Any of our `PUSH` op codes, even if off by a single digit will cause things to likely fail, the precision of capturing the correct offset, or referencing the correct storage slots is paramount when writing in low level code. Its for this reason that if you choose to write in something low level like Assembly or Huff, you should back up you logic with robust fuzz testing and even formal verification tests to assure your Huff implentation acts precisely how it should. +Any of our `PUSH` op codes, even if off by a single digit will cause things to likely fail, the precision of capturing the correct offset, or referencing the correct storage slots is paramount when writing in low level code. Its for this reason that if you choose to write in something low level like Assembly or Huff, you should back up you logic with robust fuzz testing and even formal verification tests to assure your Huff implementation acts precisely how it should. Don't worry, we'll absolutely be going over formal verification later in the course 😉 \ No newline at end of file diff --git a/courses/formal-verification/1-horse-store/44-msg.value-check/+page.md b/courses/formal-verification/1-horse-store/44-msg.value-check/+page.md index 737d9d9a9..43bfc39a5 100644 --- a/courses/formal-verification/1-horse-store/44-msg.value-check/+page.md +++ b/courses/formal-verification/1-horse-store/44-msg.value-check/+page.md @@ -146,7 +146,7 @@ _Follow along with this video:_ When going through op codes, I like to repeatedly ask myself _What does this chunk do?_. Let's look at the next check and walk through is execution. -I'll typically look out for 'break points', things like `Revert` and `Return` to detemine where a "chunk" starts and stops. +I'll typically look out for 'break points', things like `Revert` and `Return` to determine where a "chunk" starts and stops. ``` CALLVALUE // [msg.value] diff --git a/courses/formal-verification/1-horse-store/45-CODECOPY/+page.md b/courses/formal-verification/1-horse-store/45-CODECOPY/+page.md index 282f6b0b5..ecb02ad34 100644 --- a/courses/formal-verification/1-horse-store/45-CODECOPY/+page.md +++ b/courses/formal-verification/1-horse-store/45-CODECOPY/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### CODECOPY -Let's continue from our `JUMPDEST`. Our contructor wasn't sent any value and we avoided the initial `REVERT`. +Let's continue from our `JUMPDEST`. Our constructor wasn't sent any value and we avoided the initial `REVERT`.
Op Codes diff --git a/courses/formal-verification/1-horse-store/46-a-note-on-your-new-powers/+page.md b/courses/formal-verification/1-horse-store/46-a-note-on-your-new-powers/+page.md index 4e04f7cef..22877222e 100644 --- a/courses/formal-verification/1-horse-store/46-a-note-on-your-new-powers/+page.md +++ b/courses/formal-verification/1-horse-store/46-a-note-on-your-new-powers/+page.md @@ -33,7 +33,7 @@ DUP1 REVERT ``` -- Yes! Technically it does. In fact, I challange you to go add this to our contract and see for yourself, this check will actually be removed from our bytecode! +- Yes! Technically it does. In fact, I challenge you to go add this to our contract and see for yourself, this check will actually be removed from our bytecode! ```js constructor() payable {} diff --git a/courses/formal-verification/1-horse-store/49-soliditys-function-dispatcher/+page.md b/courses/formal-verification/1-horse-store/49-soliditys-function-dispatcher/+page.md index 3664773ee..2e2497b9c 100644 --- a/courses/formal-verification/1-horse-store/49-soliditys-function-dispatcher/+page.md +++ b/courses/formal-verification/1-horse-store/49-soliditys-function-dispatcher/+page.md @@ -225,4 +225,4 @@ REVERT This will prevent calls to our contract from executing arbitrary code if a `function selector` match isn't found. -We're already through over half the op codes of our contract and you're doing phenomally. Let's keep going! +We're already through over half the op codes of our contract and you're doing phenomenally. Let's keep going! diff --git a/courses/formal-verification/1-horse-store/53-update-horse-number-recap/+page.md b/courses/formal-verification/1-horse-store/53-update-horse-number-recap/+page.md index c6fe5d31d..7b902d287 100644 --- a/courses/formal-verification/1-horse-store/53-update-horse-number-recap/+page.md +++ b/courses/formal-verification/1-horse-store/53-update-horse-number-recap/+page.md @@ -207,7 +207,7 @@ JUMP ✅ ### CALLDATASIZE Check -Next our execution is going to check our `CALLDATASIZE`. We want to be sure that the data received, when the `function selector` is removed, is still large enough to satify the requirements of our function parameter - in this case we need a 32 byte integer or our `CALLDATASIZE - func_selector` to be > `0x20` +Next our execution is going to check our `CALLDATASIZE`. We want to be sure that the data received, when the `function selector` is removed, is still large enough to satisfy the requirements of our function parameter - in this case we need a 32 byte integer or our `CALLDATASIZE - func_selector` to be > `0x20` ```js JUMPDEST ✅ diff --git a/courses/formal-verification/1-horse-store/54-readNumberOfHorses-op-codes/+page.md b/courses/formal-verification/1-horse-store/54-readNumberOfHorses-op-codes/+page.md index a4ba3fd59..bf967cf5d 100644 --- a/courses/formal-verification/1-horse-store/54-readNumberOfHorses-op-codes/+page.md +++ b/courses/formal-verification/1-horse-store/54-readNumberOfHorses-op-codes/+page.md @@ -257,7 +257,7 @@ We're then reordering our stack a little bit using `SWAP1` and `DUP2`. This is n `MSTORE` takes the top item of our stack (the memory offset, or location of free memory that our pointer gave us), and stores there the second from the top item in our stack - numHorses. We now have `0x40:0x80` and `0x80:numHorses` as items at their respective locations in memory! -Our next step would normally be updating our `free memory pointer` with the next location of free memory, but Solodity is actually smart enough to know the call is about to end and memory won't be accessed anymore, so `MLOAD` is never called! +Our next step would normally be updating our `free memory pointer` with the next location of free memory, but Solidity is actually smart enough to know the call is about to end and memory won't be accessed anymore, so `MLOAD` is never called! Let's see how the call completes it's return though: @@ -440,4 +440,3 @@ Here's where we've come so far: The last section of our bytecode is going to be Metadata. We're almost done! - diff --git a/courses/formal-verification/1-horse-store/56-decompilers-disassembly/+page.md b/courses/formal-verification/1-horse-store/56-decompilers-disassembly/+page.md index 654d9accc..9bcf004b8 100644 --- a/courses/formal-verification/1-horse-store/56-decompilers-disassembly/+page.md +++ b/courses/formal-verification/1-horse-store/56-decompilers-disassembly/+page.md @@ -6,7 +6,7 @@ _Follow along with this video:_ --- -Alright! We've gone op code by op code and break down our Solodity contract's bytecode. At this point we could maybe even decompile our contract back into some semblence of Solidity code by following through the execution! +Alright! We've gone op code by op code and break down our Solidity contract's bytecode. At this point we could maybe even decompile our contract back into some semblence of Solidity code by following through the execution! This isn't something we necessarily have to do ourselves though. There exist tool such as [Dedaub](https://app.dedaub.com/decompile) that can try to decompile byte code for us! diff --git a/courses/formal-verification/1-horse-store/61-pure-yul/+page.md b/courses/formal-verification/1-horse-store/61-pure-yul/+page.md index b24c6046d..5436320bf 100644 --- a/courses/formal-verification/1-horse-store/61-pure-yul/+page.md +++ b/courses/formal-verification/1-horse-store/61-pure-yul/+page.md @@ -43,7 +43,7 @@ Datacopy, dataoffset and datasize might seem unfamiliar, but these are function ::image{src='/formal-verification-1/61-pure-yul/pure-yul1.png' style='width: 100%; height: auto;'} -We can see that in our circunstances the `datacopy` function is being used as equivalent to the `codecopy` op code, and what does `codecopy` do? Well, it's taking the size and offset of our `runtime code` (we haven't written the `runtime` yet!) and returning it to be copied to the blockchain! +We can see that in our circumstances the `datacopy` function is being used as equivalent to the `codecopy` op code, and what does `codecopy` do? Well, it's taking the size and offset of our `runtime code` (we haven't written the `runtime` yet!) and returning it to be copied to the blockchain! ```js object "HorseStoreYul" { diff --git a/courses/formal-verification/1-horse-store/62-horsestorev2-introduction/+page.md b/courses/formal-verification/1-horse-store/62-horsestorev2-introduction/+page.md index 3fa028e39..4778353ab 100644 --- a/courses/formal-verification/1-horse-store/62-horsestorev2-introduction/+page.md +++ b/courses/formal-verification/1-horse-store/62-horsestorev2-introduction/+page.md @@ -129,10 +129,10 @@ mapping(uint256 id => uint256 lastFedTimeStamp) public horseIdToFedTimeStamp; Ultimately however all this contract allows a user to do is to mint a horse NFT via the `mintHorse()` function, feed a horse via `feedHorse()` (this function just updates a mapping) and check if a horse is happy via `isHappyHorse()` -Our goal in the comming lessons will be to rewrite this V2 contract in Huff! +Our goal in the coming lessons will be to rewrite this V2 contract in Huff! Before moving forward, I want you to take a look at the [GitHub repo](https://github.com/Cyfrin/1-horse-store-s23/tree/main/test/v2) for this lesson and copy over the files contained within `test/v2`. We won't write all these tests from scratch, but these files will allow us to test our `HorseStoreV2` contracts with ease and compare our implementations. -Feel free to pause here and try writting `HorseStoreV2` in Huff yourself! It will be a great opportunity to challenge yourself and see how much you've learnt so far! +Feel free to pause here and try writing `HorseStoreV2` in Huff yourself! It will be a great opportunity to challenge yourself and see how much you've learnt so far! Otherwise, let's get started and write `HorseStoreV2` in Huff together! \ No newline at end of file diff --git a/courses/formal-verification/1-horse-store/66-horseidtofedtimestamp/+page.md b/courses/formal-verification/1-horse-store/66-horseidtofedtimestamp/+page.md index 86f741497..698f3bfcb 100644 --- a/courses/formal-verification/1-horse-store/66-horseidtofedtimestamp/+page.md +++ b/courses/formal-verification/1-horse-store/66-horseidtofedtimestamp/+page.md @@ -83,6 +83,6 @@ We're first getting the `horseId` from our call data via `calldataload` at the ` We next use another `Hashmap.huff` macro `LOAD_ELEMENT_FROM_KEYS`. This functions much like the reverse of our previous `STORE_ELEMENT_FROM_KEYS` in that we are taking the location of the mapping (`HORSE_FED_TIMESTAMP_LOCATION`) and passing it our horseId key. The macro is then returning to our stack the appropriate data mapped to that key - `horseFedTimestamp`. -With our data on our stack, we then need to store it in memory in order for it to be returned. So we call `mstore` at an offset of `0x00` then we exectute: `0x20 0x00 return` +With our data on our stack, we then need to store it in memory in order for it to be returned. So we call `mstore` at an offset of `0x00` then we execute: `0x20 0x00 return` `0X20 0X00 return` is a syntax you'll see commonly. It's saying - **return 32 bytes, starting at offset 0x00 from memory.** diff --git a/courses/formal-verification/1-horse-store/67-ishappyhorse/+page.md b/courses/formal-verification/1-horse-store/67-ishappyhorse/+page.md index bced5c9e1..251a8a820 100644 --- a/courses/formal-verification/1-horse-store/67-ishappyhorse/+page.md +++ b/courses/formal-verification/1-horse-store/67-ishappyhorse/+page.md @@ -85,7 +85,7 @@ The start shouldn't be too complicated, we're going to need the parameter being timestamp // [timestamp, horseFedTimestamp] } ``` -In order to retain some items on the stack before our next operations we're going to exectute two `dup2`s. We'll then call `sub` in order to subtract our `horseFedTimestamp` from our current `timestamp`. +In order to retain some items on the stack before our next operations we're going to execute two `dup2`s. We'll then call `sub` in order to subtract our `horseFedTimestamp` from our current `timestamp`. ```js #define macro IS_HAPPY_HORSE() = takes (0) returns (0) { diff --git a/courses/formal-verification/1-horse-store/70-huff-yul-and-solidity-gas-comparisons/+page.md b/courses/formal-verification/1-horse-store/70-huff-yul-and-solidity-gas-comparisons/+page.md index 271bd48ee..02e353e17 100644 --- a/courses/formal-verification/1-horse-store/70-huff-yul-and-solidity-gas-comparisons/+page.md +++ b/courses/formal-verification/1-horse-store/70-huff-yul-and-solidity-gas-comparisons/+page.md @@ -45,4 +45,4 @@ Huff wins again! Let's look at one comparison from HorseStoreV2: Wow! It's nearly 10,000 more gas in raw Solidity than it is in raw Huff. When looking at comparisons like this, it's easy to begin to see the advantages of coding in low level languages like Huff and Yul. -Always remember the trade-offs that are made to save this gas however. This saved gas we see is a product of all the checks we skipped the implementation of in Huff, checks meant to keep people safe. We skipped checking for msg.value and call data length for example. These checks exist for a reason and we should be confident and consciencious when we choose to omit them. +Always remember the trade-offs that are made to save this gas however. This saved gas we see is a product of all the checks we skipped the implementation of in Huff, checks meant to keep people safe. We skipped checking for msg.value and call data length for example. These checks exist for a reason and we should be confident and conscientious when we choose to omit them. diff --git a/courses/formal-verification/1-horse-store/71-section-1-horsestore-recap/+page.md b/courses/formal-verification/1-horse-store/71-section-1-horsestore-recap/+page.md index e6bc71953..d1aef4d68 100644 --- a/courses/formal-verification/1-horse-store/71-section-1-horsestore-recap/+page.md +++ b/courses/formal-verification/1-horse-store/71-section-1-horsestore-recap/+page.md @@ -11,7 +11,7 @@ What did we learn in this section? ### The Stack, Memory and Storage -We learnt how the stack, memory and storage work and how they interact with eachother. +We learnt how the stack, memory and storage work and how they interact with each other. - Memory is temporary, this is the space in which we interact with data, this is cleared after execution - Storage is permanent and data here will persist after execution. diff --git a/courses/formal-verification/1-horse-store/9-evm-the-stack/+page.md b/courses/formal-verification/1-horse-store/9-evm-the-stack/+page.md index 189601ea0..51529b86d 100644 --- a/courses/formal-verification/1-horse-store/9-evm-the-stack/+page.md +++ b/courses/formal-verification/1-horse-store/9-evm-the-stack/+page.md @@ -55,7 +55,7 @@ For our purposes, our focus will be the areas **Stack**, **Memory**, and **Stora ### The Stack -When we want to perform computions on data, we have to consider where the data will be stored and the order of our computions. Of all the spaces in the image above, the cheapest location for this (from the perspective of gas) is going to be on `the stack`. +When we want to perform computations on data, we have to consider where the data will be stored and the order of our computations. Of all the spaces in the image above, the cheapest location for this (from the perspective of gas) is going to be on `the stack`. If we take a look at the `ADD` op code in [**evm.codes**](https://www.evm.codes/?fork=shanghai) we can see how this addition operation actually works. @@ -65,4 +65,4 @@ If we take a look at the `ADD` op code in [**evm.codes**](https://www.evm.codes/ ::image{src='/formal-verification-1/9-evm-the-stack/evm-the-stack-3.png' style='width: 75%; height: auto;'} -In the next lesson, we'll take a look at how `memory` and `storage` is handled differently from eachother. +In the next lesson, we'll take a look at how `memory` and `storage` is handled differently from each other. diff --git a/courses/formal-verification/3-gasbad/01-introduction/+page.md b/courses/formal-verification/3-gasbad/01-introduction/+page.md index 714235548..77517f22b 100644 --- a/courses/formal-verification/3-gasbad/01-introduction/+page.md +++ b/courses/formal-verification/3-gasbad/01-introduction/+page.md @@ -24,7 +24,7 @@ So, what the Gas Bad NFT Marketplace is doing, is similar to Seaport in that the In addition to the `NFTMarketplace.sol` contract they've also written `GasBadNFTMarketplace.sol` which is essentially the exact same code base, but much of the logic has been converted to assembly to save gas. Here's a comparison between the `listItem` functions of each: -**NFTMarkplace.sol** +**NFTMarketplace.sol** ```js function listItem(address nftAddress, uint256 tokenId, uint256 price) external { @@ -76,7 +76,7 @@ function listItem(address nftAddress, uint256 tokenId, uint256 price) external { A major challenge of ours in this section will be assuring that these two code bases are _actually_ doing the same thing, and we're going to use formal verification to mathematically prove this to be true (or not!). -I see this methodology as being a great way for protocols to be gas optimized in the future. A contract is written in solidity, and then written again in a more gas efficient way. The two contracts can be compared to assure they are behaving identifically and that the cheaper execution is valid. +I see this methodology as being a great way for protocols to be gas optimized in the future. A contract is written in solidity, and then written again in a more gas efficient way. The two contracts can be compared to assure they are behaving identically and that the cheaper execution is valid. The Gas Bad NFT Marketplace code base contains certora configuration and spec files already, but this is what we're going to be trying to replicate together. You can use these files as an answer key to check your work, or if you get stuck. diff --git a/courses/formal-verification/3-gasbad/02-setup/+page.md b/courses/formal-verification/3-gasbad/02-setup/+page.md index 8347cba0e..ef415b004 100644 --- a/courses/formal-verification/3-gasbad/02-setup/+page.md +++ b/courses/formal-verification/3-gasbad/02-setup/+page.md @@ -32,7 +32,7 @@ Let's crack open the README to verify the setup steps recommended by the protoco ::image{src='/formal-verification-3/2-setup//setup1.png' style='width: 100%; height: auto;'} -The protocol wants us to use the `make` command! This should largely set our workspace up for us by removing old modules, installing our dependences and building the project. +The protocol wants us to use the `make` command! This should largely set our workspace up for us by removing old modules, installing our dependencies and building the project. > ❗ **WARNING** > Before running `make` we should always check our foundry.toml to assure `FFI=False`, running arbitrary code while our framework has these permissions is dangerous! **Be safe!** diff --git a/courses/formal-verification/3-gasbad/08-parametric-rules/+page.md b/courses/formal-verification/3-gasbad/08-parametric-rules/+page.md index 50b98c0ed..9a0895999 100644 --- a/courses/formal-verification/3-gasbad/08-parametric-rules/+page.md +++ b/courses/formal-verification/3-gasbad/08-parametric-rules/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Parametric Rules -In this lesson we'll go through a `parametric` formal verification example. You can read more about Parametric rules [**here in the Certora docs**](https://docs.certora.com/en/latest/docs/user-guide/parametric.html), but in brief they're rules which take ambiguious methods as parameters and differ from invariants in two key ways: +In this lesson we'll go through a `parametric` formal verification example. You can read more about Parametric rules [**here in the Certora docs**](https://docs.certora.com/en/latest/docs/user-guide/parametric.html), but in brief they're rules which take ambiguous methods as parameters and differ from invariants in two key ways: 1. Invariants are also testing after the constructor 2. Invariants are used to assert properties of the storage (between function calls), while parametric rules are used to assert properties of _changes_ in the storage (caused by function calls). diff --git a/courses/formal-verification/3-gasbad/10-formal-vertification-setup/+page.md b/courses/formal-verification/3-gasbad/10-formal-vertification-setup/+page.md index 7c0515adf..dbd1c8aa0 100644 --- a/courses/formal-verification/3-gasbad/10-formal-vertification-setup/+page.md +++ b/courses/formal-verification/3-gasbad/10-formal-vertification-setup/+page.md @@ -1,12 +1,12 @@ --- -title: Formal Vertification Setup +title: Formal Verification Setup --- _Follow along with this video:_ --- -### Formal Vertification Setup +### Formal Verification Setup We're ready to finally formally verify our GasBadNftMarketplace contract! Start by creating `GasBad.spec` and `GasBad.conf` files in their respective Certora folders. diff --git a/courses/formal-verification/3-gasbad/11-ghost-and-hooks/+page.md b/courses/formal-verification/3-gasbad/11-ghost-and-hooks/+page.md index a10d92064..6d1f615d7 100644 --- a/courses/formal-verification/3-gasbad/11-ghost-and-hooks/+page.md +++ b/courses/formal-verification/3-gasbad/11-ghost-and-hooks/+page.md @@ -31,7 +31,7 @@ This may be a little tricky, but it's entirely possible. However, we first need ::image{src='/formal-verification-3/11-ghosts-and-hooks/ghosts-and-hooks1.png' style='width: 100%; height: auto;'} -At their core, `Ghost Variables` are variable which are declared specifically to be used by `Certora`. Declaring them this way allows them to act as extentions to contract state and their values will mimic the behaviour of contract storage (reverting and resetting when appropriate). +At their core, `Ghost Variables` are variable which are declared specifically to be used by `Certora`. Declaring them this way allows them to act as extensions to contract state and their values will mimic the behaviour of contract storage (reverting and resetting when appropriate). The most common use of `Ghost Variables` is in conjunction with `Hooks` to communication information back to specified `rules`. diff --git a/courses/formal-verification/3-gasbad/13-analyzing-certora-errors/+page.md b/courses/formal-verification/3-gasbad/13-analyzing-certora-errors/+page.md index 8fd30438f..c05108d86 100644 --- a/courses/formal-verification/3-gasbad/13-analyzing-certora-errors/+page.md +++ b/courses/formal-verification/3-gasbad/13-analyzing-certora-errors/+page.md @@ -24,7 +24,7 @@ Drill into the error for GasBadNftMarketplace for a better idea of what's happen Well, what's going on here? We initialized our ghost variables with a value, so what gives? -Despite setting initial values, the `Certora` prover assumes that these values can be changed at any point unless specifcally instructed that they are static, or `persistent`. Effectively the prover recognizes that our ghost variables have been initialized and then starts changing them to random values. +Despite setting initial values, the `Certora` prover assumes that these values can be changed at any point unless specifically instructed that they are static, or `persistent`. Effectively the prover recognizes that our ghost variables have been initialized and then starts changing them to random values. In our particular circumstance, `Certora` had the variable start at 0, but was unsure if this variable could change. The `transferFrom` call, for example, could be calling `mint`! diff --git a/courses/formal-verification/3-gasbad/14-persistent-ghosts/+page.md b/courses/formal-verification/3-gasbad/14-persistent-ghosts/+page.md index 0010906f9..c2c6c963c 100644 --- a/courses/formal-verification/3-gasbad/14-persistent-ghosts/+page.md +++ b/courses/formal-verification/3-gasbad/14-persistent-ghosts/+page.md @@ -30,7 +30,7 @@ persistent ghost mathint log4Count { } ``` -This would technically _solve_ our HAVOC problem, but it's worth considering that while this make our proof `valid`, it does not allow it to be `sound`. Simple put, these external calls _could_ change the value of variables in storage, but the use of the `persistent` keyword is effectly choosing to ignore this. +This would technically _solve_ our HAVOC problem, but it's worth considering that while this make our proof `valid`, it does not allow it to be `sound`. Simple put, these external calls _could_ change the value of variables in storage, but the use of the `persistent` keyword is effectively choosing to ignore this. ### Wrap Up diff --git a/courses/formal-verification/3-gasbad/16-method-entries-introduction/+page.md b/courses/formal-verification/3-gasbad/16-method-entries-introduction/+page.md index 9f34de837..7c9c99785 100644 --- a/courses/formal-verification/3-gasbad/16-method-entries-introduction/+page.md +++ b/courses/formal-verification/3-gasbad/16-method-entries-introduction/+page.md @@ -64,7 +64,7 @@ methods { } ``` -The above is telling the `Certora` prover that any function withing the currentContract being verified should always return 1. Pehaps a strange thing to configure in our case, but you could imagine similar methodologies being applied to libraries which are in scope, but inconsequential to what is being verified at the time. +The above is telling the `Certora` prover that any function withing the currentContract being verified should always return 1. Perhaps a strange thing to configure in our case, but you could imagine similar methodologies being applied to libraries which are in scope, but inconsequential to what is being verified at the time. ### Wrap Up diff --git a/courses/formal-verification/3-gasbad/17-summary-declaration-examples/+page.md b/courses/formal-verification/3-gasbad/17-summary-declaration-examples/+page.md index 48a7750cd..258cde004 100644 --- a/courses/formal-verification/3-gasbad/17-summary-declaration-examples/+page.md +++ b/courses/formal-verification/3-gasbad/17-summary-declaration-examples/+page.md @@ -24,12 +24,12 @@ We also have `HAVOC summaries` available to us, which allow us to control, with Lastly, for the scope of this course, and most applicably to our GasBad solution, we have `DISPATCHER summaries`. -A `DISPATCHER summary` set to true tells the prover that a given function can only execute logic as defined by another contract within our scope. This restricts the behaviour of the function calls in the prover to something predicatable and thus validatable. +A `DISPATCHER summary` set to true tells the prover that a given function can only execute logic as defined by another contract within our scope. This restricts the behaviour of the function calls in the prover to something predictable and thus validatable. ::image{src='/formal-verification-3/17-summary-declaration-examples/summary-declaration-examples3.png' style='width: 100%; height: auto;'} ### Wrap Up -Wow, we've got way more flexibility within the `methods block` than we originally thought! We're going to be employing a `DISPATCHER summary` as means to solve our GasBad prover error. Don't worry if this summary type is hard to grasp as first. Let's apply it to our situaion and hopefully come away with a clearer understanding of how it works. +Wow, we've got way more flexibility within the `methods block` than we originally thought! We're going to be employing a `DISPATCHER summary` as means to solve our GasBad prover error. Don't worry if this summary type is hard to grasp as first. Let's apply it to our situation and hopefully come away with a clearer understanding of how it works. See you in the next lesson! diff --git a/courses/formal-verification/3-gasbad/18-summary-implementations/+page.md b/courses/formal-verification/3-gasbad/18-summary-implementations/+page.md index 548bb1801..e7952747d 100644 --- a/courses/formal-verification/3-gasbad/18-summary-implementations/+page.md +++ b/courses/formal-verification/3-gasbad/18-summary-implementations/+page.md @@ -85,7 +85,7 @@ By employing the `wildcard entry` we can avoid issues with where this function i Because the scope we're providing the prover includes `NftMock.sol`, we're instructing `Certora`, through our above configuration, to treat every `safeTransferFrom` call as though it behaves like the one in our `NftMock.sol` contract. -Now, it's worth pointing out that by employing our declaraction this way we're adopting some assumptions. Primarily, we're assuming that our NFTs `safeTransferFrom` function won't alter storage and that the `safeTransferFrom` function behaves fairly innocuously. This may not necessarily be a safe assumption, but for the purposes of our example this is fine. +Now, it's worth pointing out that by employing our declaration this way we're adopting some assumptions. Primarily, we're assuming that our NFTs `safeTransferFrom` function won't alter storage and that the `safeTransferFrom` function behaves fairly innocuously. This may not necessarily be a safe assumption, but for the purposes of our example this is fine. ### Running the Prover @@ -141,7 +141,7 @@ invariant anytime_mapping_updated_emit_event() ::image{src='/formal-verification-3/18-summary-implementations/summary-implementations3.png' style='width: 100%; height: auto;'} -Uh oh, we're still seeing an issue. Let's drill into the call trace to determine what's happening. If we navigate through the call trace Certora provides to the safeTranferFrom call that was previously failing, we can see a few interesting things. +Uh oh, we're still seeing an issue. Let's drill into the call trace to determine what's happening. If we navigate through the call trace Certora provides to the safeTransferFrom call that was previously failing, we can see a few interesting things. ::image{src='/formal-verification-3/18-summary-implementations/summary-implementations4.png' style='width: 100%; height: auto;'} diff --git a/courses/formal-verification/3-gasbad/21-mid-lesson-recap/+page.md b/courses/formal-verification/3-gasbad/21-mid-lesson-recap/+page.md index 3f7ea2761..38c0f3bba 100644 --- a/courses/formal-verification/3-gasbad/21-mid-lesson-recap/+page.md +++ b/courses/formal-verification/3-gasbad/21-mid-lesson-recap/+page.md @@ -12,11 +12,11 @@ We've learnt tonnes already, let's do a quick summary of what we've gone over so ### Ghost Variables -We investigated ghost variables and how they're configured within a .spec file. We learnt that these variables are treated as temporary parts of the contract which are used by the pover alone. +We investigated ghost variables and how they're configured within a .spec file. We learnt that these variables are treated as temporary parts of the contract which are used by the prover alone. Ghost variables are initialized using an `init_state axiom`. -In many instances a situation arived at by the prover may result in ghost variables being HAVOC'd (randomized). To prevent this, we can use the `persistent` key word when declaring our ghost variables. +In many instances a situation arrived at by the prover may result in ghost variables being HAVOC'd (randomized). To prevent this, we can use the `persistent` key word when declaring our ghost variables. ```js persistent ghost mathint listingUpdatesCount{ @@ -71,6 +71,6 @@ The root of what I'm trying to instill is this idea that - the prover is going t It's ultimately our job to vet these outputs and determine - is this the fault of my code, or is the prover unclear about what my goals are? -In the next lesson we'll drill this concept in with a final rule that should be a blast to connfigure. +In the next lesson we'll drill this concept in with a final rule that should be a blast to configure. See you there! diff --git a/courses/formal-verification/3-gasbad/24-using/+page.md b/courses/formal-verification/3-gasbad/24-using/+page.md index 09e9b28de..628408dcc 100644 --- a/courses/formal-verification/3-gasbad/24-using/+page.md +++ b/courses/formal-verification/3-gasbad/24-using/+page.md @@ -18,7 +18,7 @@ rule calling_any_function_should_result_in_each_contract_having_the_same_state(m } ``` -...we are calling `method f` on _whichever contract is currently being verfied_. Remember that functionally `f(e, args) == currentContract.f(e, args)`. With that said, we need a way to reference the specific contracts we mean for our rule to compare, and this is where the `using` keyword comes in. +...we are calling `method f` on _whichever contract is currently being verified_. Remember that functionally `f(e, args) == currentContract.f(e, args)`. With that said, we need a way to reference the specific contracts we mean for our rule to compare, and this is where the `using` keyword comes in. ::image{src='/formal-verification-3/24-using/using1.png' style='width: 100%; height: auto;'} @@ -41,6 +41,6 @@ rule calling_any_function_should_result_in_each_contract_having_the_same_state(m ### Wrap Up -With some finer control over which files are being tested against eachother, we're ready to finish fleshing out our rule, in the next lesson. +With some finer control over which files are being tested against each other, we're ready to finish fleshing out our rule, in the next lesson. Almost done! diff --git a/courses/formal-verification/3-gasbad/25-finishing-the-rule/+page.md b/courses/formal-verification/3-gasbad/25-finishing-the-rule/+page.md index b0559c1e6..989819bf6 100644 --- a/courses/formal-verification/3-gasbad/25-finishing-the-rule/+page.md +++ b/courses/formal-verification/3-gasbad/25-finishing-the-rule/+page.md @@ -247,7 +247,7 @@ Because we're using `require` statements, instead of a `filter block`, `Certora` ### Wrap Up -Despite the `sanity` errors, we can clearly see that any time the function selectors being called match, our rule is verifying the call. This test is indeed proving to us that the contracts are functioning identically under indentical circumnstances. +Despite the `sanity` errors, we can clearly see that any time the function selectors being called match, our rule is verifying the call. This test is indeed proving to us that the contracts are functioning identically under identical circumstances. > ❗ **PROTIP** > We _could_ set `"rule_sanity": "none"`, in our `GasBad.conf`, in order for these sanity checks to reflect `passed`, but we should always be cautious when removing these checks. diff --git a/courses/formal-verification/3-gasbad/26-do-you-understand-how-cool-this-is/+page.md b/courses/formal-verification/3-gasbad/26-do-you-understand-how-cool-this-is/+page.md index f92f68f2b..0b659702b 100644 --- a/courses/formal-verification/3-gasbad/26-do-you-understand-how-cool-this-is/+page.md +++ b/courses/formal-verification/3-gasbad/26-do-you-understand-how-cool-this-is/+page.md @@ -10,7 +10,7 @@ _Follow along with this video:_ You now have the power to write READABLE Solidity code, and then rewrite it in Assembly/Huff to be SUPER gas optimized. -Furthermore, you now possess the ability to FORMALLY VERIFY that the gas optimized code functions indentically to the Solidity code. +Furthermore, you now possess the ability to FORMALLY VERIFY that the gas optimized code functions identically to the Solidity code. This is HUGE. I can't stress this enough. We've mathematically proven that _any_ function called on these two contracts will behave the same. diff --git a/courses/formal-verification/3-gasbad/27-section-3-recap/+page.md b/courses/formal-verification/3-gasbad/27-section-3-recap/+page.md index 058ef9f40..50c167386 100644 --- a/courses/formal-verification/3-gasbad/27-section-3-recap/+page.md +++ b/courses/formal-verification/3-gasbad/27-section-3-recap/+page.md @@ -12,7 +12,7 @@ We just learnt a tonne, and in record time. Let's recap some of the things we co ### .conf -By writing 2 more .conf files, we gained a bunch more experience in configurating our formal verification tests. We learnt different options within this configuration such as: +By writing 2 more .conf files, we gained a bunch more experience in configuring our formal verification tests. We learnt different options within this configuration such as: - `rule_sanity` - We experimented with `basic` and `none` and saw how this affected Certora's assessment of the `sanity` or soundness of our tests - `prover_args` - options we can pass our CLI to fine tune the assumptions of the prover. @@ -42,7 +42,7 @@ By writing 2 more .conf files, we gained a bunch more experience in configuratin **Summary Declarations** -We also learnt about summary declarations, the DISPATCHER summary in particular. Summary Declaractions allow us to tell the Certora provers to replace any function logic with whatever behaviour we want. In the case of our external calls, we use the DISPATCHER summary in order to restrict what the prover expects to be the result of these calls, which is otherwise unpredicatable. +We also learnt about summary declarations, the DISPATCHER summary in particular. Summary Declarations allow us to tell the Certora provers to replace any function logic with whatever behaviour we want. In the case of our external calls, we use the DISPATCHER summary in order to restrict what the prover expects to be the result of these calls, which is otherwise unpredictable. ```js function _.onERC721Received(address, address, uint256, bytes) external => DISPATCHER(true); diff --git a/courses/foundry/1-foundry-simple-storage/12-deploy-a-smart-contract-locally-using-ganache/+page.md b/courses/foundry/1-foundry-simple-storage/12-deploy-a-smart-contract-locally-using-ganache/+page.md index bc9d5ae7c..44956a6d8 100644 --- a/courses/foundry/1-foundry-simple-storage/12-deploy-a-smart-contract-locally-using-ganache/+page.md +++ b/courses/foundry/1-foundry-simple-storage/12-deploy-a-smart-contract-locally-using-ganache/+page.md @@ -78,7 +78,7 @@ To send a transaction to your custom blockchain, you need to add it as a network Block explorer URL: - (we don't have a block explorer for our newly created blockchain, which will most likely disappear when we close the VS Code / Ganache app) -Great! Now that we configured our local network, the next step is to add one of the accounts available in Ganche or Anvil into our MetaMask. [This is done as follows](https://support.metamask.io/hc/en-us/articles/360015489331-How-to-import-an-account#h_01G01W07NV7Q94M7P1EBD5BYM4): +Great! Now that we configured our local network, the next step is to add one of the accounts available in Ganache or Anvil into our MetaMask. [This is done as follows](https://support.metamask.io/hc/en-us/articles/360015489331-How-to-import-an-account#h_01G01W07NV7Q94M7P1EBD5BYM4): 1. Click the account selector at the top of your wallet. diff --git a/courses/foundry/1-foundry-simple-storage/21-deploying-to-a-testnet/+page.md b/courses/foundry/1-foundry-simple-storage/21-deploying-to-a-testnet/+page.md index ef4e1332d..2f1039d80 100644 --- a/courses/foundry/1-foundry-simple-storage/21-deploying-to-a-testnet/+page.md +++ b/courses/foundry/1-foundry-simple-storage/21-deploying-to-a-testnet/+page.md @@ -18,7 +18,7 @@ Clearly, we need an actual testnet for a real network. But our trusty MetaMask h _To create one, we could run our own blockchain node, but let's be honest — many folks prefer avoiding that route. Instead, we utilize Node as a Service (NaaS) applications to expedite the process._ -One promising option is using Alchemy - a free NaaS platform that we can send the transactions to. This procedure resides within the _Deploying to Testnet or Mainnnet_ section in the full course repo of the Foundry. +One promising option is using Alchemy - a free NaaS platform that we can send the transactions to. This procedure resides within the _Deploying to Testnet or Mainnet_ section in the full course repo of the Foundry. ::image{src='/foundry/19-testnet-deploy/testnet1.png' style='width: 100%; height: auto;'} diff --git a/courses/foundry/2-foundry-fund-me/15-adding-more-coverage-to-the-tests/+page.md b/courses/foundry/2-foundry-fund-me/15-adding-more-coverage-to-the-tests/+page.md index 9a4c3d184..5bfb2f7f9 100644 --- a/courses/foundry/2-foundry-fund-me/15-adding-more-coverage-to-the-tests/+page.md +++ b/courses/foundry/2-foundry-fund-me/15-adding-more-coverage-to-the-tests/+page.md @@ -27,7 +27,7 @@ What's happening here? We start with our user `alice` who calls `fundMe.fund` in Run the test using `forge test --mt testAddsFunderToArrayOfFunders`. It passed, perfect! -Each of our tests uses a fresh `setUp`, so if we run all of them and `testFundUpdatesFundDataStrucutre` calls `fund`, that won't be persistent for `testAddsFunderToArrayOfFunders`. +Each of our tests uses a fresh `setUp`, so if we run all of them and `testFundUpdatesFundDataStructure` calls `fund`, that won't be persistent for `testAddsFunderToArrayOfFunders`. Moving on, we should test the `withdraw` function. Let's check that only the owner can `withdraw`. @@ -183,7 +183,7 @@ As we've talked about above, we use the `uint160` index to obtain an address. We The `SEND_VALUE` specified in `hoax` represents the ether value that will be provided to `address(i)`. -Good, now that we have pranked an address and it has some balance we call `fundeMe.fund`. +Good, now that we have pranked an address and it has some balance we call `fundMe.fund`. After the loop ends we repeat what we did in the `testWithdrawFromASingleFunder`. We record the contract and owner's starting balances. This concludes our `Arrange` stage. diff --git a/courses/foundry/2-foundry-fund-me/17-calculate-withdraw-gas-costs/+page.md b/courses/foundry/2-foundry-fund-me/17-calculate-withdraw-gas-costs/+page.md index 23e50216a..e2432e290 100644 --- a/courses/foundry/2-foundry-fund-me/17-calculate-withdraw-gas-costs/+page.md +++ b/courses/foundry/2-foundry-fund-me/17-calculate-withdraw-gas-costs/+page.md @@ -90,7 +90,7 @@ Compiler run successful! Ran 1 test for test/FundMe.t.sol:FundMeTest [PASS] testWithdrawFromASingleFunder() (gas: 87869) Logs: - Withdraw consummed: 10628 gas + Withdraw consumed: 10628 gas Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.67ms (2.06ms CPU time) ``` diff --git a/courses/foundry/2-foundry-fund-me/18-introduction-to-storage-optimization/+page.md b/courses/foundry/2-foundry-fund-me/18-introduction-to-storage-optimization/+page.md index d67a158a2..a43c4dd81 100644 --- a/courses/foundry/2-foundry-fund-me/18-introduction-to-storage-optimization/+page.md +++ b/courses/foundry/2-foundry-fund-me/18-introduction-to-storage-optimization/+page.md @@ -34,7 +34,7 @@ The important aspects are the following: Now this seems like a lot, but let's go through some examples: (Try to think about how the storage looks before reading the description) -```solidit +```solidity uint256 var1 = 1337; uint256 var2 = 9000; uint64 var3 = 0; diff --git a/courses/foundry/2-foundry-fund-me/21-automate-your-smart-contracts-actions-makefile/+page.md b/courses/foundry/2-foundry-fund-me/21-automate-your-smart-contracts-actions-makefile/+page.md index 825ed286a..eeccdb7c6 100644 --- a/courses/foundry/2-foundry-fund-me/21-automate-your-smart-contracts-actions-makefile/+page.md +++ b/courses/foundry/2-foundry-fund-me/21-automate-your-smart-contracts-actions-makefile/+page.md @@ -122,7 +122,7 @@ Treat this `Makefile` as a framework for your projects. Open the file and go through it. -The `.PHONY:` tells make that all the `all test clean deploy fund help install snapshot format anvil` are not folders. Following that we declare the `DEFAULT_ANIVL_KEY` and a custom help message. +The `.PHONY:` tells make that all the `all test clean deploy fund help install snapshot format anvil` are not folders. Following that we declare the `DEFAULT_ANVIL_KEY` and a custom help message. Run make help to print it in your terminal. diff --git a/courses/foundry/2-foundry-fund-me/8-running-tests-on-chains-forks/+page.md b/courses/foundry/2-foundry-fund-me/8-running-tests-on-chains-forks/+page.md index bc21c2ec0..4e4966d4b 100644 --- a/courses/foundry/2-foundry-fund-me/8-running-tests-on-chains-forks/+page.md +++ b/courses/foundry/2-foundry-fund-me/8-running-tests-on-chains-forks/+page.md @@ -38,7 +38,7 @@ Back to our problem, how can we fix this? Forking is the solution we need. If we run the test on an anvil instance that copies the current Sepolia state, where AggregatorV3 exists at that address, then our test function will not revert anymore. For that, we need a Sepolia RPC URL. -Remember how in a [previous lesson we delpoyed a smart contract on Sepolia](https://updraft.cyfrin.io/courses/foundry/foundry-simple-storage/deploying-smart-contract-testnet-sepolia)? It's similar, we can use the same RPC we used back then. +Remember how in a [previous lesson we deployed a smart contract on Sepolia](https://updraft.cyfrin.io/courses/foundry/foundry-simple-storage/deploying-smart-contract-testnet-sepolia)? It's similar, we can use the same RPC we used back then. Thus: diff --git a/courses/foundry/3-html-fund-me/3-metamask/+page.md b/courses/foundry/3-html-fund-me/3-metamask/+page.md index 0f8cba1f9..9c9490204 100644 --- a/courses/foundry/3-html-fund-me/3-metamask/+page.md +++ b/courses/foundry/3-html-fund-me/3-metamask/+page.md @@ -112,7 +112,7 @@ As before, we're checking for the existence of `window.ethereum` and then .. def ### RPC URLs and Providers -`ethers` is a javascript package that simplifies the use and interacation of browser wallets with our code. +`ethers` is a javascript package that simplifies the use and interaction of browser wallets with our code. What `ethers.BrowserProvider(window.ethereum)` is doing, is deriving the providers MetaMask is injecting into our `window.ethereum` object. The providers are the RPC URLs associated with the networks in our MetaMask account. diff --git a/courses/foundry/4-smart-contract-lottery/16-implementing-chainlink-automation/+page.md b/courses/foundry/4-smart-contract-lottery/16-implementing-chainlink-automation/+page.md index ec8cf6939..5e6e828cc 100644 --- a/courses/foundry/4-smart-contract-lottery/16-implementing-chainlink-automation/+page.md +++ b/courses/foundry/4-smart-contract-lottery/16-implementing-chainlink-automation/+page.md @@ -20,7 +20,7 @@ For this to work we need to refactor the `pickWinner` function. That functionali * 2. The lottery is open. * 3. The contract has ETH. * 4. There are players registered. - * 5. Implicity, your subscription is funded with LINK. + * 5. Implicitly, your subscription is funded with LINK. */ function checkUpkeep(bytes memory /* checkData */) public view returns (bool upkeepNeeded, bytes memory /* performData */) { bool isOpen = RaffleState.OPEN == s_raffleState; @@ -45,7 +45,7 @@ Back to our raffle now, what are the conditions required to be true in order to * 2. The lottery is open. * 3. The contract has ETH. * 4. There are players registered. - * 5. Implicity, your subscription is funded with LINK. + * 5. Implicitly, your subscription is funded with LINK. ``` For points 1-3 we coded the following lines: diff --git a/courses/foundry/4-smart-contract-lottery/19-tests-and-deploy-the-lotterys-smart-contract-pt1/+page.md b/courses/foundry/4-smart-contract-lottery/19-tests-and-deploy-the-lotterys-smart-contract-pt1/+page.md index 97c63bcc1..27096b1cf 100644 --- a/courses/foundry/4-smart-contract-lottery/19-tests-and-deploy-the-lotterys-smart-contract-pt1/+page.md +++ b/courses/foundry/4-smart-contract-lottery/19-tests-and-deploy-the-lotterys-smart-contract-pt1/+page.md @@ -56,7 +56,7 @@ This code is good on its own, but, we can make it better. For example, we need a Before that, let's write some tests. -Inside the `test` folder create two new folders called `intergration` and `unit`. Here we'll put our integration and unit tests. Inside the newly created `unit` folder create a file called `RaffleTest.t.sol`. +Inside the `test` folder create two new folders called `integration` and `unit`. Here we'll put our integration and unit tests. Inside the newly created `unit` folder create a file called `RaffleTest.t.sol`. Let's start writing the first test. You've already done this at least two times in this section. Try to do it on your own and come back when you get stuck. diff --git a/courses/foundry/4-smart-contract-lottery/23-setup-the-tests/+page.md b/courses/foundry/4-smart-contract-lottery/23-setup-the-tests/+page.md index 33affbab5..2fa9753f6 100644 --- a/courses/foundry/4-smart-contract-lottery/23-setup-the-tests/+page.md +++ b/courses/foundry/4-smart-contract-lottery/23-setup-the-tests/+page.md @@ -66,11 +66,11 @@ We call `vm.prank(PLAYER)` to configure the fact that the next transaction will After that we use the `vm.expectRevert` [cheatcode](https://book.getfoundry.sh/cheatcodes/expect-revert?highlight=expectRevert#expectrevert) to test if the next call will revert. We also have the option to specify the error message. You can do that by calling the `errorName.selector` as input of the `vm.expectRevert` cheatcode. Following that we call the `enterRaffle` without specifying the `value` of the transaction. -Run the test using `forge test --mt testRaffleRevertsWHenYouDontPayEnought`. +Run the test using `forge test --mt testRaffleRevertsWHenYouDontPayEnough`. ``` Ran 1 test for test/unit/RaffleTest.t.sol:RaffleTest -[PASS] testRaffleRevertsWHenYouDontPayEnought() (gas: 10865) +[PASS] testRaffleRevertsWHenYouDontPayEnough() (gas: 10865) Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.99ms (161.70µs CPU time) ``` diff --git a/courses/foundry/4-smart-contract-lottery/31-adding-a-consumer/+page.md b/courses/foundry/4-smart-contract-lottery/31-adding-a-consumer/+page.md index 659438588..c345c5d13 100644 --- a/courses/foundry/4-smart-contract-lottery/31-adding-a-consumer/+page.md +++ b/courses/foundry/4-smart-contract-lottery/31-adding-a-consumer/+page.md @@ -77,7 +77,7 @@ So... what happened here? 1. We used `DevOpsTools` to grab the last deployment of the `Raffle` contract inside the `run` function; 2. We also call `addConsumerUsingConfig` inside the `run` function; 3. We define `addConsumerUsingConfig` as a public function taking an address as an input; -4. We deploy a new `HelperConfig` and call `activeNetworkConfig` to grab the `vrfCoordinato` and `subscriptionId` addresses; +4. We deploy a new `HelperConfig` and call `activeNetworkConfig` to grab the `vrfCoordinate` and `subscriptionId` addresses; 5. We call the `addConsumer` function; 6. We define `addConsumer` as a public function taking 3 input parameters: address of the `raffle` contract, address of `vrfCoordinator` and `subscriptionId`; 7. We log some things useful for debugging; @@ -87,7 +87,7 @@ Try a nice `forge build` and check if everything is compiling. Perfect! Let's go back to `DeployRaffle.s.sol` and import the thing we added in `Interactions.s.sol`: -`import {CreateSubscription, FundSubscription, AddConsummer} from "./Interactions.s.sol";` +`import {CreateSubscription, FundSubscription, AddConsumer} from "./Interactions.s.sol";` Now let's integrate the `FundSubscription` with the `CreateSubscription` bit: diff --git a/courses/foundry/4-smart-contract-lottery/37-one-big-test/+page.md b/courses/foundry/4-smart-contract-lottery/37-one-big-test/+page.md index 438800fc6..fd63d6a4c 100644 --- a/courses/foundry/4-smart-contract-lottery/37-one-big-test/+page.md +++ b/courses/foundry/4-smart-contract-lottery/37-one-big-test/+page.md @@ -138,7 +138,7 @@ Now we are ready to start our assertions. 11. We assert that the raffle state is `OPEN` because that's how our raffle should be after the winner is drawn and the prize is sent; 12. We assert that we have chosen a winner; 13. We assert that the `s_players` array has been properly reset, so players from the previous raffle don't get to participate in the next one without paying; -14. We assert that the `fullfillRandomWords` updates the `s_lastTimeStamp` variable; +14. We assert that the `fulfillRandomWords` updates the `s_lastTimeStamp` variable; 15. We assert that the winner receives their ETH prize; Amazing work, let's try it out with `forge test --mt testFulfillRandomWordsPicksAWinnerResetsAndSendsMoney --vv`. diff --git a/courses/foundry/4-smart-contract-lottery/40-testnet-demo/+page.md b/courses/foundry/4-smart-contract-lottery/40-testnet-demo/+page.md index b1034f61c..617fa22ea 100644 --- a/courses/foundry/4-smart-contract-lottery/40-testnet-demo/+page.md +++ b/courses/foundry/4-smart-contract-lottery/40-testnet-demo/+page.md @@ -80,7 +80,7 @@ deploy: The `@` indicates that we don't want this line printed out. We do this because if not used it will print out your private key, and we don't want that. -Every time we use an environment variable in the Makefile we use the dollar sign and paranthesis to flag it as an environment variable. The `forge script` above won't work as is because we don't have any `NETWORK_ARGS` defined. Our main goal is to be able to call the following command `make deploy ARGS="--network sepolia"` and our Makefile to automatically grab the proper Sepolia deployment parameters. +Every time we use an environment variable in the Makefile we use the dollar sign and parenthesis to flag it as an environment variable. The `forge script` above won't work as is because we don't have any `NETWORK_ARGS` defined. Our main goal is to be able to call the following command `make deploy ARGS="--network sepolia"` and our Makefile to automatically grab the proper Sepolia deployment parameters. Put the following above your `deploy` target: diff --git a/courses/foundry/4-smart-contract-lottery/6-random-numbers-block-timestamp/+page.md b/courses/foundry/4-smart-contract-lottery/6-random-numbers-block-timestamp/+page.md index 1c257eb2e..ff9331372 100644 --- a/courses/foundry/4-smart-contract-lottery/6-random-numbers-block-timestamp/+page.md +++ b/courses/foundry/4-smart-contract-lottery/6-random-numbers-block-timestamp/+page.md @@ -56,7 +56,7 @@ contract Raffle{ constructor(uint256 entranceFee, uint256 interval) { i_entranceFee = entranceFee; i_interval = interval; - s_lastTimeStamp = block.timestmap; + s_lastTimeStamp = block.timestamp; } } ``` diff --git a/courses/foundry/4-smart-contract-lottery/7-random-numbers-introduction-to-chainlink-vrf/+page.md b/courses/foundry/4-smart-contract-lottery/7-random-numbers-introduction-to-chainlink-vrf/+page.md index c78aef625..b8231d871 100644 --- a/courses/foundry/4-smart-contract-lottery/7-random-numbers-introduction-to-chainlink-vrf/+page.md +++ b/courses/foundry/4-smart-contract-lottery/7-random-numbers-introduction-to-chainlink-vrf/+page.md @@ -96,7 +96,7 @@ function requestRandomWords() This function is the place where we call the `requestRandomWords` on the `VRFCoordinatorV2Interface` which sends us back the `requestId`. We record this `requestId` in the mapping, creating its `RequestStatus`, we push it into the `requestIds` array and update the `lastRequestId` variable. The function returns the `requestId`. -After calling the function above, Chainlink will call your `fulfillRandomWords` function. They will provide the `_requestId` corresponding to your `requestRandomWords` call together with the `_randomWrods`. It updates the `fulfilled` and `randomWords` struct parameters. In real-world applications, this is where the logic happens. If you have to assign some traits to an NFT, roll a dice, draw the raffle winner, etc. +After calling the function above, Chainlink will call your `fulfillRandomWords` function. They will provide the `_requestId` corresponding to your `requestRandomWords` call together with the `_randomWords`. It updates the `fulfilled` and `randomWords` struct parameters. In real-world applications, this is where the logic happens. If you have to assign some traits to an NFT, roll a dice, draw the raffle winner, etc. Great! Let's come back to the configuration parameters. The `keyHash` variable represents the gas lane we want to use. Think of those as the maximum gas price you are willing to pay for a request in gwei. It functions as an ID of the off-chain VRF job that runs in response to requests. diff --git a/courses/foundry/4-smart-contract-lottery/8-implement-the-chainlink-vrf/+page.md b/courses/foundry/4-smart-contract-lottery/8-implement-the-chainlink-vrf/+page.md index e43df5b7e..d65228e2b 100644 --- a/courses/foundry/4-smart-contract-lottery/8-implement-the-chainlink-vrf/+page.md +++ b/courses/foundry/4-smart-contract-lottery/8-implement-the-chainlink-vrf/+page.md @@ -73,7 +73,7 @@ I've divided the `Raffle` variables from the `Chainlink VRF` variables to keep t Adjust the constructor to accommodate all the new variables and imports: ```solidity -constructor(uint256 entranceFee, uint256 interval, addsress vrfCoordinator) { +constructor(uint256 entranceFee, uint256 interval, address vrfCoordinator) { i_entranceFee = entranceFee; i_interval = interval; s_lastTimeStamp = block.timestamp; diff --git a/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/37-adding-packages-uv/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/37-adding-packages-uv/+page.md index b82fac182..8acb74d0c 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/37-adding-packages-uv/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/37-adding-packages-uv/+page.md @@ -2,11 +2,11 @@ The UV tool helps us manage Python packages and dependencies across different projects and versions. -We'll use the **Titanobo** package in this lesson to showcase how UV can be used to manage dependencies. +We'll use the **Titanoboa** package in this lesson to showcase how UV can be used to manage dependencies. **Titano Boa** is a package that allows us to evaluate code written in Python. -First, let's create a simple Python script that will utilize **Titanobo**. +First, let's create a simple Python script that will utilize **Titanoboa**. ```python import boa import sys @@ -15,7 +15,7 @@ print(boa.eval('"empty(uint256())"')) print("Hello!") ``` -If we try to run this script without having **Titano Boa** installed, we'll encounter an error message as **Titanobo** is not available. +If we try to run this script without having **Titano Boa** installed, we'll encounter an error message as **Titanoboa** is not available. **Let's install Titano Boa globally using pip** ```bash diff --git a/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/38-virtual-envs/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/38-virtual-envs/+page.md index 14b967874..ad756abc4 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/38-virtual-envs/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/38-virtual-envs/+page.md @@ -2,7 +2,7 @@ Virtual environments are an important concept to understand even if we don't use `uv`. -Technically, a virtual environment is a setting that `uv` creates to isolate our Python version and packages. Back in our Cyfron Updraft terminal, we can type: +Technically, a virtual environment is a setting that `uv` creates to isolate our Python version and packages. Back in our Cyfrin Updraft terminal, we can type: ```bash uv venv diff --git a/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/5-google-ai/+page.md b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/5-google-ai/+page.md index 46bb1aec6..e1e5cc081 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/5-google-ai/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/1-python-in-updraft/5-google-ai/+page.md @@ -30,6 +30,6 @@ It's important though, that you do understand what this code is actually doing s We'll close this, and we'll delete everything in here, and start with the next section. -If you want to save this locally for later, you can hit file, download. Then you can download this as a .pymb or .py file, free to have it locally if you want to study offline as well. +If you want to save this locally for later, you can hit file, download. Then you can download this as a .pynb or .py file, free to have it locally if you want to study offline as well. We'll go ahead and create a new cell or a new block of code by scrolling down. We'll click the + Code button here. We'll get a new cell. diff --git a/courses/intermediate-python-vyper-smart-contract-development/2-web3py/3-vyper-extension/+page.md b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/3-vyper-extension/+page.md index 4308896c0..880cbf641 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/2-web3py/3-vyper-extension/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/2-web3py/3-vyper-extension/+page.md @@ -1,8 +1,8 @@ ## Vyper VS Code Extension -We'll go back to the GitHub repo for this course: [link to repo] and then we can either grab the `favorites.vy` file from the Web3py Favorite's Cyffin Updraft, or go back to the Moccasin full course. +We'll go back to the GitHub repo for this course: [link to repo] and then we can either grab the `favorites.vy` file from the Web3py Favorite's Cyfrin Updraft, or go back to the Moccasin full course. -We'll scroll up and look for the Favorite's Cyffin Updraft repo. We'll click the `favorites.vy` file and then copy the entire file. +We'll scroll up and look for the Favorite's Cyfrin Updraft repo. We'll click the `favorites.vy` file and then copy the entire file. Next, we'll go to our VS Code and right-click in the file explorer. We'll create a new file and name it `favorites.vy`, and then paste the copied code into it. diff --git a/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/12-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/12-recap/+page.md index 69d0af577..7bc3b2ad1 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/12-recap/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/3-boa-favs/12-recap/+page.md @@ -2,7 +2,7 @@ We learned a lot of things in this section. First, we learned how to deploy a smart contract using `Titanobo Boa`, and then how to interact with existing contracts. -### Deploying with Titanobo Boa +### Deploying with Titano Boa We can deploy a contract with a single line of code: @@ -10,7 +10,7 @@ We can deploy a contract with a single line of code: favorites_contract = boa.load("favorites.vy") ``` -This will compile, deploy, and send a transaction to a fake PyEVM chain, which is a local chain that `Titanobo Boa` spins up. We will not be using local chains after this section. +This will compile, deploy, and send a transaction to a fake PyEVM chain, which is a local chain that `Titano Boa` spins up. We will not be using local chains after this section. ### Interacting with Existing Contracts @@ -70,4 +70,4 @@ def main(): ### Moccasin -This is the last section of the `Titanobo Boa` series, in the next section we'll move on to the `Moccasin` series. +This is the last section of the `Titano Boa` series, in the next section we'll move on to the `Moccasin` series. diff --git a/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/27-recap/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/27-recap/+page.md index 39489661d..18f27cfdc 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/27-recap/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/27-recap/+page.md @@ -91,4 +91,4 @@ mocassin-0 = "0.3.4b2", pytest-8 = "8.3.3", ``` -You have learned an absolute ton in this section. And you should be incredibly proud of yourself. Now, if you haven't shared on Twitter or on some social media, I'm going to just tell you one more time, you absolutely should. Joining the developer community is going to a increase your chances of getting a job if that's what you're looking for. b you're going to get to meet a ton of really cool phenomenal people. And c give you a chance to Yeah, join like-minded individuals. You can join here or if you're on Cyffin Updraft, you can of course join the Discord and meet a ton of other like-minded developers as well. That being said, huge congratulations for getting this far. And huge congratulations for finishing Mocassin Favorites. +You have learned an absolute ton in this section. And you should be incredibly proud of yourself. Now, if you haven't shared on Twitter or on some social media, I'm going to just tell you one more time, you absolutely should. Joining the developer community is going to a increase your chances of getting a job if that's what you're looking for. b you're going to get to meet a ton of really cool phenomenal people. And c give you a chance to Yeah, join like-minded individuals. You can join here or if you're on Cyfrin Updraft, you can of course join the Discord and meet a ton of other like-minded developers as well. That being said, huge congratulations for getting this far. And huge congratulations for finishing Mocassin Favorites. diff --git a/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/9-using-key/+page.md b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/9-using-key/+page.md index 4c59eed74..291bc710f 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/9-using-key/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/4-mox-favs/9-using-key/+page.md @@ -1,6 +1,6 @@ -## Using an encrypted key in your moccasain script +## Using an encrypted key in your moccasin script -We've already encrypted a private key in our Mocaasain project and have the following in our `mocassin.toml` file. +We've already encrypted a private key in our Moccasin project and have the following in our `mocassin.toml` file. ```toml [project] diff --git a/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/25-workshop/+page.md b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/25-workshop/+page.md index e35133e52..1b384b4c2 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/25-workshop/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/6-mox-coffee/25-workshop/+page.md @@ -16,9 +16,9 @@ Here is how we'll do it: We'll use this command to run our tests, which will output the coverage we have achieved. -2. Sign up for [Cyfrn Profiles](https://profiles.cyfrn.io/). +2. Sign up for [Cyfrin Profiles](https://profiles.cyfrn.io/). - This is very important for building your web3 career. Cyfrn Profiles provides a platform for you to showcase your skills, find opportunities, and build a network of fellow developers. + This is very important for building your web3 career. Cyfrin Profiles provides a platform for you to showcase your skills, find opportunities, and build a network of fellow developers. 3. Push your code to GitHub diff --git a/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/2-introduction/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/2-introduction/+page.md index d3234817e..5fdf7ea8a 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/2-introduction/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/2-introduction/+page.md @@ -5,12 +5,12 @@ In this lesson, we will take a look at HTML/JS Fund Me (Quick Fullstack/Front En We can find the code for this lesson on our GitHub repo: ```python -Cyfriin/foundry-full-course-f23 +Cyfrin/foundry-full-course-f23 ``` In this lesson we will be learning the basics of how our MetaMask or wallet interacts with a website. This is important knowledge. We will also be teaching you how to verify that your wallet is sending the transaction that you intended to send. -We will not be teaching you how to build a full-stack application in this lesson. However, we are planning to launch a full-stack course on Cyfriin Updraft in the future. +We will not be teaching you how to build a full-stack application in this lesson. However, we are planning to launch a full-stack course on Cyfrin Updraft in the future. This HTML/JS Fund Me is a very basic, raw JavaScript full-website application. If you want to try to replicate it, you are free to do so. However, it is important that you understand what is going on under the hood when you interact with these websites. The knowledge that we are going to teach you here will work for every single website you interact with. This will allow you to know exactly what's going on when you interact with a website and send a transaction to the blockchain. diff --git a/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/5-function-selectors/+page.md b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/5-function-selectors/+page.md index f698adbc9..351354cc2 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/5-function-selectors/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/7-mox-html/5-function-selectors/+page.md @@ -4,7 +4,7 @@ We'll look at function selectors and how they work within a smart contract. We c If we go to the **DATA** tab, we see the function type is **Fund**. -We can also see the raw transaction data in the **HEX** section of the transaction. We see the value, which is 0.1 GO or etherium. +We can also see the raw transaction data in the **HEX** section of the transaction. We see the value, which is 0.1 GO or ethereum. We are going to explore function selectors in greater detail in a later lesson, but for now, we can see how they operate. diff --git a/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/1-intro/+page.md b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/1-intro/+page.md index 094de6a65..eb021669a 100644 --- a/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/1-intro/+page.md +++ b/courses/intermediate-python-vyper-smart-contract-development/8-mox-erc20/1-intro/+page.md @@ -152,7 +152,7 @@ from eth_utils import to_wei ``` ```python -from moccasine.boa_tools import VyperContract +from moccasin.boa_tools import VyperContract ``` ```python diff --git a/courses/intro-python-vyper-smart-contract-development/1-favorites/2-best-practices/+page.md b/courses/intro-python-vyper-smart-contract-development/1-favorites/2-best-practices/+page.md index 66a9e0c34..b08949f28 100644 --- a/courses/intro-python-vyper-smart-contract-development/1-favorites/2-best-practices/+page.md +++ b/courses/intro-python-vyper-smart-contract-development/1-favorites/2-best-practices/+page.md @@ -2,9 +2,9 @@ We're going to start off by talking about some best practices so that you can get the absolute most out of this course and be as effective as possible. -You're either watching this on Cyfr.in Updraft or on YouTube. We encourage everyone to watch this on Cyfr.in Updraft, because we've got a ton of features to make the learning experience that much easier for you. +You're either watching this on Cyfrin Updraft or on YouTube. We encourage everyone to watch this on Cyfrin Updraft, because we've got a ton of features to make the learning experience that much easier for you. -If you are watching this on Cyfr.in Updraft, though, there's a couple links I need you to be aware of. The first one, in the top right, is going to be the GitHub Resources page. This will bring you over to what's called a GitHub repo, or a GitHub repository, or basically a site that has all the code and all the information and basically all the materials that you're going to need to learn everything in our curriculum. You could basically think of this as your bible for the duration of your blockchain developer journey. +If you are watching this on Cyfrin Updraft, though, there's a couple links I need you to be aware of. The first one, in the top right, is going to be the GitHub Resources page. This will bring you over to what's called a GitHub repo, or a GitHub repository, or basically a site that has all the code and all the information and basically all the materials that you're going to need to learn everything in our curriculum. You could basically think of this as your bible for the duration of your blockchain developer journey. Additionally, in this GitHub, there's a Discussions tab right here that you can click on, and in here is where you can ask questions, discuss with other people taking the course, interact with members helping out, and it's where you can discuss anything that you're having trouble with. @@ -20,27 +20,27 @@ Additionally, there's a link to join the GitHub discussions. This is your platfo Additionally, there is a link to the Discord for more real-time communication. I urge you to ask questions in the GitHub discussions as well, because those are going to be indexed, going to make them much easier to Google search later and have them show up, as opposed to Discord. Discord is still phenomenal for you to join them. -For those of you watching on YouTube, hello, you should scroll down to the description, and in the description are going to be links to these resources as well, and additionally, a link to Cyfr.in Updraft. If you've been watching, you've already seen some of the advantages that Cyfr.in Updraft has, including Written Lessons, single videos, and there's also ways to track your progress instead of having to scrub on a giant YouTube video. So, for all of you who are watching this on YouTube, definitely be sure to go over to Cyfr.in Updraft, sign up there and watch the curriculum there because your learning experience will be much better. But, leave this video playing in the background on YouTube, so we get the bump from the YouTube algorithm. Thank you. +For those of you watching on YouTube, hello, you should scroll down to the description, and in the description are going to be links to these resources as well, and additionally, a link to Cyfrin Updraft. If you've been watching, you've already seen some of the advantages that Cyfrin Updraft has, including Written Lessons, single videos, and there's also ways to track your progress instead of having to scrub on a giant YouTube video. So, for all of you who are watching this on YouTube, definitely be sure to go over to Cyfrin Updraft, sign up there and watch the curriculum there because your learning experience will be much better. But, leave this video playing in the background on YouTube, so we get the bump from the YouTube algorithm. Thank you. That being said, as we go through this course, we're also going to teach you some best practices on working with artificial intelligence, how to best prompt these AIs, so that they can give you the best results. Just keep in mind, they sometimes get things wrong. And, it's a good idea if you are going to use an AI to fact-check it with a human, or another resource. So, be sure to say hi in the discussions and maybe meet some like-minded peers. -And, additionally, once we do get to the coding portion of this course, it's a good idea to code along with me, as I'm explaining things. So, having the video up, as well as your coding screen, is a good idea, so you can follow along with me, as I'm explaining it. If you're watching this on Cyfr.in Updraft, you can just click the little video pop-out button and have the video pop out as such, and code next to it. +And, additionally, once we do get to the coding portion of this course, it's a good idea to code along with me, as I'm explaining things. So, having the video up, as well as your coding screen, is a good idea, so you can follow along with me, as I'm explaining it. If you're watching this on Cyfrin Updraft, you can just click the little video pop-out button and have the video pop out as such, and code next to it. All of this is to say, if you run into an issue, jump to that GitHub repo, and make a discussion. We will also be giving you some tips very soon about how to best make a discussion. Yes, asking well-formatted questions is not only the secret to being a fantastic AI prompt engineer, but also becoming an incredibly successful developer. We're going to learn how to ask well-formatted questions, and whenever we post on discussions or forums or whatever, we're going to work on formatting them as best as possible. Take breaks. I cannot tell you how many people have tried to rush through these courses and be like, "Oh, I'm going to finish in a single weekend!" Your brain doesn't work like that. Your brain needs time to absorb the information, so take breaks. Maybe every 25 minutes to a half hour, take a 5 minute break, or maybe you like working in longer chunks, maybe take a whole hour, and then take a 15-20 minute break. Don't try to rush through the whole video in a day, you're not going to retain the information. Go outside, go for a walk, grab some ice cream, get some coffee, go to the gym. Your brain needs time to have the information settle. Maybe every 2 hours, just step away. Maybe be done for the day. Work at whatever pace makes sense for you. Everyone's going to have a different learning pace. There is no right speed for this course. I've had people take my courses in 2 weeks, in 3 months, in 6 months. It doesn't matter. Pick a pace that you can do, and stick to it. Not only work at your pace, make sure that I'm talking at a pace that makes sense for you. There's a little gear icon in the YouTube video here, where you can change the speed of how I'm talking and how fast the video's going. So, if I'm talking way too fast for you, then you can slow me down. But, if I'm talking too slow, then you can speed me up. -And, if you're watching this on Cyfr.in Updraft, you have the same dials as well in the bottom right-hand corner. Additionally, if English isn't your native language, we have several different subtitles on the Cyfr.in Updraft video player as well. So, make the adjustments you need to make me go the speed you want me to go. And, of course, this course is modular, so you can bounce around topic to topic, and go to where you want to go. +And, if you're watching this on Cyfrin Updraft, you have the same dials as well in the bottom right-hand corner. Additionally, if English isn't your native language, we have several different subtitles on the Cyfrin Updraft video player as well. So, make the adjustments you need to make me go the speed you want me to go. And, of course, this course is modular, so you can bounce around topic to topic, and go to where you want to go. You don't want to do any full stack stuff, then skip that section. If you want to go right to the advanced stuff, do that. Like I said, go the pace and take the learnings that you want to do. And, after every lesson, it might be a good idea to go back and reflect on each lesson to really make sure the knowledge gets ingrained. Repetition is the mother of skill, and we're going to be repeating a lot of smart contract development. -Now, the last bit here is in the Cyfr.in Updraft platform. We're going to have quizzes that you can take to help see if you learn the knowledge that you were supposed to learn. +Now, the last bit here is in the Cyfrin Updraft platform. We're going to have quizzes that you can take to help see if you learn the knowledge that you were supposed to learn. -If you're watching this on YouTube, you don't have that, so go sign up for Cyfr.in Updraft and then play the YouTube video in the background, so the YouTube algorithm bumps this stuff. But, additionally, at the end of every section, if you go to the GitHub repo associated with that section, and you scroll down, there's going to be a bonus NFTs section with a link. This will bring you to a coding challenge on chain that you can actually solve to mint yourself an NFT, a badge of honor proving that you gained the knowledge that you were supposed to. +If you're watching this on YouTube, you don't have that, so go sign up for Cyfrin Updraft and then play the YouTube video in the background, so the YouTube algorithm bumps this stuff. But, additionally, at the end of every section, if you go to the GitHub repo associated with that section, and you scroll down, there's going to be a bonus NFTs section with a link. This will bring you to a coding challenge on chain that you can actually solve to mint yourself an NFT, a badge of honor proving that you gained the knowledge that you were supposed to. These are optional challenges that you can do to try to make sure that you actually learned what was meant to be learned here. diff --git a/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/19-integer-division/+page.md b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/19-integer-division/+page.md index 7f0505d68..9c463d24e 100644 --- a/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/19-integer-division/+page.md +++ b/courses/intro-python-vyper-smart-contract-development/2-remix-coffee/19-integer-division/+page.md @@ -66,7 +66,7 @@ We can see that this works by trying a few examples. Let's compile this and deploy it. ```bash -Compile buy_me_a_cofee.vy +Compile buy_me_a_coffee.vy ``` We'll grab any address, like our price feed address. We'll scroll down and put in one for divide_me. What do you think we'll get if we do 1 / 3? diff --git a/courses/security/0-introduction/6-exercises/+page.md b/courses/security/0-introduction/6-exercises/+page.md index 49b4de73b..2edc1c0ea 100644 --- a/courses/security/0-introduction/6-exercises/+page.md +++ b/courses/security/0-introduction/6-exercises/+page.md @@ -8,7 +8,7 @@ _Follow along with this video_ --- -### Section 0: Excercises +### Section 0: Exercises The first exercise is important. This is **just for you**. This isn't meant to be a motivation to share with others, or chat about publicly, this is what inspired you to take the first step and what will continue to inspire you to take the next. diff --git a/courses/security/1-review/11-encoding-function/+page.md b/courses/security/1-review/11-encoding-function/+page.md index c91e326eb..ece536a96 100644 --- a/courses/security/1-review/11-encoding-function/+page.md +++ b/courses/security/1-review/11-encoding-function/+page.md @@ -1,5 +1,5 @@ --- -title: Introduction to Enconding Function Calls Directly +title: Introduction to Encoding Function Calls Directly --- _Follow along with the video_ @@ -13,7 +13,7 @@ With the previous lesson's foundation laid, lets look at what encoding is like w We know the EVM is looking for this encoded information, this binary _stuff_. And since transactions sent to the blockchain are ultimately compiled down to this binary, what this allows us to do is populate the `Data` property of a transaction with this binary ourselves. -::image{src='/security-section-1/11-encoding-function/encoding-function2.png' style='width: 95%; height: auto;' alt='block fee' caption='Remember the properties of a Transaction' captionSyle='font-size: 10px' figureStyle='display: flex; flex-direction: column; align-items: center;'} +::image{src='/security-section-1/11-encoding-function/encoding-function2.png' style='width: 95%; height: auto;' alt='block fee' caption='Remember the properties of a Transaction' captionStyle='font-size: 10px' figureStyle='display: flex; flex-direction: column; align-items: center;'} ### ABI Encoding and Transactions diff --git a/courses/security/1-review/12-upgradeable-contracts/+page.md b/courses/security/1-review/12-upgradeable-contracts/+page.md index d3c39e606..f25d329b6 100644 --- a/courses/security/1-review/12-upgradeable-contracts/+page.md +++ b/courses/security/1-review/12-upgradeable-contracts/+page.md @@ -118,7 +118,7 @@ With that all set up, here's what we'd do next: 1. deploy both `SmallProxy.sol` and `ImplementationA.sol` 2. call the `setImplementation()` function on `SmallProxy.sol`, passing it `ImplementationA`'s address as an argument 3. acquire the data needed for the transaction being sent - > By passing `777` to our `getDataToTransact()` function we have returned: `0x552410770000000000000000000000000000000000000000000000000000000000000309` this encodes the `function signature` with the passed arguement of `777`. + > By passing `777` to our `getDataToTransact()` function we have returned: `0x552410770000000000000000000000000000000000000000000000000000000000000309` this encodes the `function signature` with the passed argument of `777`. When this is passed to our proxy contract, the contract won't recognize the function signature, will call `fallback()` (which calls `_delegate()`) and pass the data to our implementation contract which DOES recognize this data! @@ -156,4 +156,4 @@ When we then pass the same data as before to our proxy contract, we can indeed s Now, with this understanding in hand, it's easy to see the power proxies hold. On one hand, they are very convenient and afford developers some safeguard if things should need to change. On the other - if this process is controlled by a single (or small group) of wallets, this opens the door to some high risk centralization concerns. -Next, we'll be looking at `selfDestruct` and how it can be used to circumvent intended contract funtionality! +Next, we'll be looking at `selfDestruct` and how it can be used to circumvent intended contract functionality! diff --git a/courses/security/1-review/3-fuzzing-and-invariants/+page.md b/courses/security/1-review/3-fuzzing-and-invariants/+page.md index 7d4d0d6d2..eb1501ebd 100644 --- a/courses/security/1-review/3-fuzzing-and-invariants/+page.md +++ b/courses/security/1-review/3-fuzzing-and-invariants/+page.md @@ -65,7 +65,7 @@ function testIsAlwaysGetZeroFuzz(uint256 data) public { } ``` -Foundry will automatically randomize data and use numerous examples to run through the test script. This test will be supplied random data from 0 to uint256.max(), as many times as you've conifigured runs. +Foundry will automatically randomize data and use numerous examples to run through the test script. This test will be supplied random data from 0 to uint256.max(), as many times as you've configured runs. > Reminder: You can configure the number of runs in your foundry.toml under the [fuzz] variable diff --git a/courses/security/1-review/9-fallback-and-receive/+page.md b/courses/security/1-review/9-fallback-and-receive/+page.md index 935e9749d..c72faf7df 100644 --- a/courses/security/1-review/9-fallback-and-receive/+page.md +++ b/courses/security/1-review/9-fallback-and-receive/+page.md @@ -6,7 +6,7 @@ _Follow along with the video_ --- -In the world of Solidity smart contracts, it's important to understand the fallback and receive functions. By default, Solidity smart contracts reject any Ether (ETH) sent to them. In order to enable your contract to accept ETH, we would implement `fallback` and `receive` functions. Let's look at these mose closely. +In the world of Solidity smart contracts, it's important to understand the fallback and receive functions. By default, Solidity smart contracts reject any Ether (ETH) sent to them. In order to enable your contract to accept ETH, we would implement `fallback` and `receive` functions. Let's look at these more closely. ## What are the Fallback and Receive functions? diff --git a/courses/security/2-audit/8-exercises/+page.md b/courses/security/2-audit/8-exercises/+page.md index 6f1ba811c..70ab435cc 100644 --- a/courses/security/2-audit/8-exercises/+page.md +++ b/courses/security/2-audit/8-exercises/+page.md @@ -6,7 +6,7 @@ _Follow along with this video:_ --- -### Section 2: Excercises +### Section 2: Exercises --- diff --git a/courses/security/3-first-audit/1-first-review/+page.md b/courses/security/3-first-audit/1-first-review/+page.md index 466974771..c90dbe3d3 100644 --- a/courses/security/3-first-audit/1-first-review/+page.md +++ b/courses/security/3-first-audit/1-first-review/+page.md @@ -14,7 +14,7 @@ This is an exciting journey to improve our understanding of audits. We'll streng For out first audit we're immersing ourselves into a scenario where we're auditing the PasswordStore protocol, just like you could if you were working for a firm like Cyfrin. It's a very immersive and experiential way of learning as we'll be adopting the role of a security researcher who has just received an audit request from a protocol. -In later lessons we'll also go through the process of submission findings in a competive scenario like `CodeHawks` +In later lessons we'll also go through the process of submission findings in a competitive scenario like `CodeHawks` ::image{src='/security-section-3/1-review/firstaudit1.png' style='width: 100%; height: auto;'} diff --git a/courses/security/3-first-audit/10-exploit-public-data/+page.md b/courses/security/3-first-audit/10-exploit-public-data/+page.md index 90d9f6ed6..a48b24cee 100644 --- a/courses/security/3-first-audit/10-exploit-public-data/+page.md +++ b/courses/security/3-first-audit/10-exploit-public-data/+page.md @@ -25,7 +25,7 @@ function getPassword() external view returns (string memory) { Starting, starting as always with the `NatSpec` documentation, we see a couple things to note: -- Only the owner should be able to retreive the password (_your `access control` bells should be ringing_) +- Only the owner should be able to retrieve the password (_your `access control` bells should be ringing_) - The function should take the parameter `newPassword`. We see a problem on the very next line. This function _doesn't take_ a parameter. Certainly informational, but let's make a note of it. diff --git a/courses/security/3-first-audit/12-protocol-tests/+page.md b/courses/security/3-first-audit/12-protocol-tests/+page.md index 2f275f917..d0818a317 100644 --- a/courses/security/3-first-audit/12-protocol-tests/+page.md +++ b/courses/security/3-first-audit/12-protocol-tests/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ::image{src='/security-section-3/12-protocol-tests/protocol-tests1.png' style='width: 100%; height: auto;'} -As security researchers our job is to ultimatly do what's necessary to make a protocol more secure. While we've thoroughly examined everything within scope of `PasswordStore` there can be some value in expanding our recon. +As security researchers our job is to ultimately do what's necessary to make a protocol more secure. While we've thoroughly examined everything within scope of `PasswordStore` there can be some value in expanding our recon. Test suites should be an expectation of any protocol serious about security, assuring adequate test coverage will be valuable in a `private audit`. diff --git a/courses/security/3-first-audit/14-an-amazing-title/+page.md b/courses/security/3-first-audit/14-an-amazing-title/+page.md index 0d592de59..7c7c5293e 100644 --- a/courses/security/3-first-audit/14-an-amazing-title/+page.md +++ b/courses/security/3-first-audit/14-an-amazing-title/+page.md @@ -30,7 +30,7 @@ The first thing we need to fill out is our report's title. We want to be concise So, we ask ourselves _what is the root cause of this finding, and what impact does it have?_ -For this finding the root cause would be something aking to: +For this finding the root cause would be something asking to: - **Storage variables on-chain are publicly visible** diff --git a/courses/security/3-first-audit/15-description/+page.md b/courses/security/3-first-audit/15-description/+page.md index 61521e192..e3bca739b 100644 --- a/courses/security/3-first-audit/15-description/+page.md +++ b/courses/security/3-first-audit/15-description/+page.md @@ -26,7 +26,7 @@ Alright, `title` done. What's next? Let's take a look at description and impact. ### Description -Our goal here is to describe the vulnerability consicely while clearly illustrating the problem. A description for our finding here might look like this. +Our goal here is to describe the vulnerability concisely while clearly illustrating the problem. A description for our finding here might look like this. --- @@ -61,7 +61,7 @@ This is the kind of clarity we should strive for in our reports! The impact is fairly self-evident, but to articulate it: ``` -**Impact:** Anyone is able to read the private password, severly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. ``` Putting things together, our report so far should look like this @@ -75,7 +75,7 @@ Putting things together, our report so far should look like this I show one such method of reading any data off chain below. -**Impact:** Anyone is able to read the private password, severly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. **Proof of Concept:** @@ -88,6 +88,6 @@ I show one such method of reading any data off chain below. In the next lesson, we're going to go over `Proof of Concept` sometimes called `Proof of Code`. This is a critical section of our report where we show, irrefutably, that the vulnerability exists and has considerable impact. -This is the section that prevents protocols from disregarding legitmate concerns. +This is the section that prevents protocols from disregarding legitimate concerns. Let's get to the code! diff --git a/courses/security/3-first-audit/16-proof-of-code/+page.md b/courses/security/3-first-audit/16-proof-of-code/+page.md index 5acd9c0e3..3764a2e40 100644 --- a/courses/security/3-first-audit/16-proof-of-code/+page.md +++ b/courses/security/3-first-audit/16-proof-of-code/+page.md @@ -16,7 +16,7 @@ _Follow along with this video:_ I show one such method of reading any data off chain below. -**Impact:** Anyone is able to read the private password, severly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. **Proof of Concept:** @@ -83,7 +83,7 @@ And we've done it. In a few quick commands we've shown that the data our client I show one such method of reading any data off chain below. :br :br -**Impact:** Anyone is able to read the private password, severaly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. :br :br **Proof of Concept:**The below test case shows how anyone could read the password directly from the blockchain. We use foundry's cast tool to read directly from the storage of the contract, without being the owner. diff --git a/courses/security/3-first-audit/17-recommended-mitigation/+page.md b/courses/security/3-first-audit/17-recommended-mitigation/+page.md index dc3003324..315de3e5a 100644 --- a/courses/security/3-first-audit/17-recommended-mitigation/+page.md +++ b/courses/security/3-first-audit/17-recommended-mitigation/+page.md @@ -19,7 +19,7 @@ _Follow along with this video:_ I show one such method of reading any data off chain below. -**Impact:** Anyone is able to read the private password, severaly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. **Proof of Concept:** The below test case shows how anyone could read the password directly from the blockchain. We use foundry's cast tool to read directly from the storage of the contract, without being the owner. @@ -84,7 +84,7 @@ Here's our report now: I show one such method of reading any data off chain below. :br :br -**Impact:** Anyone is able to read the private password, severaly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. :br :br **Proof of Concept:** The below test case shows how anyone could read the password directly from the blockchain. We use foundry's cast tool to read directly from the storage of the contract, without being the owner. diff --git a/courses/security/3-first-audit/18-finding-writeup/+page.md b/courses/security/3-first-audit/18-finding-writeup/+page.md index f750ef954..09b842caf 100644 --- a/courses/security/3-first-audit/18-finding-writeup/+page.md +++ b/courses/security/3-first-audit/18-finding-writeup/+page.md @@ -17,7 +17,7 @@ _Follow along with this video:_ I show one such method of reading any data off chain below. -**Impact:** Anyone is able to read the private password, severaly breaking the functionality of the protocol. +**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol. **Proof of Concept:** The below test case shows how anyone could read the password directly from the blockchain. We use foundry's cast tool to read directly from the storage of the contract, without being the owner. diff --git a/courses/security/3-first-audit/19-access-control-writeup/+page.md b/courses/security/3-first-audit/19-access-control-writeup/+page.md index 58c99a685..b7b1a78fe 100644 --- a/courses/security/3-first-audit/19-access-control-writeup/+page.md +++ b/courses/security/3-first-audit/19-access-control-writeup/+page.md @@ -72,7 +72,7 @@ function setPassword(string memory newPassword) external { The impact of our vulnerability should be pretty easy. Let's write it out now. ``` -**Impact:** Anyone can set/change the stored password, severly breaking the contract's intended functionality +**Impact:** Anyone can set/change the stored password, severely breaking the contract's intended functionality ``` Let's put things together in our report so far. @@ -92,7 +92,7 @@ function setPassword(string memory newPassword) external { } ''' -**Impact:** Anyone can set/change the stored password, severly breaking the contract's intended functionality +**Impact:** Anyone can set/change the stored password, severely breaking the contract's intended functionality **Proof of Concept:** diff --git a/courses/security/3-first-audit/20-missing-access-controls-proof-of-code/+page.md b/courses/security/3-first-audit/20-missing-access-controls-proof-of-code/+page.md index 7f566f024..08847819e 100644 --- a/courses/security/3-first-audit/20-missing-access-controls-proof-of-code/+page.md +++ b/courses/security/3-first-audit/20-missing-access-controls-proof-of-code/+page.md @@ -21,7 +21,7 @@ s_password = newPassword; emit SetNewPassword(); } -**Impact:** Anyone can set/change the stored password, severly breaking the contract's intended functionality +**Impact:** Anyone can set/change the stored password, severely breaking the contract's intended functionality **Proof of Concept:** @@ -77,7 +77,7 @@ function setPassword(string memory newPassword) external { } ''' -**Impact:** Anyone can set/change the stored password, severly breaking the contract's intended functionality +**Impact:** Anyone can set/change the stored password, severely breaking the contract's intended functionality **Proof of Concept:** Add the following to the PasswordStore.t.sol test file: @@ -131,6 +131,6 @@ if(msg.sender != s_owner){ ### Wrap Up -That's two findings down. Repetition is what will strengthen these skills and make writting these reports second nature. As we saw in this lesson, security reviewers even get to do a little coding 😋. +That's two findings down. Repetition is what will strengthen these skills and make writing these reports second nature. As we saw in this lesson, security reviewers even get to do a little coding 😋. Let's move on to our third finding, this one should be quick! diff --git a/courses/security/3-first-audit/22-augmented-report-with-ai/+page.md b/courses/security/3-first-audit/22-augmented-report-with-ai/+page.md index 9a1c28c42..2fd533429 100644 --- a/courses/security/3-first-audit/22-augmented-report-with-ai/+page.md +++ b/courses/security/3-first-audit/22-augmented-report-with-ai/+page.md @@ -19,7 +19,7 @@ The key to getting a decent response from an AI model (like ChatGPT), is to give In our care we want the AI to proof read our report and suggest grammar and formatting changes. It's best to give the AI a bit of context. ``` -The following is a markdown write-up of a findiing in a smart contract codebase, can you help me make sure it is grammatically correct and formatted nicely? +The following is a markdown write-up of a finding in a smart contract codebase, can you help me make sure it is grammatically correct and formatted nicely? --- PASTE-REPORT HERE diff --git a/courses/security/3-first-audit/24-severity-rating-introduction/+page.md b/courses/security/3-first-audit/24-severity-rating-introduction/+page.md index 100592537..c71d9608c 100644 --- a/courses/security/3-first-audit/24-severity-rating-introduction/+page.md +++ b/courses/security/3-first-audit/24-severity-rating-introduction/+page.md @@ -10,7 +10,7 @@ _Follow along with this video:_ For this lesson we'll be referencing the [**CodeHawks Documentation**](https://docs.codehawks.com/hawks-auditors/how-to-evaluate-a-finding-severity). There's a section specifically outlining `How to Evaluate a Finding Severity` and we'll be leveraging that methodology here. -We'll be breaking our severities into `High`, `Medium` and `Low`. Some security researchers will include a `Critical` severity, if they believe a situation warants one, but we'll stick with these 3 for now. +We'll be breaking our severities into `High`, `Medium` and `Low`. Some security researchers will include a `Critical` severity, if they believe a situation warrants one, but we'll stick with these 3 for now. ### Impact: High, Medium, and Low diff --git a/courses/security/3-first-audit/25-assesing-highs/+page.md b/courses/security/3-first-audit/25-assesing-highs/+page.md index 95f454108..525937c48 100644 --- a/courses/security/3-first-audit/25-assesing-highs/+page.md +++ b/courses/security/3-first-audit/25-assesing-highs/+page.md @@ -41,7 +41,7 @@ Alright! We're ready to start applying our understanding of `likelihood` and `im
-Let's consider impacts and likelhoods of our first scenario (I've provided you a reference to them above). +Let's consider impacts and likelihoods of our first scenario (I've provided you a reference to them above). Upon consideration we see that, while funds aren't at risk, the user's 'hidden' password being visible to anyone is a pretty severe impact to how the protocol is expected to function. @@ -92,7 +92,7 @@ Considering our second finding, we can tell that anyone being able to set the pa The `likelihood` is also going to be `High`. Anyone can do this, at any time, the vulnerability is rooted in `access control`. -### Likehood & Impact: +### Likelihood & Impact: - Impact: High - Likelihood: High diff --git a/courses/security/3-first-audit/26-severity-rating-informational/+page.md b/courses/security/3-first-audit/26-severity-rating-informational/+page.md index c3691f344..ebf6c9ca4 100644 --- a/courses/security/3-first-audit/26-severity-rating-informational/+page.md +++ b/courses/security/3-first-audit/26-severity-rating-informational/+page.md @@ -1,5 +1,5 @@ --- -title: Severity Rating Assesing Informational/Gas/Non-Crit +title: Severity Rating Assessing Informational/Gas/Non-Crit --- _Follow along with this video:_ diff --git a/courses/security/3-first-audit/31-recap-and-congrats/+page.md b/courses/security/3-first-audit/31-recap-and-congrats/+page.md index d25179d2e..4720008d9 100644 --- a/courses/security/3-first-audit/31-recap-and-congrats/+page.md +++ b/courses/security/3-first-audit/31-recap-and-congrats/+page.md @@ -54,7 +54,7 @@ We covered the phases of an audit and each steps within. ### The Tincho -The legendary Tincho from [**The Red Guild**](https://blog.theredguild.org/) blessed us with his wisdom and experience, outlining the approach he takes while peforming a security review. He stresses: +The legendary Tincho from [**The Red Guild**](https://blog.theredguild.org/) blessed us with his wisdom and experience, outlining the approach he takes while performing a security review. He stresses: - Read the docs - Take notes often - right in the codebase diff --git a/courses/security/3-first-audit/7-context/+page.md b/courses/security/3-first-audit/7-context/+page.md index 025a3beec..cd6194ca3 100644 --- a/courses/security/3-first-audit/7-context/+page.md +++ b/courses/security/3-first-audit/7-context/+page.md @@ -55,7 +55,7 @@ Applying Tincho's methodology to this process, we can: > Please note that if your codebase contains a solitary file like ours, this step won't be necessary. -Some aspects I'll draw your attention to in this metrics report are the `Inhertance Graph`, `The Call Graph`, and `The Contracts Summary`. It's not super obvious with such a simple protocol, but these are going to provide valuable insight down the line. Familiarize yourself with them now (way at the bottom). +Some aspects I'll draw your attention to in this metrics report are the `Inheritance Graph`, `The Call Graph`, and `The Contracts Summary`. It's not super obvious with such a simple protocol, but these are going to provide valuable insight down the line. Familiarize yourself with them now (way at the bottom). ::image{src='/security-section-3/7-context/context6.png' style='width: 100%; height: auto;'} diff --git a/courses/security/3-first-audit/8-understanding-the-code/+page.md b/courses/security/3-first-audit/8-understanding-the-code/+page.md index 59477752e..e2f032807 100644 --- a/courses/security/3-first-audit/8-understanding-the-code/+page.md +++ b/courses/security/3-first-audit/8-understanding-the-code/+page.md @@ -14,7 +14,7 @@ So let's take it from the top, just like Tincho did… ### Understanding What the Codebase Is Supposed to Do -Our client's documentation has let us know what the intended functionality of the protocol are. Namely: A user should be able to store and retreive their password, no one else should be able to see it. +Our client's documentation has let us know what the intended functionality of the protocol are. Namely: A user should be able to store and retrieve their password, no one else should be able to see it. Let's try to find this functionality within the code as we go through things line by line. diff --git a/courses/security/4-puppy-raffle/1-introduction/+page.md b/courses/security/4-puppy-raffle/1-introduction/+page.md index c1599a667..72dd134e9 100644 --- a/courses/security/4-puppy-raffle/1-introduction/+page.md +++ b/courses/security/4-puppy-raffle/1-introduction/+page.md @@ -16,7 +16,7 @@ We'll see the differences between a private audit report and a competitive audit CodeHawks First Flights offer an excellent platform for budding smart contract security researchers. This platform contains relatively easy-to-understand codebases that resemble those you will find in this course. -If you are a beginner, they are a perfect opportunity to get live auditing experience and build upon the things you've learnt in a practical setting. For experienced auditors, they serve as a chance to engage in the community and itterate on your established skills. +If you are a beginner, they are a perfect opportunity to get live auditing experience and build upon the things you've learnt in a practical setting. For experienced auditors, they serve as a chance to engage in the community and iterate on your established skills. ::image{src='/security-section-4/1-introduction/introduction1.png' style='width: 100%; height: auto;'} @@ -48,13 +48,13 @@ This should give you real insight into what's at stake as we're performing secur ### Exercises -At the end of the section we'll have _even more_ excercises for you to expand on your knowledge and challenge yourself beyond the course's teachings. These are your opportunities to branch out, network and gain additional experience. +At the end of the section we'll have _even more_ exercises for you to expand on your knowledge and challenge yourself beyond the course's teachings. These are your opportunities to branch out, network and gain additional experience. This includes participating in a CodeHawks First Flight or a competitive audit! Get ready! ### Prep for Puppy Raffle -If you take a look at the [**repo**](https://github.com/Cyfrin/4-puppy-raffle-audit) associated with this section, you'll see a fairly robust README already supplied. For this review, we're assuming the protocol has already undergone some degreee of onboarding and they've provided us a respectable repo. +If you take a look at the [**repo**](https://github.com/Cyfrin/4-puppy-raffle-audit) associated with this section, you'll see a fairly robust README already supplied. For this review, we're assuming the protocol has already undergone some degree of onboarding and they've provided us a respectable repo. I will transparently point out that, much like our previous protocol review, this repo has multiple branches, one of which is the `audit-data` branch. I **STRONGLY** encourage you to resist peeking in this branch until the end. The `audit-data` branch effectively serves as an `answer key`, in which all the vulnerabilities and write-ups can be found. diff --git a/courses/security/4-puppy-raffle/10-sc-exploits-minimized/+page.md b/courses/security/4-puppy-raffle/10-sc-exploits-minimized/+page.md index 68a649095..1e6a14898 100644 --- a/courses/security/4-puppy-raffle/10-sc-exploits-minimized/+page.md +++ b/courses/security/4-puppy-raffle/10-sc-exploits-minimized/+page.md @@ -23,6 +23,6 @@ In order to get a better understanding of this bug, let's look at a _minimized_ ::image{src='/security-section-4/10-sc-exploits-minimized/sc-exploits-minimized1.png' style='width: 75%; height: auto;'} -This is an amazing resource to test your skills in general and familiarize yourself with common exploits. Addionally the `src` folder of `sc-exploits-minimized` contains minimalistic examples of a variety of vulnerabilities as well. +This is an amazing resource to test your skills in general and familiarize yourself with common exploits. Additionally the `src` folder of `sc-exploits-minimized` contains minimalistic examples of a variety of vulnerabilities as well. For now, let's check out the [**Remix example**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/denial-of-service/DoS.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js) of the Denial of Service exploit in the next lesson. diff --git a/courses/security/4-puppy-raffle/12-dos-case-study/+page.md b/courses/security/4-puppy-raffle/12-dos-case-study/+page.md index b6b364641..ab8c98df4 100644 --- a/courses/security/4-puppy-raffle/12-dos-case-study/+page.md +++ b/courses/security/4-puppy-raffle/12-dos-case-study/+page.md @@ -34,7 +34,7 @@ function distributeDividends(uint amount) public payable lock { for (uint i; i < length; i++){ if(users[i] != address(0)){ UserInfo storage user = userInfo[users[i]]; - user.rewards += (amount.mul(IERC20(address(thiss).balanceOf(users[i])).div(totalSupply.sub(MINIMUM_LIQUIDITY)))); + user.rewards += (amount.mul(IERC20(address(this).balanceOf(users[i])).div(totalSupply.sub(MINIMUM_LIQUIDITY)))); } } } @@ -46,7 +46,7 @@ The practical effect of this is that, were the length of the `users[]` array lon ### Confirming the Attack Vector -In order to verify this is a vulnerability. We should invesitgate under what circumstances the `user[]` array can be added to. +In order to verify this is a vulnerability. We should investigate under what circumstances the `user[]` array can be added to. By searching for the variable we see the array is appended to in the mint function: @@ -111,7 +111,7 @@ To summarize, here are a couple things to keep an eye out for which may lead to - Is the iterable entity bounded by size? - Can a user append arbitrary items to the list? - How much does it cost the user to do so? -2. **External calls**: These can be anything from transfering Eth to calling a third-party contract. Evaluate ways these external calls could fail, leading to an incomplete transaction. +2. **External calls**: These can be anything from transferring Eth to calling a third-party contract. Evaluate ways these external calls could fail, leading to an incomplete transaction. DoS attacks put simply are - the denial of functions of a protocol. They can arise from multiple sources, but the end result is always a transaction failing to execute. diff --git a/courses/security/4-puppy-raffle/13-dos-poc/+page.md b/courses/security/4-puppy-raffle/13-dos-poc/+page.md index ff363203c..974283604 100644 --- a/courses/security/4-puppy-raffle/13-dos-poc/+page.md +++ b/courses/security/4-puppy-raffle/13-dos-poc/+page.md @@ -101,7 +101,7 @@ Running the command `forge test --mt testDenialOfService -vvv` should give us an Now let's do the same thing for the second 100 players! We'll need to add something like this to our test. ```js -// Creats another array of 100 players +// Creates another array of 100 players address[] memory playersTwo = new address[](playersNum); for (uint256 i = 0; i < playersTwo.length; i++) { playersTwo[i] = address(i + playersNum); diff --git a/courses/security/4-puppy-raffle/14-dos-reporting/+page.md b/courses/security/4-puppy-raffle/14-dos-reporting/+page.md index a40cb2ca6..6228983c8 100644 --- a/courses/security/4-puppy-raffle/14-dos-reporting/+page.md +++ b/courses/security/4-puppy-raffle/14-dos-reporting/+page.md @@ -10,7 +10,7 @@ _Follow along with this video:_ Maybe you're the type of security reviewer who likes to save all the write ups to the end. There's nothing wrong with that! As you grow and gain experience you'll begin to carve out your own workflow and ways of doing things. -In future lessons, we may not go through writing things up together, but for now - let's report this uncovered DoS vulnverability +In future lessons, we may not go through writing things up together, but for now - let's report this uncovered DoS vulnerability We of course start with our template, create a `findings.md` file and paste this within: @@ -102,7 +102,7 @@ If we have 2 sets of 100 players enter, the gas costs will be as such: - 1st 100 players: ~6252048 gas - 2nd 100 players: ~18068138 gas -This is more than 3x more expensivee for the second 100 players. +This is more than 3x more expensive for the second 100 players.
Proof of Code @@ -126,7 +126,7 @@ function testDenialOfService() public { uint256 gasUsedFirst = (gasStart - gasEnd) * tx.gasprice; console.log("Gas cost of the first 100 players: ", gasUsedFirst); - // Creats another array of 100 players + // Creates another array of 100 players address[] memory playersTwo = new address[](playersNum); for (uint256 i = 0; i < playersTwo.length; i++) { playersTwo[i] = address(i + playersNum); @@ -177,7 +177,7 @@ If we have 2 sets of 100 players enter, the gas costs will be as such: - 1st 100 players: ~6252048 gas - 2nd 100 players: ~18068138 gas -This is more than 3x more expensivee for the second 100 players. +This is more than 3x more expensive for the second 100 players.
Proof of Code @@ -201,7 +201,7 @@ function testDenialOfService() public { uint256 gasUsedFirst = (gasStart - gasEnd) * tx.gasprice; console.log("Gas cost of the first 100 players: ", gasUsedFirst); - // Creats another array of 100 players + // Creates another array of 100 players address[] memory playersTwo = new address[](playersNum); for (uint256 i = 0; i < playersTwo.length; i++) { playersTwo[i] = address(i + playersNum); diff --git a/courses/security/4-puppy-raffle/15-dos-mitigation/+page.md b/courses/security/4-puppy-raffle/15-dos-mitigation/+page.md index 2b203f56f..34d6352f6 100644 --- a/courses/security/4-puppy-raffle/15-dos-mitigation/+page.md +++ b/courses/security/4-puppy-raffle/15-dos-mitigation/+page.md @@ -84,7 +84,7 @@ If we have 2 sets of 100 players enter, the gas costs will be as such: - 1st 100 players: ~6252048 gas - 2nd 100 players: ~18068138 gas -This is more than 3x more expensivee for the second 100 players. +This is more than 3x more expensive for the second 100 players.
Proof of Code @@ -108,7 +108,7 @@ function testDenialOfService() public { uint256 gasUsedFirst = (gasStart - gasEnd) * tx.gasprice; console.log("Gas cost of the first 100 players: ", gasUsedFirst); - // Creats another array of 100 players + // Creates another array of 100 players address[] memory playersTwo = new address[](playersNum); for (uint256 i = 0; i < playersTwo.length; i++) { playersTwo[i] = address(i + playersNum); diff --git a/courses/security/4-puppy-raffle/16-exploit-business-logic-edge-case/+page.md b/courses/security/4-puppy-raffle/16-exploit-business-logic-edge-case/+page.md index 116ef1415..1777c72ed 100644 --- a/courses/security/4-puppy-raffle/16-exploit-business-logic-edge-case/+page.md +++ b/courses/security/4-puppy-raffle/16-exploit-business-logic-edge-case/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Business Logic Edge Case -By now we've identified fairly clearly how the `enterRaffle` function works. Our finding looks great. Let's next move onto the `refund` function, this one was mentioned explicitly in our documention. +By now we've identified fairly clearly how the `enterRaffle` function works. Our finding looks great. Let's next move onto the `refund` function, this one was mentioned explicitly in our documentation. ``` Users are allowed to get a refund of their ticket & value if they call the refund function diff --git a/courses/security/4-puppy-raffle/17-recon-refund/+page.md b/courses/security/4-puppy-raffle/17-recon-refund/+page.md index 5b117b1b8..09fcbd35a 100644 --- a/courses/security/4-puppy-raffle/17-recon-refund/+page.md +++ b/courses/security/4-puppy-raffle/17-recon-refund/+page.md @@ -45,7 +45,7 @@ Before this however, we see the `sendValue` function being called. This is what --- -`sendValue` may look unusual, this is just a simplfied method to transfer funds contained within the [**OpenZeppelin Address.sol library**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol). +`sendValue` may look unusual, this is just a simplified method to transfer funds contained within the [**OpenZeppelin Address.sol library**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol). > ```js > function sendValue(address payable recipient, >uint256 amount) internal { diff --git a/courses/security/4-puppy-raffle/18-exploit-reentrancy/+page.md b/courses/security/4-puppy-raffle/18-exploit-reentrancy/+page.md index f1e342b60..8acd67cd8 100644 --- a/courses/security/4-puppy-raffle/18-exploit-reentrancy/+page.md +++ b/courses/security/4-puppy-raffle/18-exploit-reentrancy/+page.md @@ -65,7 +65,7 @@ And then withdraw them :brcontract balance = 0 ether :brUser A balance = 10 ether -The order of operations is reeally important in these situations. In our `withdrawBalance` function, we see that the function is making an external call _before_ updating the state of the contract. +The order of operations is really important in these situations. In our `withdrawBalance` function, we see that the function is making an external call _before_ updating the state of the contract. What this means, is that an attacker could have that external call be made in such a way that it triggers a call of the `withdrawBalance` function again (hence - reentrancy). @@ -101,7 +101,7 @@ function attack() public payable { } ``` -2. The `ReentrancyVictim` contract does what's it's supposed to and received the deposit, then processs the withdrawal. During this process the victim contract makes a call to the attacker's contract. +2. The `ReentrancyVictim` contract does what's it's supposed to and received the deposit, then process the withdrawal. During this process the victim contract makes a call to the attacker's contract. **NOTE: THIS IS BEFORE OUR BALANCE HAS BEEN UPDATED** diff --git a/courses/security/4-puppy-raffle/19-reentrancy-remix-example/+page.md b/courses/security/4-puppy-raffle/19-reentrancy-remix-example/+page.md index a038ed0a6..6feefc096 100644 --- a/courses/security/4-puppy-raffle/19-reentrancy-remix-example/+page.md +++ b/courses/security/4-puppy-raffle/19-reentrancy-remix-example/+page.md @@ -44,7 +44,7 @@ function withdrawBalance() public { That's it! -The first time this function is called now, the user's balance is updated to zero before making external calls. This means if an enternal call causes this function to be called again - the user's balance will already be updated as zero, so no further funds will be withdrawn. +The first time this function is called now, the user's balance is updated to zero before making external calls. This means if an external call causes this function to be called again - the user's balance will already be updated as zero, so no further funds will be withdrawn. Let's see this in action, in [**Remix**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/reentrancy/Reentrancy.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js). diff --git a/courses/security/4-puppy-raffle/21-reentrancy-menace-to-society/+page.md b/courses/security/4-puppy-raffle/21-reentrancy-menace-to-society/+page.md index 98c498a52..77b327ba6 100644 --- a/courses/security/4-puppy-raffle/21-reentrancy-menace-to-society/+page.md +++ b/courses/security/4-puppy-raffle/21-reentrancy-menace-to-society/+page.md @@ -16,7 +16,7 @@ Why am I stressing re-entrancy so much you might ask? The answer is simple. This is so frustrating! -There's a [**GitHub Repo**](https://github.com/pcaversaccio/reentrancy-attacks) maintained by Pascal (legend) that catalogues re-entrancy attacks which have occured. I encourage you to look through these examples and really acquire a sense of the scope of the problem. +There's a [**GitHub Repo**](https://github.com/pcaversaccio/reentrancy-attacks) maintained by Pascal (legend) that catalogues re-entrancy attacks which have occurred. I encourage you to look through these examples and really acquire a sense of the scope of the problem. ### Case Study: The DAO diff --git a/courses/security/4-puppy-raffle/22-reentrancy-recap/+page.md b/courses/security/4-puppy-raffle/22-reentrancy-recap/+page.md index 6ad65f503..7da92286b 100644 --- a/courses/security/4-puppy-raffle/22-reentrancy-recap/+page.md +++ b/courses/security/4-puppy-raffle/22-reentrancy-recap/+page.md @@ -18,7 +18,7 @@ As a more indepth reference: ::image{src='/security-section-4/18-exploit-reentrancy/exploit-reentrancy2.png' style='width: 75%; height: auto;'} -We learnt that re-entrancy is a _very_ common attack vector and walked through how to indentify and reproduce the vulnerability both in [**Remix**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/reentrancy/Reentrancy.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js) and locally as well as how to test for them. +We learnt that re-entrancy is a _very_ common attack vector and walked through how to identify and reproduce the vulnerability both in [**Remix**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/reentrancy/Reentrancy.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js) and locally as well as how to test for them.
Re-entrancy Test Example @@ -82,7 +82,7 @@ Additionally, we learnt that `static analysis` tools like `Slither` can even cat We also covered how to safeguard against this attack in at least two ways. - Adhering to the CEI (Checks, Effects, Interactions) pattern, assuring we perform state changes _before_ making external calls. -- Implenting a nonReentrant modifier like one offered by [**OpenZeppellin's ReentrancyGuard**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol). +- Implementing a nonReentrant modifier like one offered by [**OpenZeppelin's ReentrancyGuard**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol). - Applying a mutex lock to our function ourselves.
Mutex Lock Example diff --git a/courses/security/4-puppy-raffle/23-reentrancy-poc/+page.md b/courses/security/4-puppy-raffle/23-reentrancy-poc/+page.md index 0d348f04d..2f4e5aeec 100644 --- a/courses/security/4-puppy-raffle/23-reentrancy-poc/+page.md +++ b/courses/security/4-puppy-raffle/23-reentrancy-poc/+page.md @@ -138,7 +138,7 @@ address attacker = makeAddr("attacker"); vm.deal(attacker, 1 ether); ``` -Next, we'll grab some balances so we're ablee to log our changes after the attack. +Next, we'll grab some balances so we're able to log our changes after the attack. ```js uint256 startingAttackContractBalance = address(attackerContract).balance; diff --git a/courses/security/4-puppy-raffle/24-recon-continued/+page.md b/courses/security/4-puppy-raffle/24-recon-continued/+page.md index aea7a9a2c..bbbe81c66 100644 --- a/courses/security/4-puppy-raffle/24-recon-continued/+page.md +++ b/courses/security/4-puppy-raffle/24-recon-continued/+page.md @@ -75,7 +75,7 @@ require(block.timestamp >= raffleStartTime + raffleDuration, "PuppyRaffle: Raffle not over"); ``` -I encourage you to write these thoughts down in your `notes.md` file and actually write in-line notes to keep them organized. Being able to reference these thoughts during our write ups and later in the review is incredibly valuable to the proceess. +I encourage you to write these thoughts down in your `notes.md` file and actually write in-line notes to keep them organized. Being able to reference these thoughts during our write ups and later in the review is incredibly valuable to the process. ```js // @Audit: Does this follow CEI? @@ -106,7 +106,7 @@ It's important that this selection is fair and truly random or this could be exp ### Wrap Up -Having gone through the `selectWinner` function, we now have a better understanding of this process and how it's controlleed. +Having gone through the `selectWinner` function, we now have a better understanding of this process and how it's controlled. The function can't be called until the `raffleDuration` has passed and there are at least 4 people entered. Once `selectWinner` is called and passes checks, it uses a pseudo-random method to determine a winner of the raffle and then transfers the `prizePool` and mints them an NFT. diff --git a/courses/security/4-puppy-raffle/27-weak-randomness-case-study/+page.md b/courses/security/4-puppy-raffle/27-weak-randomness-case-study/+page.md index 49ae72fa7..9cbd6269d 100644 --- a/courses/security/4-puppy-raffle/27-weak-randomness-case-study/+page.md +++ b/courses/security/4-puppy-raffle/27-weak-randomness-case-study/+page.md @@ -24,13 +24,13 @@ The concept behind Meebits was simple. If you owned a CryptoPunk, you could mint ### How the Attack Happened -There were 4 distinct things that occured. +There were 4 distinct things that occurred. **Metadata Disclosure:** The Meebit contract contained an IPFS hash which pointed to metadata for the collection. Within the Metadata there existed a string of text that clearly disclosed which traits would be the most rare "...While just five of the 20,000 Meebits are of the dissected form, which is the rarest. The kinds include dissected, visitor, skeleton, robot, elephant, pig and human, listed in decreasing order of rarity." -In addition to this, the `tokenURI` function allowed public access to the traits of your minted Meetbit, by passing the function your tokenId. +In addition to this, the `tokenURI` function allowed public access to the traits of your minted Meebit, by passing the function your tokenId. **Insecure Randomness:** Meebits calculated a random index based on this line of code: @@ -99,6 +99,6 @@ The attacking contract called this mint function and reverted for over 6 hours. ### Wrap Up -There you have it. That's how an attacker in 2021 was able to exploit weak randomness in the Meetbits contract. +There you have it. That's how an attacker in 2021 was able to exploit weak randomness in the Meebits contract. Thanks again to Andy! In the next lesson we'll be going over how to prevent this madness! diff --git a/courses/security/4-puppy-raffle/29-exploit-integer-overflow/+page.md b/courses/security/4-puppy-raffle/29-exploit-integer-overflow/+page.md index c0c6dff3e..1e9222f57 100644 --- a/courses/security/4-puppy-raffle/29-exploit-integer-overflow/+page.md +++ b/courses/security/4-puppy-raffle/29-exploit-integer-overflow/+page.md @@ -17,9 +17,9 @@ function selectWinner() external { uint256 winnerIndex = uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, block.difficulty))) % players.length; address winner = players[winnerIndex]; - // @Audit: Why the calculationi for totalAmountCollected, why not address(this).balance? + // @Audit: Why the calculation for totalAmountCollected, why not address(this).balance? uint256 totalAmountCollected = players.length * entranceFee; - // @Audit:80% prizePool, 20% fee. Is this correct? Arithmatic may lead to precision loss + // @Audit:80% prizePool, 20% fee. Is this correct? Arithmetic may lead to precision loss uint256 prizePool = (totalAmountCollected * 80) / 100; uint256 fee = (totalAmountCollected * 20) / 100; // @Audit: Total fees the owner should be able to collect. Why the casting? Overflow. diff --git a/courses/security/4-puppy-raffle/31-unsafe-casting/+page.md b/courses/security/4-puppy-raffle/31-unsafe-casting/+page.md index c796a1d4d..6217079e1 100644 --- a/courses/security/4-puppy-raffle/31-unsafe-casting/+page.md +++ b/courses/security/4-puppy-raffle/31-unsafe-casting/+page.md @@ -35,4 +35,4 @@ Our value has wrapped on us again! // uint64(twenthEth) = 1553255926290448384 ``` -This is absolutely something we're caalling out in our audit report. Puppy Raffle is at risk of losing so many fees! +This is absolutely something we're calling out in our audit report. Puppy Raffle is at risk of losing so many fees! diff --git a/courses/security/4-puppy-raffle/32-recon-continued-2/+page.md b/courses/security/4-puppy-raffle/32-recon-continued-2/+page.md index 41539664f..aa45f1c3d 100644 --- a/courses/security/4-puppy-raffle/32-recon-continued-2/+page.md +++ b/courses/security/4-puppy-raffle/32-recon-continued-2/+page.md @@ -133,7 +133,7 @@ So, let's break this function down to see what it's doing. First we see a require statement and already a couple questions come to mind _Hint: there are issues with this line_ ```js -// @Audit: If there are players, fees can't be withdrawn, does this make withdrawl difficult? +// @Audit: If there are players, fees can't be withdrawn, does this make withdrawal difficult? require(address(this).balance == uint256(totalFees), "PuppyRaffle: There are currently players active!"); ``` diff --git a/courses/security/4-puppy-raffle/34-mishandling-of-eth-minimized/+page.md b/courses/security/4-puppy-raffle/34-mishandling-of-eth-minimized/+page.md index 824bcf280..7ee12f9cf 100644 --- a/courses/security/4-puppy-raffle/34-mishandling-of-eth-minimized/+page.md +++ b/courses/security/4-puppy-raffle/34-mishandling-of-eth-minimized/+page.md @@ -97,7 +97,7 @@ Lastly, try calling the `withdraw` function on `SelfDestructMe.sol`. It reverts! ### Wrap Up -We've illustrated how relying on a contract's balance as a means of internal counting can be risky. There's really no way to be certain that arbitrary value isn't sent to a contract currenty. +We've illustrated how relying on a contract's balance as a means of internal counting can be risky. There's really no way to be certain that arbitrary value isn't sent to a contract currently. As I'd mentioned previously, the concept of `Mishandling Eth` is a broad one. Our sc-exploits-minimized repo outlines another common scenario (push over pull) that I encourage you to look at, as we won't go over it here. diff --git a/courses/security/4-puppy-raffle/35-mishandling-of-eth-case-study/+page.md b/courses/security/4-puppy-raffle/35-mishandling-of-eth-case-study/+page.md index bbdcdb0b7..3f17f7ab6 100644 --- a/courses/security/4-puppy-raffle/35-mishandling-of-eth-case-study/+page.md +++ b/courses/security/4-puppy-raffle/35-mishandling-of-eth-case-study/+page.md @@ -29,7 +29,7 @@ function batch(bytes[] calldata calls, bool revertOnFail) external payable retur In the simplest terms, this function allows a user to compile multiple calls into a single transaction - sounds useful. -The oversight was in the use of `delegatecall`. When implementing delegatecall, msg.sender _and_ msg.value are persistant. This meant that a single value sent for one call in this function could be used for multiple calls! +The oversight was in the use of `delegatecall`. When implementing delegatecall, msg.sender _and_ msg.value are persistent. This meant that a single value sent for one call in this function could be used for multiple calls! > **For example:** If I were to call a function which cost 1 Eth, to call it 100 times, it should cost 100 Eth. In the case of the `batch` function, a user would be able to call the function 100 times, for only 1 Eth! diff --git a/courses/security/4-puppy-raffle/38-info-and-gas-findings/+page.md b/courses/security/4-puppy-raffle/38-info-and-gas-findings/+page.md index f6332adf5..afac569b3 100644 --- a/courses/security/4-puppy-raffle/38-info-and-gas-findings/+page.md +++ b/courses/security/4-puppy-raffle/38-info-and-gas-findings/+page.md @@ -58,7 +58,7 @@ A good practice will be to investigate the specific versions being used for repo We can navigate to the OpenZeppelin security section [**here**](https://github.com/OpenZeppelin/openzeppelin-contracts/security). -This section of the OpenZepplin repo is kept updated with known security vulnerabilities within various versions of the OpenZeppelin library. +This section of the OpenZeppelin repo is kept updated with known security vulnerabilities within various versions of the OpenZeppelin library. By clicking on one of the advisories, we get a detailed breakdown including the affected versions. diff --git a/courses/security/4-puppy-raffle/4-tooling-slither/+page.md b/courses/security/4-puppy-raffle/4-tooling-slither/+page.md index 2a355a51f..6e044296c 100644 --- a/courses/security/4-puppy-raffle/4-tooling-slither/+page.md +++ b/courses/security/4-puppy-raffle/4-tooling-slither/+page.md @@ -66,7 +66,7 @@ The output color codes potential issues: - **Green** - Areas that are probably ok, may be `informational` findings, we may want to have a look - **Yellow** - Potential issue detected, we should probably take a closer look -- **Red** - Signifant issues detected that should absolutely be addressed. +- **Red** - Significant issues detected that should absolutely be addressed. Here's an example of what some of these look like: diff --git a/courses/security/4-puppy-raffle/40-slither-walkthrough/+page.md b/courses/security/4-puppy-raffle/40-slither-walkthrough/+page.md index e9f8a918f..84e0b755b 100644 --- a/courses/security/4-puppy-raffle/40-slither-walkthrough/+page.md +++ b/courses/security/4-puppy-raffle/40-slither-walkthrough/+page.md @@ -40,9 +40,9 @@ function withdrawFees() external { } ``` -So, `Slither` is telling us that our feeAddress is arbirary and may be malicious. Let's look at the attack vector in the [**`Slither` documentation**](https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations). +So, `Slither` is telling us that our feeAddress is arbitrary and may be malicious. Let's look at the attack vector in the [**`Slither` documentation**](https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations). -The documentation outlines that since our `feeAddress` can be changed, whomever receives funds from `withdrawFees` could theoretically be anybody. However, in `PuppyRaffle`, the `feeAddress` can only be changed by the `owner`, so this would be considereed intention in our protocol. +The documentation outlines that since our `feeAddress` can be changed, whomever receives funds from `withdrawFees` could theoretically be anybody. However, in `PuppyRaffle`, the `feeAddress` can only be changed by the `owner`, so this would be considered intention in our protocol. ```js function changeFeeAddress(address newFeeAddress) external onlyOwner { @@ -189,7 +189,7 @@ We can have our `Slither` report remove these warnings once we've made note of t Now, you may be asking yourself _These are reentrancy, why aren't they high!?_. -Well, these warnings are specifically pointing to the vulnerability described by the manipulation of the order or value of events being emitted. By reentering these functions an attacker is able to manupulate the events being emitted and potentially compromise third party reliance on them. +Well, these warnings are specifically pointing to the vulnerability described by the manipulation of the order or value of events being emitted. By reentering these functions an attacker is able to manipulate the events being emitted and potentially compromise third party reliance on them. There's a lot of debate about what kind of severity should be ascribed to event based findings, but my personal rule of thumb is that they are _at least_ `Low Severity`. Examples include: @@ -350,7 +350,7 @@ These are simply pointing out naming convention concerns in a couple of our libr - Dangerous Calls: - `"this (lib/openzeppelin-contracts/contracts/utils/Context.sol#21)" inContext (lib/openzeppelin-contracts/contracts/utils/Context.sol#15-24)` -Another warning from a depedency of ours, we'll ignore this, but if you want to remove it you can add the line: +Another warning from a dependency of ours, we'll ignore this, but if you want to remove it you can add the line: ```js // slither-disable-next-line redundant-statements diff --git a/courses/security/4-puppy-raffle/46-submitting-a-competitive-audit-finding/+page.md b/courses/security/4-puppy-raffle/46-submitting-a-competitive-audit-finding/+page.md index 87c8e808b..a13f31341 100644 --- a/courses/security/4-puppy-raffle/46-submitting-a-competitive-audit-finding/+page.md +++ b/courses/security/4-puppy-raffle/46-submitting-a-competitive-audit-finding/+page.md @@ -21,7 +21,7 @@ Some of this should seem very familiar. We can enter a title and choose an appro - The title of a competitive audit submission can omit the [S-#] categorization. This will ultimately be prepended by judges if the report is deemed valid. - Remember: a good title is comprised of Root Cause + Impact! -For `Relevant GitHub Links`, we're meant to provide a link, not just to the code base/contract, but to the specific lines we've identified as problematic. Using our DoS Vulnerability from `PuppyRaffle.sol` as an example, we can link directly to the loop in our `enterRaffle` function by right-clicking the line in GitHub and chooosing `copy permalink`. +For `Relevant GitHub Links`, we're meant to provide a link, not just to the code base/contract, but to the specific lines we've identified as problematic. Using our DoS Vulnerability from `PuppyRaffle.sol` as an example, we can link directly to the loop in our `enterRaffle` function by right-clicking the line in GitHub and choosing `copy permalink`. ::image{src='/security-section-4/46-submitting-competitive-finding/submitting-competitive-finding2.png' style='width: 75%; height: auto;'} @@ -49,7 +49,7 @@ Something to always strive for is quality in the write ups you submit. In compet ### Wrap Up -Once a First Flight or Competitive Audit concludes, you'll be able to navitgate to `My Findings` in CodeHawks and download your submissions in markdown. It's worthwhile to add these to your portfolio to show your skills and experience to the world! +Once a First Flight or Competitive Audit concludes, you'll be able to navigate to `My Findings` in CodeHawks and download your submissions in markdown. It's worthwhile to add these to your portfolio to show your skills and experience to the world! That's all there is to submitting to a competitive audit! From there a judge will take over. Be sure to sign up to CodeHawks, I promise you that participating in competitive audits and First Flights will supercharge your abilities as a security researcher. diff --git a/courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md b/courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md index fc19101c7..61c589ad9 100644 --- a/courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md +++ b/courses/security/4-puppy-raffle/5-tooling-aderyn/+page.md @@ -262,6 +262,6 @@ _**WOW!**_ We have a report of vulnerabilities already gorgeously formatted and ### Wrap Up -Fast, and efficient, [**Aderyn**](https://github.com/Cyfrin/aderyn) offers a swift vulnerability report of your smart contracts which is almost ready to be presented. Aesthetically neat and structurally organized, the tool is a quick starter for anyone performing security reviews. We'll be leveraging the poweer of Aderyn throughout the course!. +Fast, and efficient, [**Aderyn**](https://github.com/Cyfrin/aderyn) offers a swift vulnerability report of your smart contracts which is almost ready to be presented. Aesthetically neat and structurally organized, the tool is a quick starter for anyone performing security reviews. We'll be leveraging the power of Aderyn throughout the course!. Let's look at one more tool briefly in the next lesson. diff --git a/courses/security/4-puppy-raffle/51-reporting-zero-address-check/+page.md b/courses/security/4-puppy-raffle/51-reporting-zero-address-check/+page.md index bee1d3a9c..cabfa25a2 100644 --- a/courses/security/4-puppy-raffle/51-reporting-zero-address-check/+page.md +++ b/courses/security/4-puppy-raffle/51-reporting-zero-address-check/+page.md @@ -11,7 +11,7 @@ _Follow along with this video:_ We're flying through these! Next note that comes up when we search our `@Audit` tag is ... ```js -constructor(uint256 _entranceFee, address _feeAddress, uint256 _raffleDuration) EERC721 ("Puppy Raffle, "PR""){ +constructor(uint256 _entranceFee, address _feeAddress, uint256 _raffleDuration) ERC721 ("Puppy Raffle, "PR""){ // @Audit: check for zero address! ... } @@ -46,7 +46,7 @@ Assigning values to address state variables without checking for `address(0)`. Leveraging our tools is a great way to speed up the write up process. Thanks, `Aderyn`! Mark the note as complete and we'll move on to the next finding! ```js -constructor(uint256 _entranceFee, address _feeAddress, uint256 _raffleDuration) EERC721 ("Puppy Raffle, "PR""){ +constructor(uint256 _entranceFee, address _feeAddress, uint256 _raffleDuration) ERC721 ("Puppy Raffle, "PR""){ // @Written: check for zero address! ... } diff --git a/courses/security/4-puppy-raffle/54-reporting-reentrancy/+page.md b/courses/security/4-puppy-raffle/54-reporting-reentrancy/+page.md index 42559c3c3..36015f9d5 100644 --- a/courses/security/4-puppy-raffle/54-reporting-reentrancy/+page.md +++ b/courses/security/4-puppy-raffle/54-reporting-reentrancy/+page.md @@ -20,7 +20,7 @@ We know this is going to be a high, based on everything we went over and all we ### [H-1] Reentrancy attack in `PuppyRaffle::refund` allows entrant to drain raffle balance ``` -> **Note:** It's often a good idea to go through the steps of building a PoC to prove an issue before taking the time to write things up. We wrote a test for reentracy, that we'll be using, earlier. +> **Note:** It's often a good idea to go through the steps of building a PoC to prove an issue before taking the time to write things up. We wrote a test for reentrancy, that we'll be using, earlier. On to the next parts of the report template. @@ -154,7 +154,7 @@ Last part - Recommendation. We know this, this protocol should be following CEI. require(playerAddress != address(0), "PuppyRaffle: Player already refunded, or is not active"); + players[playerIndex] = address(0); + emit RaffleRefunded(playerAddress); - payable(msg.sender).sendeValue(entranceFees); + payable(msg.sender).sendValue(entranceFees); - players[playerIndex] = address(0); - emit RaffleRefunded(playerAddress); } diff --git a/courses/security/4-puppy-raffle/55-reporting-getActivePlayerIndex-incorrect-for-edge-case/+page.md b/courses/security/4-puppy-raffle/55-reporting-getActivePlayerIndex-incorrect-for-edge-case/+page.md index fe7ce3ed3..5b90ae9d7 100644 --- a/courses/security/4-puppy-raffle/55-reporting-getActivePlayerIndex-incorrect-for-edge-case/+page.md +++ b/courses/security/4-puppy-raffle/55-reporting-getActivePlayerIndex-incorrect-for-edge-case/+page.md @@ -15,7 +15,7 @@ Let's begin the write up with a title. There's some argument to be had that a vu Ultimately we're going to record this as a low. My title is going to look like so: ``` -[L-1] `PuppyRaffle::getActivePlayerIndex` returns 0 for non-existant players and players at index 0 causing players to incorrectly think they have not entered the raffle +[L-1] `PuppyRaffle::getActivePlayerIndex` returns 0 for non-existent players and players at index 0 causing players to incorrectly think they have not entered the raffle ``` Root Cause. Impact. Classic. 😆 diff --git a/courses/security/4-puppy-raffle/56-reporting-should-follow-cei/+page.md b/courses/security/4-puppy-raffle/56-reporting-should-follow-cei/+page.md index c40acac47..2b85ad6a4 100644 --- a/courses/security/4-puppy-raffle/56-reporting-should-follow-cei/+page.md +++ b/courses/security/4-puppy-raffle/56-reporting-should-follow-cei/+page.md @@ -13,7 +13,7 @@ Taking a look at our next `@Audit` tag, this finding should be another quick one ```` **Title:** [I-4] does not follow CEI, which is not a best practice -It's best to keep code cleaen and follow CEI (Checks, Effects, Interactions). +It's best to keep code clean and follow CEI (Checks, Effects, Interactions). ```diff - (bool success,) = winner.call{value: prizePool}(""); diff --git a/courses/security/4-puppy-raffle/6-tooling-solidity-visual-developer/+page.md b/courses/security/4-puppy-raffle/6-tooling-solidity-visual-developer/+page.md index 701b131ce..77adcc0e8 100644 --- a/courses/security/4-puppy-raffle/6-tooling-solidity-visual-developer/+page.md +++ b/courses/security/4-puppy-raffle/6-tooling-solidity-visual-developer/+page.md @@ -20,7 +20,7 @@ We also went over `Solidity Metrics` earlier, but let's take another look as `Pu ### Solidity Metrics Insights -Scrolling to the bottom of the `Solidity: Metrics` report, take a look at the `Inheritence Graph` +Scrolling to the bottom of the `Solidity: Metrics` report, take a look at the `Inheritance Graph` ::image{src='/security-section-4/6-tooling-svd/tooling-svd1.png' style='width: 75%; height: auto;'} @@ -42,7 +42,7 @@ This is incredibly valuable. It provides is a clear breakdown of `Internal` vs ` There's another tool I'll briefly mention - some developers swear by it. It's the extension [**Solidity Visual Developer**](https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor) for VS Code. -In addition to providing very similar reporting as Solidity Metrics, the inheritence graph is interactive and it provides syntax highlighting in your code based on variable types. +In addition to providing very similar reporting as Solidity Metrics, the inheritance graph is interactive and it provides syntax highlighting in your code based on variable types. ::image{src='/security-section-4/6-tooling-svd/tooling-svd4.png' style='width: 75%; height: auto;'} diff --git a/courses/security/4-puppy-raffle/60-reporting-smart-contract-wallet-reverts-winning/+page.md b/courses/security/4-puppy-raffle/60-reporting-smart-contract-wallet-reverts-winning/+page.md index a14d51ab8..b39e1adaa 100644 --- a/courses/security/4-puppy-raffle/60-reporting-smart-contract-wallet-reverts-winning/+page.md +++ b/courses/security/4-puppy-raffle/60-reporting-smart-contract-wallet-reverts-winning/+page.md @@ -42,7 +42,7 @@ Also, true winners would not be able to get paid out, and someone else would win **Recommended Mitigation:** There are a few options to mitigate this issue. 1. Do not allow smart contract wallet entrants (not recommended) -2. Create a mapping of addresses -> payout so winners can pull their funds out themselves, putting the owness on the winner to claim their prize. (Recommended) +2. Create a mapping of addresses -> payout so winners can pull their funds out themselves, putting the owners on the winner to claim their prize. (Recommended) ``` To briefly touch on our recommendations here - The reason disallowing smart contract entrants would not be a preferred mitigation, is that this would restrict situations like multisignature wallets from participating. We'd much rather not lock people out entirely. diff --git a/courses/security/4-puppy-raffle/63-adding-the-audit-to-our-portfolio/+page.md b/courses/security/4-puppy-raffle/63-adding-the-audit-to-our-portfolio/+page.md index 773628bf1..24eadd37b 100644 --- a/courses/security/4-puppy-raffle/63-adding-the-audit-to-our-portfolio/+page.md +++ b/courses/security/4-puppy-raffle/63-adding-the-audit-to-our-portfolio/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Adding to our Portfolio -Ok, we've - for the most part - completed the write ups for the findings we identified in Puppy Raffle. The next step is generatin our PDF report and adding this to our security portfolio! +Ok, we've - for the most part - completed the write ups for the findings we identified in Puppy Raffle. The next step is generating our PDF report and adding this to our security portfolio! First step, let's add what we need to our `audit-data` folder. @@ -245,7 +245,7 @@ View the report in the dropdown below, please know it's quiet long. There are a few attack vectors here. - 1. Validators can know ahead of time the `block.timestamp` and `block.difficulty` and use that knowledge to predict when / how to participate. See the [solidity blog on prevrando](https://soliditydeveloper.com/prevrandao) here. `block.difficulty` was recently replaced with `prevrandao`. + 1. Validators can know ahead of time the `block.timestamp` and `block.difficulty` and use that knowledge to predict when / how to participate. See the [solidity blog on prevrandao](https://soliditydeveloper.com/prevrandao) here. `block.difficulty` was recently replaced with `prevrandao`. 2. Users can manipulate the `msg.sender` value to result in their index being the winner. Using on-chain values as a randomness seed is a [well-known attack vector](https://betterprogramming.pub/how-to-generate-truly-random-numbers-in-solidity-and-blockchain-9ced6472dbdf) in the blockchain space. @@ -528,7 +528,7 @@ View the report in the dropdown below, please know it's quiet long. ### [M-2] Balance check on `PuppyRaffle::withdrawFees` enables griefers to selfdestruct a contract to send ETH to the raffle, blocking withdrawals - **Description:** The `PuppyRaffle::withdrawFees` function checks the `totalFees` equals the ETH balance of the contract (`address(this).balance`). Since this contract doesn't have a `payable` fallback or `receive` function, you'd think this wouldn't be possible, but a user could `selfdesctruct` a contract with ETH in it and force funds to the `PuppyRaffle` contract, breaking this check. + **Description:** The `PuppyRaffle::withdrawFees` function checks the `totalFees` equals the ETH balance of the contract (`address(this).balance`). Since this contract doesn't have a `payable` fallback or `receive` function, you'd think this wouldn't be possible, but a user could `selfdestruct` a contract with ETH in it and force funds to the `PuppyRaffle` contract, breaking this check. ```javascript function withdrawFees() external { @@ -642,13 +642,13 @@ View the report in the dropdown below, please know it's quiet long. **Recommended Mitigation:** There are a few options to mitigate this issue. 4. Do not allow smart contract wallet entrants (not recommended) - 5. Create a mapping of addresses -> payout so winners can pull their funds out themselves, putting the owness on the winner to claim their prize. (Recommended) + 5. Create a mapping of addresses -> payout so winners can pull their funds out themselves, putting the owners on the winner to claim their prize. (Recommended) ## Informational / Non-Critical ### [I-1] Floating pragmas - **Description:** Contracts should use strict versions of solidity. Locking the version ensures that contracts are not deployed with a different version of solidity than they were tested with. An incorrect version could lead to uninteded results. + **Description:** Contracts should use strict versions of solidity. Locking the version ensures that contracts are not deployed with a different version of solidity than they were tested with. An incorrect version could lead to unintended results. https://swcregistry.io/docs/SWC-103/ diff --git a/courses/security/4-puppy-raffle/65-solodit/+page.md b/courses/security/4-puppy-raffle/65-solodit/+page.md index e43c747ae..785d0e950 100644 --- a/courses/security/4-puppy-raffle/65-solodit/+page.md +++ b/courses/security/4-puppy-raffle/65-solodit/+page.md @@ -14,7 +14,7 @@ The legendary [**Hans Friese**](https://twitter.com/hansfriese?lang=en) Was the When asked for advice on how he performs so well, he says one of the most beneficial things he does is reading the reports of other auditors. -Thus [**Solodit**](https://solodit.xyz/) was born. [**Solodit**](https://solodit.xyz/) aggregates publicly available security reports from across the industry into a single convenient aveneue to search and sort through. +Thus [**Solodit**](https://solodit.xyz/) was born. [**Solodit**](https://solodit.xyz/) aggregates publicly available security reports from across the industry into a single convenient avenue to search and sort through. Once logged in you should see something like this, a clean UI through which you can search and filter by anything you'd like. diff --git a/courses/security/4-puppy-raffle/8-recon-reading-the-code/+page.md b/courses/security/4-puppy-raffle/8-recon-reading-the-code/+page.md index 0a11540f4..4735fa241 100644 --- a/courses/security/4-puppy-raffle/8-recon-reading-the-code/+page.md +++ b/courses/security/4-puppy-raffle/8-recon-reading-the-code/+page.md @@ -42,7 +42,7 @@ function enterRaffle(address[] memory newPlayers) public payable { Starting with the `NatSpec` we may have a few questions rise. - _What's meant by # of players?_ -- _How does the function prevent duplicant entrants?_ +- _How does the function prevent duplicate entrants?_ Write questions like these in your `notes.md` or even as `@audit` notes inline. These are things we'll want to answer as we progress through the code. diff --git a/courses/security/5-tswap/11-stateless-and-stateful-fuzzing-practice/+page.md b/courses/security/5-tswap/11-stateless-and-stateful-fuzzing-practice/+page.md index 2b1ba3089..5871c6408 100644 --- a/courses/security/5-tswap/11-stateless-and-stateful-fuzzing-practice/+page.md +++ b/courses/security/5-tswap/11-stateless-and-stateful-fuzzing-practice/+page.md @@ -32,7 +32,7 @@ In the following sections we're going to focus on 3 types of testing to check fo 2. Open Stateful Fuzzing (harder) 3. Closed Stateful Fuzzing w/ Handler (Hardest) -Now, before moving forward, I strong encourage you to read through and understand the infomation in the [**invariant-break README**](https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/invariant-break/README.md). Understanding the concepts contained therein will give you a big advantage in the next sections as we employ them practically. +Now, before moving forward, I strong encourage you to read through and understand the information in the [**invariant-break README**](https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/invariant-break/README.md). Understanding the concepts contained therein will give you a big advantage in the next sections as we employ them practically. The next thing I want you to do, is delete the `test/invariant-break` folder in the `sc-exploits-minimized` repo you just cloned. Actually writing out this code is and understanding how these tests work is what will allow you to master these skills. diff --git a/courses/security/5-tswap/13-where-stateless-fuzzing-fails/+page.md b/courses/security/5-tswap/13-where-stateless-fuzzing-fails/+page.md index d0d5304cc..16cdbf421 100644 --- a/courses/security/5-tswap/13-where-stateless-fuzzing-fails/+page.md +++ b/courses/security/5-tswap/13-where-stateless-fuzzing-fails/+page.md @@ -111,7 +111,7 @@ It's important to understand these few settings we're using here. - depth - how many random functions will be called per run - fail_on_revert - this value determines if a test will fail as a product of reverted transactions. We'll go into more detail soon. -Remember you can always reference the [**Foundry Book**](https://book.getfoundry.sh/reference/config/testing?highlight=%5Binvariant%5D#invariant) for an exaustive list of these configurations. +Remember you can always reference the [**Foundry Book**](https://book.getfoundry.sh/reference/config/testing?highlight=%5Binvariant%5D#invariant) for an exhaustive list of these configurations. Let's run the test. diff --git a/courses/security/5-tswap/14-fuzzing-where-method-1-fails/+page.md b/courses/security/5-tswap/14-fuzzing-where-method-1-fails/+page.md index e98e0ab32..0930be1d0 100644 --- a/courses/security/5-tswap/14-fuzzing-where-method-1-fails/+page.md +++ b/courses/security/5-tswap/14-fuzzing-where-method-1-fails/+page.md @@ -19,7 +19,7 @@ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol /* * This contract represents a vault for ERC20 tokens. * - * INVARIANT: Users must always be able to withdraw the exact balance amout out. + * INVARIANT: Users must always be able to withdraw the exact balance amount. */ contract HandlerStatefulFuzzCatches { error HandlerStatefulFuzzCatches__UnsupportedToken(); @@ -96,7 +96,7 @@ import {HandlerStatefulFuzzCatches} from "src/invariant-break/HandlerStatefulFuz import {Test} from "forge-std/Test.sol"; import {StdInvariant} from "forge-std/StdInvariant.sol"; import {MockUSDC} from "test/mocks/MockUSDC.sol"; -import {YeildERC20} from "test/mocks/YeildERC20.sol"; +import {YieldERC20} from "test/mocks/YieldERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; ``` @@ -107,7 +107,7 @@ contract AttemptedBreakTest is StdInvariant, Test { HandlerStatefulFuzzCatches handlerstatefulFuzzCatches; MockUSDC mockUSDC; - YeildERC20 yeildERC20; + YieldERC20 yieldERC20; IERC20[] supportedTokens; address user = makeAddr("user"); @@ -117,7 +117,7 @@ And now, our `setUp` function. A few things to consider here: 1. Mocks need to be deployed 2. Mocks need to be added to our `supportedTokens` array -3. Our `user` needs to have a balance of YeildERC20 and/or MockUSDC +3. Our `user` needs to have a balance of YieldERC20 and/or MockUSDC 4. Our `HandlerStatefulFuzzCatches.sol` contract needs to be deployed with our `supportedTokens` argument 5. `HandlerStatefulFuzzCatches.sol` needs to be set as our fuzzer's `targetContract` @@ -127,18 +127,18 @@ What's this `setUp` function look like? function setUp() public { vm.startPrank(user); mockUSDC = new MockUSDC(); - yeildERC20 = new YeildERC20(); - mockUSDC.mint(user, yeildERC20.INITIAL_SUPPLY()); + yieldERC20 = new YieldERC20(); + mockUSDC.mint(user, yieldERC20.INITIAL_SUPPLY()); vm.stopPrank(); - supportedTokens.push(IERC20(address(yeildERC20))); + supportedTokens.push(IERC20(address(yieldERC20))); supportedTokens.push(IERC20(address(mockUSDC))); handlerstatefulFuzzCatches = new HandlerStatefulFuzzCatches(supportedTokens); targetContract(address(handlerstatefulFuzzCatches)); } ``` -In the above we're pranking our `user` and then deploying and minting the tokens the `user` needs. `supportedTokens` then has both `mockUSDC` and `yeildERC20` pushed to it and our `HandlerStatefulFuzzCatches.sol` contract is deployed and set as our `targetContract`. Nailed it! +In the above we're pranking our `user` and then deploying and minting the tokens the `user` needs. `supportedTokens` then has both `mockUSDC` and `yieldERC20` pushed to it and our `HandlerStatefulFuzzCatches.sol` contract is deployed and set as our `targetContract`. Nailed it! Let's now consider what our invariant might look like. We know _Users must always be able to withdraw the exact balance amount out_. @@ -152,8 +152,8 @@ contract AttemptedBreakTest is StdInvariant, Test { function setUp() public { vm.startPrank(user); mockUSDC = new MockUSDC(); - yeildERC20 = new YeildERC20(); - startingAmount = yeildERC20.INITIAL_SUPPLY(); + yieldERC20 = new YieldERC20(); + startingAmount = yieldERC20.INITIAL_SUPPLY(); mockUSDC.mint(user, startingAmount); vm.stopPrank(); ... @@ -165,7 +165,7 @@ With a little refactoring we can now reference the `startingAmount` of our `user ```js function testStartingAmount() public view { assert(startingAmount == mockUSDC.balanceOf(user)); - assert(startingAmount == yeildERC20.balanceOf(user)); + assert(startingAmount == yieldERC20.balanceOf(user)); } ``` @@ -179,22 +179,22 @@ Now, if the `user` deposits and then withdraws everything, their startingAmount function statefulFuzz_TestInvariantBreaks() public { vm.startPrank(user); handlerstatefulFuzzCatches.withdrawToken(IERC20(address(mockUSDC))); - handlerstatefulFuzzCatches.withdrawToken(IERC20(address(yeildERC20))); + handlerstatefulFuzzCatches.withdrawToken(IERC20(address(yieldERC20))); vm.stopPrank(); assert(handlerstatefulFuzzCatches.tokenBalances(user, IERC20(address(mockUSDC))) == 0); - assert(handlerstatefulFuzzCatches.tokenBalances(user, IERC20(address(yeildERC20))) == 0); + assert(handlerstatefulFuzzCatches.tokenBalances(user, IERC20(address(yieldERC20))) == 0); assert(mockUSDC.balanceOf(user) == startingAmount); - assert(yeildERC20.balanceOf(user) == startingAmount); + assert(yieldERC20.balanceOf(user) == startingAmount); } ``` In this function, we're assuring the the fuzz tests will end with our `user` withdrawing both types of tokens from the protocol. We're then asserting a number of things 1. `user`'s deposit balance of MockUSDC is reset to 0 -2. `user`'s deposit balance of YeildERC20 is reset to 0 +2. `user`'s deposit balance of YieldERC20 is reset to 0 3. `user`'s balance of MockUSDC returns to the startingAmount -4. `user`'s balance of YeildERC20 returns to the startingAmount +4. `user`'s balance of YieldERC20 returns to the startingAmount Let's run it with `forge test --mt statefulFuzz_TestInvariantBreaks` @@ -226,4 +226,4 @@ We learnt about the limitations of stateless fuzzing and how many vulnerabilitie There are a few problems with our test so far. For example - we're only testing a single user's ability to deposit and withdraw. We should probably be fuzzing users in our tests. Additionally, we neglected to _approve_ any of our tokens before attempting to deposit, so even if the tokens were supported we likely would have reverted again. -In the next lesson, let's clean things up and look at a methodolody which allows us to narrow down the focus of our fuzz testing leveraging a handler. See you there! +In the next lesson, let's clean things up and look at a methodology which allows us to narrow down the focus of our fuzz testing leveraging a handler. See you there! diff --git a/courses/security/5-tswap/15-stateful-fuzzing-method-2/+page.md b/courses/security/5-tswap/15-stateful-fuzzing-method-2/+page.md index ae01f03cb..8696b2da0 100644 --- a/courses/security/5-tswap/15-stateful-fuzzing-method-2/+page.md +++ b/courses/security/5-tswap/15-stateful-fuzzing-method-2/+page.md @@ -14,7 +14,7 @@ We use a `Handler` to narrow the potentially limitless inputs a fuzzer can provi Start by creating two new files `test/invariant-break/handler/Handler.t.sol` and `test/invariant-break/handler/Invariant.t.sol`. -Assure `fail_on_revert = true` in our `foundy.toml`. This will give us the best insight into how effective our code and tests are. +Assure `fail_on_revert = true` in our `foundry.toml`. This will give us the best insight into how effective our code and tests are. ### Handler.t.sol @@ -50,7 +50,7 @@ We want it to: - call `depositToken` only on _supported_ tokens. - call `withdrawToken` only on _supported_ tokens. -Lets employ a way for our Handler to determine which tokens are supported. We'll start by importing `YeildERC20` and `MockUSDC`. These are going to need to be input parameters for our constructor as well. Our setup so far should look something like this: +Lets employ a way for our Handler to determine which tokens are supported. We'll start by importing `YieldERC20` and `MockUSDC`. These are going to need to be input parameters for our constructor as well. Our setup so far should look something like this: ```js // SPDX-License-Identifier: MIT @@ -59,18 +59,18 @@ pragma solidity 0.8.20; import {HandlerStatefulFuzzCatches} from "src/invariant-break/HandlerStatefulFuzzCatches.sol"; import {Test} from "forge-std/Test.sol"; import {MockUSDC} from "test/mocks/MockUSDC.sol"; -import {YeildERC20} from "test/mocks/YeildERC20.sol"; +import {YieldERC20} from "test/mocks/YieldERC20.sol"; contract Handler is Test { HandlerStatefulFuzzCatches handlerStatefulFuzzCatches; MockUSDC mockUSDC; - YeildERC20 yeildERC20; + YieldERC20 yieldERC20; address user; - constructor (HandlerStatefulFuzzCatches _handlerStatefulFuzzCatches, MockUSDC _mockUSDC, YeildERC20 _yeildERC20, address _user) { + constructor (HandlerStatefulFuzzCatches _handlerStatefulFuzzCatches, MockUSDC _mockUSDC, YieldERC20 _yieldERC20, address _user) { handlerStatefulFuzzCatches = _handlerStatefulFuzzCatches; mockUSDC = _mockUSDC; - yeildERC20 = _yeildERC20; + yieldERC20 = _yieldERC20; user = _user; } } @@ -81,11 +81,11 @@ We've also added a user with whom to call the functions of our contract! Now we Starting with `depositToken`, a way we can tell our fuzzer to only use supported tokens would be to make a function to deposit for each token we have. ```js - function depositYeildERC20(uint256 _amount) public { - uint256 amount = bound(_amount, 0, yeildERC20.balanceOf(user)); + function depositYieldERC20(uint256 _amount) public { + uint256 amount = bound(_amount, 0, yieldERC20.balanceOf(user)); vm.startPrank(user); - yeildERC20.approve(address(handlerStatefulFuzzCatches), amount); - handlerStatefulFuzzCatches.depositToken(yeildERC20, amount); + yieldERC20.approve(address(handlerStatefulFuzzCatches), amount); + handlerStatefulFuzzCatches.depositToken(yieldERC20, amount); vm.stopPrank(); } @@ -102,14 +102,14 @@ By having our fuzzer directed to these functions specifically, we're able to ass 1. The amount deposited is never more than the user has and is always a positive number 2. The token deposited is always approved for the amount being deposited -3. The only tokens deposited are those that are supported - YeildERC20 & MockUSDC +3. The only tokens deposited are those that are supported - YieldERC20 & MockUSDC Great! We're also going to want to try withdrawing. Let's see what those functions look like. ```js -function withdrawYeildERC20() public { +function withdrawYieldERC20() public { vm.startPrank(user); - handlerStatefulFuzzCatches.withdrawToken(yeildERC20); + handlerStatefulFuzzCatches.withdrawToken(yieldERC20); vm.stopPrank(); } @@ -134,31 +134,31 @@ pragma solidity 0.8.20; import {HandlerStatefulFuzzCatches} from "src/invariant-break/HandlerStatefulFuzzCatches.sol"; import {Test} from "forge-std/Test.sol"; import {MockUSDC} from "test/mocks/MockUSDC.sol"; -import {YeildERC20} from "test/mocks/YeildERC20.sol"; +import {YieldERC20} from "test/mocks/YieldERC20.sol"; contract Handler is Test { HandlerStatefulFuzzCatches handlerStatefulFuzzCatches; MockUSDC mockUSDC; - YeildERC20 yeildERC20; + YieldERC20 yieldERC20; address user; constructor( HandlerStatefulFuzzCatches _handlerStatefulFuzzCatches, MockUSDC _mockUSDC, - YeildERC20 _yeildERC20, + YieldERC20 _yieldERC20, address _user ) { handlerStatefulFuzzCatches = _handlerStatefulFuzzCatches; mockUSDC = _mockUSDC; - yeildERC20 = _yeildERC20; + yieldERC20 = _yieldERC20; user = _user; } - function depositYeildERC20(uint256 _amount) public { - uint256 amount = bound(_amount, 0, yeildERC20.balanceOf(user)); + function depositYieldERC20(uint256 _amount) public { + uint256 amount = bound(_amount, 0, yieldERC20.balanceOf(user)); vm.startPrank(user); - yeildERC20.approve(address(handlerStatefulFuzzCatches), amount); - handlerStatefulFuzzCatches.depositToken(yeildERC20, amount); + yieldERC20.approve(address(handlerStatefulFuzzCatches), amount); + handlerStatefulFuzzCatches.depositToken(yieldERC20, amount); vm.stopPrank(); } @@ -170,9 +170,9 @@ contract Handler is Test { vm.stopPrank(); } - function withdrawYeildERC20() public { + function withdrawYieldERC20() public { vm.startPrank(user); - handlerStatefulFuzzCatches.withdrawToken(yeildERC20); + handlerStatefulFuzzCatches.withdrawToken(yieldERC20); vm.stopPrank(); } @@ -201,14 +201,14 @@ import {HandlerStatefulFuzzCatches} from "src/invariant-break/HandlerStatefulFuz import {Test} from "forge-std/Test.sol"; import {StdInvariant} from "forge-std/StdInvariant.sol"; import {MockUSDC} from "test/mocks/MockUSDC.sol"; -import {YeildERC20} from "test/mocks/YeildERC20.sol"; +import {YieldERC20} from "test/mocks/YieldERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {Handler} from "test/invariant-break/handler/Handler.t.sol"; // HANDLER IMPORTED contract AttemptedBreakTest is StdInvariant, Test { HandlerStatefulFuzzCatches handlerstatefulFuzzCatches; MockUSDC mockUSDC; - YeildERC20 yeildERC20; + YieldERC20 yieldERC20; IERC20[] supportedTokens; uint256 startingAmount; @@ -219,19 +219,19 @@ contract AttemptedBreakTest is StdInvariant, Test { function setUp() public { vm.startPrank(user); mockUSDC = new MockUSDC(); - yeildERC20 = new YeildERC20(); - startingAmount = yeildERC20.INITIAL_SUPPLY(); + yieldERC20 = new YieldERC20(); + startingAmount = yieldERC20.INITIAL_SUPPLY(); mockUSDC.mint(user, startingAmount); vm.stopPrank(); - supportedTokens.push(IERC20(address(yeildERC20))); + supportedTokens.push(IERC20(address(yieldERC20))); supportedTokens.push(IERC20(address(mockUSDC))); handlerstatefulFuzzCatches = new HandlerStatefulFuzzCatches(supportedTokens); - handler = new Handler(handlerstatefulFuzzCatches, mockUSDC, yeildERC20, user); // HANDLER INITIALIZED + handler = new Handler(handlerstatefulFuzzCatches, mockUSDC, yieldERC20, user); // HANDLER INITIALIZED bytes4[] memory selectors = new bytes4[](4); // SPECIFY SELECTORS TO FUZZ - selectors[0] = handler.depositYeildERC20.selector; + selectors[0] = handler.depositYieldERC20.selector; selectors[1] = handler.depositMockUSDC.selector; - selectors[2] = handler.withdrawYeildERC20.selector; + selectors[2] = handler.withdrawYieldERC20.selector; selectors[3] = handler.withdrawMockUSDC.selector; targetSelector(FuzzSelector({addr: address(handler), selectors: selectors})); // SET TARGET SELECTORS @@ -242,7 +242,7 @@ contract AttemptedBreakTest is StdInvariant, Test { The only differences between this test contract and our previous `AttemptedBreakTest.t.sol` I've commented in the above. -Essentially we're importing our handler, and deploying/intializing it while passing handlerstatefulFuzzCatches, mockUSDC, yeildERC20 and the user as constructor parameters. +Essentially we're importing our handler, and deploying/initializing it while passing handlerstatefulFuzzCatches, mockUSDC, yieldERC20 and the user as constructor parameters. From there we are adding the specific function selectors from our handler to an array and then setting our handler address and those selectors as our target through: @@ -262,13 +262,13 @@ What makes this especially cool, is that we can reuse the previous fuzz test we function statefulFuzz_testInvariantBreaksHandler() public { vm.startPrank(user); handlerStatefulFuzzCatches.withdrawToken(mockUSDC); - handlerStatefulFuzzCatches.withdrawToken(yeildERC20); + handlerStatefulFuzzCatches.withdrawToken(yieldERC20); vm.stopPrank(); assert(mockUSDC.balanceOf(address(handlerStatefulFuzzCatches)) == 0); - assert(yeildERC20.balanceOf(address(handlerStatefulFuzzCatches)) == 0); + assert(yieldERC20.balanceOf(address(handlerStatefulFuzzCatches)) == 0); assert(mockUSDC.balanceOf(user) == startingAmount); - assert(yeildERC20.balanceOf(user) == startingAmount); + assert(yieldERC20.balanceOf(user) == startingAmount); } ``` diff --git a/courses/security/5-tswap/16-Debugging-Fuzz-Sequences/+page.md b/courses/security/5-tswap/16-Debugging-Fuzz-Sequences/+page.md index 3e2aac3c3..2520f6862 100644 --- a/courses/security/5-tswap/16-Debugging-Fuzz-Sequences/+page.md +++ b/courses/security/5-tswap/16-Debugging-Fuzz-Sequences/+page.md @@ -32,19 +32,19 @@ The reason seems to be that we're calling `transferFrom` on a random address. Wh function setUp() public { vm.startPrank(user); mockUSDC = new MockUSDC(); - yeildERC20 = new YeildERC20(); - startingAmount = yeildERC20.INITIAL_SUPPLY(); + yieldERC20 = new YieldERC20(); + startingAmount = yieldERC20.INITIAL_SUPPLY(); mockUSDC.mint(user, startingAmount); vm.stopPrank(); - supportedTokens.push(IERC20(address(yeildERC20))); + supportedTokens.push(IERC20(address(yieldERC20))); supportedTokens.push(IERC20(address(mockUSDC))); handlerStatefulFuzzCatches = new HandlerStatefulFuzzCatches(supportedTokens); - handler = new Handler(handlerStatefulFuzzCatches, mockUSDC, yeildERC20, user); // HANDLER INITIALIZED + handler = new Handler(handlerStatefulFuzzCatches, mockUSDC, yieldERC20, user); // HANDLER INITIALIZED bytes4[] memory selectors = new bytes4[](4); // SPECIFY SELECTORS TO FUZZ - selectors[0] = handler.depositYeildERC20.selector; + selectors[0] = handler.depositYieldERC20.selector; selectors[1] = handler.depositMockUSDC.selector; - selectors[2] = handler.withdrawYeildERC20.selector; + selectors[2] = handler.withdrawYieldERC20.selector; selectors[3] = handler.withdrawMockUSDC.selector; targetSelector(FuzzSelector({addr: address(handler), selectors: selectors})); // SET TARGET SELECTORS @@ -56,7 +56,7 @@ Now let's try it. ::image{src='/security-section-5/16-debugging-fuzz-sequences/debugging-fuzz-sequences2.png' style='width: 100%; height: auto;'} -Alright! It looks like we may have found something! We're seeing an error of `ERC20InsufficientBalance` when calling `withdrawToken` on `yeildERC20`. That's odd. Let's look at the `withdrawToken` function again. +Alright! It looks like we may have found something! We're seeing an error of `ERC20InsufficientBalance` when calling `withdrawToken` on `yieldERC20`. That's odd. Let's look at the `withdrawToken` function again. ```js function withdrawToken(IERC20 token) external requireSupportedToken(token) { @@ -66,7 +66,7 @@ function withdrawToken(IERC20 token) external requireSupportedToken(token) { } ``` -Nothing out of the ordinary it seems, we're just calling `safeTransfer` on the token. Maybe we need to take a closer look at `YeildERC20.sol`. +Nothing out of the ordinary it seems, we're just calling `safeTransfer` on the token. Maybe we need to take a closer look at `YieldERC20.sol`. ```js // SPDX-License-Identifier: MIT @@ -74,7 +74,7 @@ pragma solidity 0.8.20; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -contract YeildERC20 is ERC20 { +contract YieldERC20 is ERC20 { uint256 public constant INITIAL_SUPPLY = 1_000_000e18; address public immutable owner; // We take a fee once every 10 transactions @@ -83,7 +83,7 @@ contract YeildERC20 is ERC20 { uint256 public constant USER_AMOUNT = 90; uint256 public constant PRECISION = 100; - constructor() ERC20("MockYeildERC20", "MYEILD") { + constructor() ERC20("MockYieldERC20", "MYIELD") { owner = msg.sender; _mint(msg.sender, INITIAL_SUPPLY); } @@ -113,7 +113,7 @@ contract YeildERC20 is ERC20 { ``` -Ah ha! This `_update` function is sending a 10% fee to the owner of YeildERC20 every 10 transactions. This is why our `withdrawTokens` function was throwing an `ERC20InsufficientBalance` error - `HandlerStatefulFuzzCatches.sol` doesn't have enough `YeildERC20` to pay the fee! +Ah ha! This `_update` function is sending a 10% fee to the owner of YieldERC20 every 10 transactions. This is why our `withdrawTokens` function was throwing an `ERC20InsufficientBalance` error - `HandlerStatefulFuzzCatches.sol` doesn't have enough `YieldERC20` to pay the fee! This is actually a fairly common situation known is a `Fee on Transfer` token and they exist in a classification of vulnerabilities known as `Weird ERC20s`. diff --git a/courses/security/5-tswap/18-weird-erc20/+page.md b/courses/security/5-tswap/18-weird-erc20/+page.md index 5c143c2f0..4485317e1 100644 --- a/courses/security/5-tswap/18-weird-erc20/+page.md +++ b/courses/security/5-tswap/18-weird-erc20/+page.md @@ -12,7 +12,7 @@ There's a great [**GitHub Repo**](https://github.com/d-xo/weird-erc20) that's be The token we just dealt with in our `stateful fuzz testing` is an example of one of these `Weird ERC20s` - a `Fee on Transfer` token. -`YeildERC20` contained a mechanism which sent a fee to the owner every 10 transactions. This type of behaviour in fee on transfer tokens can actually break many protocols - so it's very important to keep an eye out for these incompatibilities. +`YieldERC20` contained a mechanism which sent a fee to the owner every 10 transactions. This type of behaviour in fee on transfer tokens can actually break many protocols - so it's very important to keep an eye out for these incompatibilities. Other examples of Weird ERC20s may: diff --git a/courses/security/5-tswap/2-phase-1-scoping/+page.md b/courses/security/5-tswap/2-phase-1-scoping/+page.md index 003b3c4b1..5f53198ab 100644 --- a/courses/security/5-tswap/2-phase-1-scoping/+page.md +++ b/courses/security/5-tswap/2-phase-1-scoping/+page.md @@ -17,7 +17,7 @@ cd 5-t-swap-audit `git branch` can be used to verify you're on the `main` branch. -In Puppy Raffle, the protocol had completed a basic onboarding questionnaire. In TSwap, we're going to introduct the [**Extensive Onboarding Form**](https://github.com/Cyfrin/5-t-swap-audit/blob/main/t-swap-onboarded.md). You'll learn that the more information and context we can gain about the protocol, the easier our review is going to be. +In Puppy Raffle, the protocol had completed a basic onboarding questionnaire. In TSwap, we're going to introduce the [**Extensive Onboarding Form**](https://github.com/Cyfrin/5-t-swap-audit/blob/main/t-swap-onboarded.md). You'll learn that the more information and context we can gain about the protocol, the easier our review is going to be. > Information is **_currency_** in a security review @@ -42,13 +42,13 @@ git checkout > **Protip:** After `git checkout` you can run `git branch` to acquire the ID of the hash commit. By running `git diff ` you'll receive an output of all the changed between the provided branch and the commit hash! -Notice that TSwap's SLOC is 374 - this is nearly DOUBLE what Puppy Raffle was and should be an important consideraton of ours when determining the time we need for the audit. +Notice that TSwap's SLOC is 374 - this is nearly DOUBLE what Puppy Raffle was and should be an important consideration of ours when determining the time we need for the audit. We should also note that the coverage reported here is ... abysmal. ::image{src='/security-section-5/2-phase-1-scoping/scoping2.png' style='width: 100%; height: auto;'} -The next sections I won't go over in great detail now, but read through these questions and their importance will beecome clear as we go through the protocol. +The next sections I won't go over in great detail now, but read through these questions and their importance will become clear as we go through the protocol. ::image{src='/security-section-5/2-phase-1-scoping/scoping3.png' style='width: 100%; height: auto;'} diff --git a/courses/security/5-tswap/20-constant-product-formula-explained/+page.md b/courses/security/5-tswap/20-constant-product-formula-explained/+page.md index 42d4c4e46..8f597fa36 100644 --- a/courses/security/5-tswap/20-constant-product-formula-explained/+page.md +++ b/courses/security/5-tswap/20-constant-product-formula-explained/+page.md @@ -9,7 +9,7 @@ title: Constant Product Formula Explained In order to get started writing our fuzzing test suite we'll need to define what TSwap's core invariant is. Fortunately the protocol provides this in their README. ```md -Our system works because the ratio of Token A & WETH will always stay the same. Well, for the most part. Since we add fees, our invariant technially increases. +Our system works because the ratio of Token A & WETH will always stay the same. Well, for the most part. Since we add fees, our invariant technically increases. x \* y = k @@ -44,7 +44,7 @@ This may look confusing at first, and that's ok. This is known as the `constant We should pay special mind to this line in our documentation however: ``` -Since we add fees, our invariant technially increases. +Since we add fees, our invariant technically increases. ``` With that said, this is definitely an invariant we can test. The ratio between tokens x and y should always remain the same `x * y = (x + ∆x) * (y − ∆y)`. diff --git a/courses/security/5-tswap/21-invariant-t-sol/+page.md b/courses/security/5-tswap/21-invariant-t-sol/+page.md index 57bfbdb2a..cc771bb42 100644 --- a/courses/security/5-tswap/21-invariant-t-sol/+page.md +++ b/courses/security/5-tswap/21-invariant-t-sol/+page.md @@ -10,7 +10,7 @@ We're finally going to do it! We're going to write a robust stateful fuzz suite This is the most challenging part of this entire course. If you're struggling to write stateful fuzz tests in this section, don't be discouraged. Feel free to come back after you finish the rest of the course. -We're going to start just the same as we did in our ealier lessons. Create the following files and folders in the TSwap repo. +We're going to start just the same as we did in our earlier lessons. Create the following files and folders in the TSwap repo. - `test/invariant` - `test/invariant/Invariant.t.sol` diff --git a/courses/security/5-tswap/22-handler-t-sol/+page.md b/courses/security/5-tswap/22-handler-t-sol/+page.md index 2993dd534..d0751ef26 100644 --- a/courses/security/5-tswap/22-handler-t-sol/+page.md +++ b/courses/security/5-tswap/22-handler-t-sol/+page.md @@ -39,7 +39,7 @@ Having a skim through the TSwapPool.sol code there are a few functions that stan - swapExactOutput - swapExactInput -You may notice that `swapExactInput` doesn't have any documentation! This makes is incredibly difficult to gain any insight into what this function is meant to do without reading the code. Fortunately `swapExactOutput` has some NATPEC, so we should start there. +You may notice that `swapExactInput` doesn't have any documentation! This makes is incredibly difficult to gain any insight into what this function is meant to do without reading the code. Fortunately `swapExactOutput` has some NATSPEC, so we should start there. ```js /* diff --git a/courses/security/5-tswap/23-handler-swap-function/+page.md b/courses/security/5-tswap/23-handler-swap-function/+page.md index 6e440b81c..3712895dd 100644 --- a/courses/security/5-tswap/23-handler-swap-function/+page.md +++ b/courses/security/5-tswap/23-handler-swap-function/+page.md @@ -14,7 +14,7 @@ Alright! Let's remind ourselves of our core invariant in TSwap again. Recall that our term `β` was set equal to `∆y/y` and we've already worked out `∆y`, this was our `wethAmount`, the output of our swap. -Now, we need to determine `∆x`. We could work the math out ourselves, but we'll cheat a little bit again and I'll mention that TSwapPool.sol has another useful function for us - `getInputAmountBaseOnOutput`. This function will ultmately return the poolToken amount that our user needs to input for the swap. This is our `∆y`! Let's take a look at `getInputAmountBaseOnOutput` and walk through how the math is derived for practice and a deeper understanding of the protocol. +Now, we need to determine `∆x`. We could work the math out ourselves, but we'll cheat a little bit again and I'll mention that TSwapPool.sol has another useful function for us - `getInputAmountBaseOnOutput`. This function will ultimately return the poolToken amount that our user needs to input for the swap. This is our `∆y`! Let's take a look at `getInputAmountBaseOnOutput` and walk through how the math is derived for practice and a deeper understanding of the protocol. ### getInputAmountBaseOnOutput: The Math diff --git a/courses/security/5-tswap/25-debugging-the-fuzzer/+page.md b/courses/security/5-tswap/25-debugging-the-fuzzer/+page.md index 9afa7cad0..fb9a8707f 100644 --- a/courses/security/5-tswap/25-debugging-the-fuzzer/+page.md +++ b/courses/security/5-tswap/25-debugging-the-fuzzer/+page.md @@ -20,7 +20,7 @@ forge test --mt statefulFuzz_constantProductFormulaStaysTheSameY --vvvv ::image{src='/security-section-5/25-debugging-the-fuzzer/debugging-the-fuzzer1.png' style='width: 100%; height: auto;'} -Fail, as expected. This output tells us the exception occuring during a call of the `deposit` function, but we can scroll up in the trace output to gain more infomation. +Fail, as expected. This output tells us the exception occurring during a call of the `deposit` function, but we can scroll up in the trace output to gain more information. ::image{src='/security-section-5/25-debugging-the-fuzzer/debugging-the-fuzzer2.png' style='width: 100%; height: auto;'} @@ -90,7 +90,7 @@ function swapPoolTokenForWethBasedOnOutputWeth(uint256 outputWeth) public { } ``` -This above is how we're caculating our `actualDeltaY` and `actualDeltaX` in our Handler's swap function. If we look more closely at `endingY`, `endingX`, `startingY` and `startingX`, we'll notice that we erroneously have these variables tracking the changes of balance in `address(this)`. We'll that's wrong! We need to track the balances of each token in our pool. +This above is how we're calculating our `actualDeltaY` and `actualDeltaX` in our Handler's swap function. If we look more closely at `endingY`, `endingX`, `startingY` and `startingX`, we'll notice that we erroneously have these variables tracking the changes of balance in `address(this)`. We'll that's wrong! We need to track the balances of each token in our pool. Adjust the assignments in our `Handler.t.sol` like so: @@ -104,7 +104,7 @@ uint256 endingY = weth.balanceOf(address(pool)); Then run it again! -> **Note:** debugging our fuzz sequences is a truly iteritive process. The errors you receive, and how many of them, may actually be different if you have different errors in your code. Use the steps and skills shown here to debug any error you receive the same way. +> **Note:** debugging our fuzz sequences is a truly iterative process. The errors you receive, and how many of them, may actually be different if you have different errors in your code. Use the steps and skills shown here to debug any error you receive the same way. ::image{src='/security-section-5/25-debugging-the-fuzzer/debugging-the-fuzzer4.png' style='width: 100%; height: auto;'} diff --git a/courses/security/5-tswap/26-one-last-huzzah/+page.md b/courses/security/5-tswap/26-one-last-huzzah/+page.md index 08f86c6f8..b4c333ab1 100644 --- a/courses/security/5-tswap/26-one-last-huzzah/+page.md +++ b/courses/security/5-tswap/26-one-last-huzzah/+page.md @@ -32,7 +32,7 @@ forge test --mt statefulFuzz_constantProductFormulaStaysTheSameX -vvvv It errors! We can see that our expectedDeltaX and our actualDeltaX are wildly different. _What could possibly be going on here?_ -> **Protip:** Rather than scrolling through all the function calls in our test's trace, often the steps that lead to our issue can be found in the most recent function exectution near the bottom. +> **Protip:** Rather than scrolling through all the function calls in our test's trace, often the steps that lead to our issue can be found in the most recent function execution near the bottom. ::image{src='/security-section-5/26-one-last-huzzah/one-last-huzzah2.png' style='width: 100%; height: auto;'} @@ -83,7 +83,7 @@ function _swap(IERC20 inputToken, uint256 inputAmount, IERC20 outputToken, uint2 } ``` -BINGO! TSwap is transfering extra tokens! This is similar to our `fee on transfer` issue seen earlier and in fact, `fee on transfer` tokens would break this protocol as well. +BINGO! TSwap is transferring extra tokens! This is similar to our `fee on transfer` issue seen earlier and in fact, `fee on transfer` tokens would break this protocol as well. ```js /* diff --git a/courses/security/5-tswap/28-recon-manual-review-introduction/+page.md b/courses/security/5-tswap/28-recon-manual-review-introduction/+page.md index 3bc8660e2..93daf0149 100644 --- a/courses/security/5-tswap/28-recon-manual-review-introduction/+page.md +++ b/courses/security/5-tswap/28-recon-manual-review-introduction/+page.md @@ -6,8 +6,8 @@ title: Recon Manual Review Introduction ### Manual Review of TSwap -Now that we've exercised some of our tooling, it's important to remember that our manual review is never replaced and is an invaluabled part of the process. +Now that we've exercised some of our tooling, it's important to remember that our manual review is never replaced and is an invaluable part of the process. -Now would be a great opportunity to take a break before diving into the next section of manual review, afterwhich we'll go through writing our TSwap report. +Now would be a great opportunity to take a break before diving into the next section of manual review, after which we'll go through writing our TSwap report. When you're ready, let's take a look at `TSwapPool.sol` and make note of some of the things we find. diff --git a/courses/security/5-tswap/33-using-the-compiler-as-static-analysis-tool/+page.md b/courses/security/5-tswap/33-using-the-compiler-as-static-analysis-tool/+page.md index 09a2b7812..80250903b 100644 --- a/courses/security/5-tswap/33-using-the-compiler-as-static-analysis-tool/+page.md +++ b/courses/security/5-tswap/33-using-the-compiler-as-static-analysis-tool/+page.md @@ -22,7 +22,7 @@ We should take the time to read and understand the provided NATSPEC for this fun /// @param deadline The deadline for the transaction to be completed by ``` -An assessment of the function's paramaters in our IDE points to an issue our compiler identified earlier... +An assessment of the function's parameters in our IDE points to an issue our compiler identified earlier... ::image{src='/security-section-5/33-using-the-compiler-as-static-analysis-tool/using-the-compiler-as-static-analysis-tool1.png' style='width: 100%; height: auto;'} diff --git a/courses/security/5-tswap/34-add-liquidity/+page.md b/courses/security/5-tswap/34-add-liquidity/+page.md index 5ae48b9c0..59d427ff2 100644 --- a/courses/security/5-tswap/34-add-liquidity/+page.md +++ b/courses/security/5-tswap/34-add-liquidity/+page.md @@ -6,7 +6,7 @@ title: Manual Review - TSwapPool.sol - Add Liquidity ### Manual Review Continued -Ok! We went on a bit of a tangeant following up with our compiler warnings, but let's continue where we left off, in the `deposit` function. +Ok! We went on a bit of a tangent following up with our compiler warnings, but let's continue where we left off, in the `deposit` function.
Deposit Function @@ -164,7 +164,7 @@ I always set bugs if this nature related to event data as `low`, but there's a b It's really hard to justify a situation like this as a `medium`, but we can imagine other parts of a protocol relying on events (such as an oracle) that could easily bump something like this up to a `medium` or even a `high`. -The last thing our `_addLiquidityMintAndTransfer` function does is its interactions, it actually performs the transfers of tokens. This is great! The protocol team is following `CEI (checks, efffects, interactions)`. I may even make a note for myself indicating that this has been considered and confirmed. +The last thing our `_addLiquidityMintAndTransfer` function does is its interactions, it actually performs the transfers of tokens. This is great! The protocol team is following `CEI (checks, effects, interactions)`. I may even make a note for myself indicating that this has been considered and confirmed. ```js // Follows CEI @@ -222,7 +222,7 @@ _addLiquidityMintAndTransfer(wethToDeposit, poolTokensToDeposit, liquidityTokens ### Wrap Up -Great! We're all done our review of the `deposit` function. At this point I would likely leave a note inidicating that this section of the code has been assessed and to follow-up as needed. +Great! We're all done our review of the `deposit` function. At this point I would likely leave a note indicating that this section of the code has been assessed and to follow-up as needed. Leaving regular notes in the code base as you go will make report writing much easier in the future, so get into this habit! diff --git a/courses/security/5-tswap/4-what-is-a-dex/+page.md b/courses/security/5-tswap/4-what-is-a-dex/+page.md index c4de0d2ba..8fe9f7ca2 100644 --- a/courses/security/5-tswap/4-what-is-a-dex/+page.md +++ b/courses/security/5-tswap/4-what-is-a-dex/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### What is a Dex? -At it's highest level of abstraction what TSwap aims to do is: Allow users a permissionless way to swap assets between eachother at a fair price. +At it's highest level of abstraction what TSwap aims to do is: Allow users a permissionless way to swap assets between each other at a fair price. ::image{src='/security-section-5/4-what-is-a-dex/what-is-a-dex1.png' style='width: 100%; height: auto;'} @@ -20,7 +20,7 @@ Check out the [**DEXes section of DeFiLlama**](https://defillama.com/protocols/D TSwap is also en example of an Automated Market Maker (AMM). -Automated Market Makers are different from a typical "order book" style exchange. Instead of an order book which attempts to match buy and sell orders of users, an AMM leverages `Pools` of an asset. Uniswap is a geat example of this. Check out the [**Uniswap Explained video by WhiteboadCrypto**](https://www.youtube.com/watch?v=DLu35sIqVTM) to learn more in depth. +Automated Market Makers are different from a typical "order book" style exchange. Instead of an order book which attempts to match buy and sell orders of users, an AMM leverages `Pools` of an asset. Uniswap is a great example of this. Check out the [**Uniswap Explained video by WhiteboardCrypto**](https://www.youtube.com/watch?v=DLu35sIqVTM) to learn more in depth. In our next lesson, we're going take a closer look at AMMs and how they differ from order book exchanges. diff --git a/courses/security/5-tswap/41-missing-deadline-write-up/+page.md b/courses/security/5-tswap/41-missing-deadline-write-up/+page.md index 4e5c556c9..6c4fd53ee 100644 --- a/courses/security/5-tswap/41-missing-deadline-write-up/+page.md +++ b/courses/security/5-tswap/41-missing-deadline-write-up/+page.md @@ -10,7 +10,7 @@ With our informationals out of the way, we're moving on to our first `medium sev Since the lesson in which we identified this I had a change of heart about the severity here. Since this isn't a `swap` function and is `deposit` the impact of not having a deadline is less severe than if users were able to remove liquidity from the pool. As such, we're going with `medium`! -Within `TSwapPool::deposit` we identified that the `deadline` parameter wasn't being used! This is a critical oversight as it will allow people to continue to deposit even when it's expected that they'll have been disallowed, severly altering the protocol's expected functionality. +Within `TSwapPool::deposit` we identified that the `deadline` parameter wasn't being used! This is a critical oversight as it will allow people to continue to deposit even when it's expected that they'll have been disallowed, severely altering the protocol's expected functionality. Our write up is going to start with our template as always. @@ -81,7 +81,7 @@ function deposit( ### Wrap Up -Great! This one wasn't too tough. Let's look at what the write-up looks like when we put it all together befor moving to the next finding! +Great! This one wasn't too tough. Let's look at what the write-up looks like when we put it all together before moving to the next finding!
[M-1] `TSwapPool::deposit` is missing deadline check causing transactions to complete even after the deadline diff --git a/courses/security/5-tswap/42-reporting-continued/+page.md b/courses/security/5-tswap/42-reporting-continued/+page.md index 02d63fc8e..bc60e1fb1 100644 --- a/courses/security/5-tswap/42-reporting-continued/+page.md +++ b/courses/security/5-tswap/42-reporting-continued/+page.md @@ -33,9 +33,9 @@ Let's write this up! My example of each section of the write-up template is below, but I encourage you to write your own first and then compare!
-[L-1] `TSwapPool::LiquidtyAdded` event has parameters out of order +[L-1] `TSwapPool::LiquidityAdded` event has parameters out of order -### [L-1] `TSwapPool::LiquidtyAdded` event has parameters out of order +### [L-1] `TSwapPool::LiquidityAdded` event has parameters out of order **Description:** What the `LiquidityAdded` event is emitted in the `TSwapPool::_addLiquidityMintAndTransfer` function, it logs values in an incorrect order. The `poolTokensToDeposit` value should go in the third parameter position, whereas the `wethToDeposit` value should go second. @@ -73,7 +73,7 @@ function getInputAmountBasedOnOutput( } ``` -We identified a magic number resulting in an inaccurate fee caculation! This one is big. Again, I challenge you to write your own `Proof of Concept`, keep those skills sharp. +We identified a magic number resulting in an inaccurate fee calculation! This one is big. Again, I challenge you to write your own `Proof of Concept`, keep those skills sharp.
[H-1] Incorrect fee calculation in `TSwapPool::getInputAmountBasedOnOutput` causes protocol to take too many tokens from users, resulting in lost fees @@ -133,7 +133,7 @@ This will be our second low, compare your write up to mine below: ### [L-2] Default value returned by `TSwapPool::swapExactInput` results in incorrect return value given -**Description:** The `swapExactInput` function is expected to return the actual amount of tokens bought by the caller. However, while it declares the named return value `output` it is never assigned a value, nor uses an explict return statement. +**Description:** The `swapExactInput` function is expected to return the actual amount of tokens bought by the caller. However, while it declares the named return value `output` it is never assigned a value, nor uses an explicit return statement. **Impact:** The return value will always be `0`, giving incorrect information to the caller. diff --git a/courses/security/5-tswap/43-no-slippage-protection/+page.md b/courses/security/5-tswap/43-no-slippage-protection/+page.md index 2eb9b9fd5..b8654da37 100644 --- a/courses/security/5-tswap/43-no-slippage-protection/+page.md +++ b/courses/security/5-tswap/43-no-slippage-protection/+page.md @@ -46,7 +46,7 @@ Let's write up our second `high severity` finding! Compare your write up to mine **Description:** The `swapExactOutput` function does not include any sort of slippage protection. This function is similar to what is done in `TSwapPool::swapExactInput`, where the function specifies a `minOutputAmount`, the `swapExactOutput` function should specify a `maxInputAmount`. -**Impact:** If market conditions change before the transaciton processes, the user could get a much worse swap. +**Impact:** If market conditions change before the transaction processes, the user could get a much worse swap. **Proof of Concept:** diff --git a/courses/security/5-tswap/44-sell-pool-tokens-write-up/+page.md b/courses/security/5-tswap/44-sell-pool-tokens-write-up/+page.md index 81c03bc67..eefc7bdcc 100644 --- a/courses/security/5-tswap/44-sell-pool-tokens-write-up/+page.md +++ b/courses/security/5-tswap/44-sell-pool-tokens-write-up/+page.md @@ -35,11 +35,11 @@ Compare your finding write-up to mine below! Again, I'm leaving the PoC in your ### [H-4] `TSwapPool::sellPoolTokens` mismatches input and output tokens causing users to receive the incorrect amount of tokens -**Description:** The `sellPoolTokens` function is intended to allow users to easily sell pool tokens and receive WETH in exchange. Users indicate how many pool tokens they're willing to sell in the `poolTokenAmount` parameter. However, the function currently miscalculaes the swapped amount. +**Description:** The `sellPoolTokens` function is intended to allow users to easily sell pool tokens and receive WETH in exchange. Users indicate how many pool tokens they're willing to sell in the `poolTokenAmount` parameter. However, the function currently miscalculates the swapped amount. This is due to the fact that the `swapExactOutput` function is called, whereas the `swapExactInput` function is the one that should be called. Because users specify the exact amount of input tokens, not output. -**Impact:** Users will swap the wrong amount of tokens, which is a severe disruption of protcol functionality. +**Impact:** Users will swap the wrong amount of tokens, which is a severe disruption of protocol functionality. **Proof of Concept:** diff --git a/courses/security/5-tswap/45-invariant-break-write-up-and-poc/+page.md b/courses/security/5-tswap/45-invariant-break-write-up-and-poc/+page.md index 112ef9a2d..d1aa3d89f 100644 --- a/courses/security/5-tswap/45-invariant-break-write-up-and-poc/+page.md +++ b/courses/security/5-tswap/45-invariant-break-write-up-and-poc/+page.md @@ -96,7 +96,7 @@ function testInvariantBroken() public { } ``` -Our handler has an example we can now implement of a single swap being executed. Let's move that into our new unit test. Additionally, we can carry over our caculations for `endingX` and `actualDeltaX` as well as add our assert statement. +Our handler has an example we can now implement of a single swap being executed. Let's move that into our new unit test. Additionally, we can carry over our calculations for `endingX` and `actualDeltaX` as well as add our assert statement. > **Note:** `TSwapPool.t.sol` uses `user` instead of `swapper` as we have in our handler. @@ -212,7 +212,7 @@ Most simply put, the protocol's core invariant is broken. **Proof of Concept:** 1. A user swaps 10 times, and collects the extra incentive of `1_000_000_000_000_000_000` tokens -2. That user continues to swap untill all the protocol funds are drained +2. That user continues to swap until all the protocol funds are drained
Proof Of Code diff --git a/courses/security/5-tswap/46-writeup-weird-erc20/+page.md b/courses/security/5-tswap/46-writeup-weird-erc20/+page.md index 6e23bb647..838f85f89 100644 --- a/courses/security/5-tswap/46-writeup-weird-erc20/+page.md +++ b/courses/security/5-tswap/46-writeup-weird-erc20/+page.md @@ -14,19 +14,19 @@ There's a great repository of Weird ERC20 tokens available on GitHub [**here**]( We identified a `fee on transfer` issue within TSwapPool::\_swap that outlined a critical consideration - situations where extra tokens are sent will break the protocol invariant. Well, this can be the case with certain ERC20s (among other weird situations). -We saw an exampe of this when building our first stateful fuzz test suite where the YieldERC20 token was sending 10% of a transaction value as a fee every 10 transfers. +We saw an example of this when building our first stateful fuzz test suite where the YieldERC20 token was sending 10% of a transaction value as a fee every 10 transfers. ```js function statefulFuzz_testInvariantBreakHandler() public { vm.startPrank(owner); handlerStatefulFuzzCatches.withdrawToken(mockUSDC); - handlerStatefulFuzzCatches.withdrawToken(yeildERC20); + handlerStatefulFuzzCatches.withdrawToken(yieldERC20); vm.stopPrank(); assert(mockUSDC.balanceOf(address(handlerStatefulFuzzCatches)) == 0); - assert(yeildERC20.balanceOf(address(handlerStatefulFuzzCatches)) == 0); + assert(yieldERC20.balanceOf(address(handlerStatefulFuzzCatches)) == 0); assert(mockUSDC.balanceOf(owner) == startingAmount); - assert(yeildERC20.balanceOf(owner) == startingAmount); + assert(yieldERC20.balanceOf(owner) == startingAmount); } ``` diff --git a/courses/security/5-tswap/47-creating-pdf-for-your-portfolio/+page.md b/courses/security/5-tswap/47-creating-pdf-for-your-portfolio/+page.md index e2db5048c..38ed7bbf5 100644 --- a/courses/security/5-tswap/47-creating-pdf-for-your-portfolio/+page.md +++ b/courses/security/5-tswap/47-creating-pdf-for-your-portfolio/+page.md @@ -70,7 +70,7 @@ I've included a copy of my completed template here for reference if you get stuc - [Findings](#findings) - [High](#high) - [\[H-1\] `TSwapPool::deposit` is missing deadline check causing transactions to complete even after the deadline](#h-1-tswappooldeposit-is-missing-deadline-check-causing-transactions-to-complete-even-after-the-deadline) - - [\[H-2\] Incorrect fee calculation in `TSwapPool::getInputAmountBasedOnOutput` causes protocll to take too many tokens from users, resulting in lost fees](#h-2-incorrect-fee-calculation-in-tswappoolgetinputamountbasedonoutput-causes-protocll-to-take-too-many-tokens-from-users-resulting-in-lost-fees) + - [\[H-2\] Incorrect fee calculation in `TSwapPool::getInputAmountBasedOnOutput` causes protocol to take too many tokens from users, resulting in lost fees](#h-2-incorrect-fee-calculation-in-tswappoolgetinputamountbasedonoutput-causes-protocll-to-take-too-many-tokens-from-users-resulting-in-lost-fees) - [\[H-3\] Lack of slippage protection in `TSwapPool::swapExactOutput` causes users to potentially receive way fewer tokens](#h-3-lack-of-slippage-protection-in-tswappoolswapexactoutput-causes-users-to-potentially-receive-way-fewer-tokens) - [\[H-4\] `TSwapPool::sellPoolTokens` mismatches input and output tokens causing users to receive the incorrect amount of tokens](#h-4-tswappoolsellpooltokens-mismatches-input-and-output-tokens-causing-users-to-receive-the-incorrect-amount-of-tokens) - [\[H-5\] In `TSwapPool::_swap` the extra tokens given to users after every `swapCount` breaks the protocol invariant of `x * y = k`](#h-5-in-tswappool_swap-the-extra-tokens-given-to-users-after-every-swapcount-breaks-the-protocol-invariant-of-x--y--k) @@ -80,7 +80,7 @@ I've included a copy of my completed template here for reference if you get stuc - [Informationals](#informationals) - [\[I-1\] `PoolFactory::PoolFactory__PoolDoesNotExist` is not used and should be removed](#i-1-poolfactorypoolfactory__pooldoesnotexist-is-not-used-and-should-be-removed) - [\[I-2\] Lacking zero address checks](#i-2-lacking-zero-address-checks) - - [\[I-3\] `PoolFacotry::createPool` should use `.symbol()` instead of `.name()`](#i-3-poolfacotrycreatepool-should-use-symbol-instead-of-name) + - [\[I-3\] `PoolFactory::createPool` should use `.symbol()` instead of `.name()`](#i-3-poolfacotrycreatepool-should-use-symbol-instead-of-name) - [\[I-4\] Event is missing `indexed` fields](#i-4-event-is-missing-indexed-fields) # Protocol Summary @@ -108,7 +108,7 @@ I've included a copy of my completed template here for reference if you get stuc # Executive Summary ## Issues found - | Severtity | Number of issues found | + | Severity | Number of issues found | | --------- | ---------------------- | | High | 4 | | Medium | 2 | @@ -122,7 +122,7 @@ I've included a copy of my completed template here for reference if you get stuc ### [H-1] `TSwapPool::deposit` is missing deadline check causing transactions to complete even after the deadline - **Description:** The `deposit` function accepts a deadline parameter, which according to the documentation is "The deadline for the transaction to be completed by". However, this parameter is never used. As a consequence, operationrs that add liquidity to the pool might be executed at unexpected times, in market conditions where the deposit rate is unfavorable. + **Description:** The `deposit` function accepts a deadline parameter, which according to the documentation is "The deadline for the transaction to be completed by". However, this parameter is never used. As a consequence, operations that add liquidity to the pool might be executed at unexpected times, in market conditions where the deposit rate is unfavorable. @@ -146,7 +146,7 @@ I've included a copy of my completed template here for reference if you get stuc { ``` - ### [H-2] Incorrect fee calculation in `TSwapPool::getInputAmountBasedOnOutput` causes protocll to take too many tokens from users, resulting in lost fees + ### [H-2] Incorrect fee calculation in `TSwapPool::getInputAmountBasedOnOutput` causes protocol to take too many tokens from users, resulting in lost fees **Description:** The `getInputAmountBasedOnOutput` function is intended to calculate the amount of tokens a user should deposit given an amount of tokens of output tokens. However, the function currently miscalculates the resulting amount. When calculating the fee, it scales the amount by 10_000 instead of 1_000. @@ -175,7 +175,7 @@ I've included a copy of my completed template here for reference if you get stuc **Description:** The `swapExactOutput` function does not include any sort of slippage protection. This function is similar to what is done in `TSwapPool::swapExactInput`, where the function specifies a `minOutputAmount`, the `swapExactOutput` function should specify a `maxInputAmount`. - **Impact:** If market conditions change before the transaciton processes, the user could get a much worse swap. + **Impact:** If market conditions change before the transaction processes, the user could get a much worse swap. **Proof of Concept:** 1. The price of 1 WETH right now is 1,000 USDC @@ -206,11 +206,11 @@ I've included a copy of my completed template here for reference if you get stuc ### [H-4] `TSwapPool::sellPoolTokens` mismatches input and output tokens causing users to receive the incorrect amount of tokens - **Description:** The `sellPoolTokens` function is intended to allow users to easily sell pool tokens and receive WETH in exchange. Users indicate how many pool tokens they're willing to sell in the `poolTokenAmount` parameter. However, the function currently miscalculaes the swapped amount. + **Description:** The `sellPoolTokens` function is intended to allow users to easily sell pool tokens and receive WETH in exchange. Users indicate how many pool tokens they're willing to sell in the `poolTokenAmount` parameter. However, the function currently miscalculates the swapped amount. This is due to the fact that the `swapExactOutput` function is called, whereas the `swapExactInput` function is the one that should be called. Because users specify the exact amount of input tokens, not output. - **Impact:** Users will swap the wrong amount of tokens, which is a severe disruption of protcol functionality. + **Impact:** Users will swap the wrong amount of tokens, which is a severe disruption of protocol functionality. **Proof of Concept:** @@ -256,7 +256,7 @@ I've included a copy of my completed template here for reference if you get stuc **Proof of Concept:** 1. A user swaps 10 times, and collects the extra incentive of `1_000_000_000_000_000_000` tokens - 2. That user continues to swap untill all the protocol funds are drained + 2. That user continues to swap until all the protocol funds are drained
Proof Of Code @@ -329,7 +329,7 @@ I've included a copy of my completed template here for reference if you get stuc ### [L-2] Default value returned by `TSwapPool::swapExactInput` results in incorrect return value given - **Description:** The `swapExactInput` function is expected to return the actual amount of tokens bought by the caller. However, while it declares the named return value `ouput` it is never assigned a value, nor uses an explict return statement. + **Description:** The `swapExactInput` function is expected to return the actual amount of tokens bought by the caller. However, while it declares the named return value `output` it is never assigned a value, nor uses an explicit return statement. **Impact:** The return value will always be 0, giving incorrect information to the caller. @@ -373,7 +373,7 @@ I've included a copy of my completed template here for reference if you get stuc } ``` - ### [I-3] `PoolFacotry::createPool` should use `.symbol()` instead of `.name()` + ### [I-3] `PoolFactory::createPool` should use `.symbol()` instead of `.name()` ```diff - string memory liquidityTokenSymbol = string.concat("ts", IERC20(tokenAddress).name()); diff --git a/courses/security/5-tswap/48-recap/+page.md b/courses/security/5-tswap/48-recap/+page.md index bd386a13f..1e2efa609 100644 --- a/courses/security/5-tswap/48-recap/+page.md +++ b/courses/security/5-tswap/48-recap/+page.md @@ -10,7 +10,7 @@ It's been a journey, but let's do a quick recap of everything we've covered in t 1. Context & Understanding - Without much manual review, we were able to construct fuzzing test suites (both stateful and stateless) to indentify where these invariants were broken. + Without much manual review, we were able to construct fuzzing test suites (both stateful and stateless) to identify where these invariants were broken. We experienced first hand how efficient using of tooling and a proper understanding of a protocol can really assist in our reviews in this way. @@ -26,7 +26,7 @@ It's been a journey, but let's do a quick recap of everything we've covered in t 3. Liquidity Providers - `Liquidity Providers` add funds to liquidity pools to allow an `AMM` to fascilitate trades. We learnt that fees incured while trading on an `AMM` or `Dex` are used as incentive to pay liquidity providers based on their percentage contribution to the pool! + `Liquidity Providers` add funds to liquidity pools to allow an `AMM` to facilitate trades. We learnt that fees incurred while trading on an `AMM` or `Dex` are used as incentive to pay liquidity providers based on their percentage contribution to the pool! 4. Core Invariants & Constant Product Formula diff --git a/courses/security/5-tswap/49-exercises/+page.md b/courses/security/5-tswap/49-exercises/+page.md index efcbae9c5..1a2531819 100644 --- a/courses/security/5-tswap/49-exercises/+page.md +++ b/courses/security/5-tswap/49-exercises/+page.md @@ -4,7 +4,7 @@ title: Exercises --- -### Excercises +### Exercises Put your skills to the test in the exercises below. These extra challenges will help you write better tests and be a better security searcher. diff --git a/courses/security/5-tswap/9-invariant-and-properties-introduction/+page.md b/courses/security/5-tswap/9-invariant-and-properties-introduction/+page.md index 40a5676a7..2ac38808f 100644 --- a/courses/security/5-tswap/9-invariant-and-properties-introduction/+page.md +++ b/courses/security/5-tswap/9-invariant-and-properties-introduction/+page.md @@ -21,7 +21,7 @@ In TSwap, we're fortunate enough that the developers have provided us their core ``` ## Core Invariant -Our system works because the ratio of Token A & WETH will always stay the same. Well, for the most part. Since we add fees, our invariant technially increases. +Our system works because the ratio of Token A & WETH will always stay the same. Well, for the most part. Since we add fees, our invariant technically increases. `x * y = k` - x = Token Balance X diff --git a/courses/security/6-thunder-loan/10-recon-continued/+page.md b/courses/security/6-thunder-loan/10-recon-continued/+page.md index 93a9339f0..d2140d25d 100644 --- a/courses/security/6-thunder-loan/10-recon-continued/+page.md +++ b/courses/security/6-thunder-loan/10-recon-continued/+page.md @@ -38,7 +38,7 @@ The last thing I notice in the docs here is this: We are planning to upgrade from the current ThunderLoan contract to the ThunderLoanUpgraded contract. Please include this upgrade in scope of a security review. ``` -If we look at ThunderLoan.sol we can see that it's inheriting a bunch of upgradeablity libraries such as `Initializable`, `OwnableUpgradeable`, `UUPSUpgradeable`, and `OracleUpgradeable`. We aren't going to go over the specifics of upgradeability or proxy functionality, in this course (again you can find further information on that in [**Advanced Foundry**](https://updraft.cyfrin.io/courses/advanced-foundry)), but this is a vital consideration for our review moving forward and represents a whole host of unique attack vectors we haven't seen yet. +If we look at ThunderLoan.sol we can see that it's inheriting a bunch of upgradeability libraries such as `Initializable`, `OwnableUpgradeable`, `UUPSUpgradeable`, and `OracleUpgradeable`. We aren't going to go over the specifics of upgradeability or proxy functionality, in this course (again you can find further information on that in [**Advanced Foundry**](https://updraft.cyfrin.io/courses/advanced-foundry)), but this is a vital consideration for our review moving forward and represents a whole host of unique attack vectors we haven't seen yet. ### Wrap Up diff --git a/courses/security/6-thunder-loan/11-static-analysis-slither-aderyn/+page.md b/courses/security/6-thunder-loan/11-static-analysis-slither-aderyn/+page.md index a3112f7ec..99924220e 100644 --- a/courses/security/6-thunder-loan/11-static-analysis-slither-aderyn/+page.md +++ b/courses/security/6-thunder-loan/11-static-analysis-slither-aderyn/+page.md @@ -6,7 +6,7 @@ title: Static Analysis Slither + Aderyn ### Static Analysis Slither + Aderyn -Ok! We're ready to start attacking this code base and indentifying vulnerabilities. A good first step is our static analyzers of course. +Ok! We're ready to start attacking this code base and identifying vulnerabilities. A good first step is our static analyzers of course. ### Slither diff --git a/courses/security/6-thunder-loan/12-exploit-centralization/+page.md b/courses/security/6-thunder-loan/12-exploit-centralization/+page.md index 386a0381c..22f83d295 100644 --- a/courses/security/6-thunder-loan/12-exploit-centralization/+page.md +++ b/courses/security/6-thunder-loan/12-exploit-centralization/+page.md @@ -290,7 +290,7 @@ The first vulnerability identified is `## L-1: Centralization Risk for trusted o To be transparent, most of the time this is identified for a protocol, their response will be **_"that's a known issue"_**. Despite this, it's incumbent upon us, as good security researchers, to call this out when we see it. We do this, not least of which, to cover ourselves in the event that the protocol is a rug pull. -With that said, it looks like Thunder Loan has some priviledged access. We should take a look at the code to identify which powers and functions the owner has. +With that said, it looks like Thunder Loan has some privileged access. We should take a look at the code to identify which powers and functions the owner has. ``` setAllowedToken diff --git a/courses/security/6-thunder-loan/18-flashloan-receiver/+page.md b/courses/security/6-thunder-loan/18-flashloan-receiver/+page.md index 949241df1..10dd40b7d 100644 --- a/courses/security/6-thunder-loan/18-flashloan-receiver/+page.md +++ b/courses/security/6-thunder-loan/18-flashloan-receiver/+page.md @@ -41,7 +41,7 @@ We can check if the import is being inherited anywhere by searching our workspac It seems as though this import is only being used in one of Thunder Loan's mock files for testing. -This isn't a good practice, we're changing a live contract file solely to fascilitate testing. Our test should be importing it's own instance of this interface if it's needed. +This isn't a good practice, we're changing a live contract file solely to facilitate testing. Our test should be importing it's own instance of this interface if it's needed. ```js import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/courses/security/6-thunder-loan/19-oracle-upgradeable/+page.md b/courses/security/6-thunder-loan/19-oracle-upgradeable/+page.md index cde58d7f9..90ccf5c93 100644 --- a/courses/security/6-thunder-loan/19-oracle-upgradeable/+page.md +++ b/courses/security/6-thunder-loan/19-oracle-upgradeable/+page.md @@ -83,7 +83,7 @@ Logic -> Implementation So if our constructor does something with storage, such as initializing a variable, it's not going to matter! `Initializable.sol` assists in initializing proxies with storage. -It does these through `initializer` functions which can often be identified by the naming convensions `__init` and `__init_unchained`. We can see these function implemented within `OracleUpgradeable.sol` +It does these through `initializer` functions which can often be identified by the naming conventions `__init` and `__init_unchained`. We can see these function implemented within `OracleUpgradeable.sol` ```js function __Oracle_init(address poolFactoryAddress) internal onlyInitializing { diff --git a/courses/security/6-thunder-loan/2-phase-1-scoping/+page.md b/courses/security/6-thunder-loan/2-phase-1-scoping/+page.md index 37d960549..5480406ea 100644 --- a/courses/security/6-thunder-loan/2-phase-1-scoping/+page.md +++ b/courses/security/6-thunder-loan/2-phase-1-scoping/+page.md @@ -45,7 +45,7 @@ The protocol has also provided us a clear detailing of chains and tokens with wh Knowing which tokens are used allows us to filter out considerations of Weird ERC20s etc making our jobs easier! -Within the `Roles` section of the README, we see some familiar terms. Knowing which actors are capable of what actions in a protocol is another interal piece of information in this process. +Within the `Roles` section of the README, we see some familiar terms. Knowing which actors are capable of what actions in a protocol is another internal piece of information in this process. ``` ## Roles diff --git a/courses/security/6-thunder-loan/20-failure-to-initialize/+page.md b/courses/security/6-thunder-loan/20-failure-to-initialize/+page.md index 8afd31186..7be81d3d9 100644 --- a/courses/security/6-thunder-loan/20-failure-to-initialize/+page.md +++ b/courses/security/6-thunder-loan/20-failure-to-initialize/+page.md @@ -12,10 +12,10 @@ With the context of proxies and the use of initializers understood, the first qu If a protocol fails to initialize a value, it could potentially have dire consequences. -Even though this is technically a vulnerability in ThunderLoan.sol, and we're jumping place a little bit. Let's head there and make a note of things as well as definte what this potential exploit looks line this this code base. +Even though this is technically a vulnerability in ThunderLoan.sol, and we're jumping place a little bit. Let's head there and make a note of things as well as definite what this potential exploit looks line this this code base. ```js -// Audit-Low: Intializer can be front-run +// Audit-Low: Initializer can be front-run function initialize(address tswapAddress) external initializer { __Ownable_init(msg.sender); __UUPSUpgradeable_init(); diff --git a/courses/security/6-thunder-loan/21-failure-to-initialize-remix/+page.md b/courses/security/6-thunder-loan/21-failure-to-initialize-remix/+page.md index 7544382d2..6cb52a51e 100644 --- a/courses/security/6-thunder-loan/21-failure-to-initialize-remix/+page.md +++ b/courses/security/6-thunder-loan/21-failure-to-initialize-remix/+page.md @@ -40,7 +40,7 @@ The example here is very simple, but it should illustrate the potential impact o ::image{src='/security-section-6/21-failure-to-initialize-remix/failure-to-initialize-remix1.png' style='width: 100%; height: auto;'} -You should see it begin unitialized with `myValue` set to zero. If the protocol then proceeds to be used (by calling `increment`), the `initialize` function can be called at any time to overwrite the expected `myValue`. +You should see it begin initialized with `myValue` set to zero. If the protocol then proceeds to be used (by calling `increment`), the `initialize` function can be called at any time to overwrite the expected `myValue`. ::image{src='/security-section-6/21-failure-to-initialize-remix/failure-to-initialize-remix2.png' style='width: 100%; height: auto;'} diff --git a/courses/security/6-thunder-loan/23-oracleupgradeable-continued/+page.md b/courses/security/6-thunder-loan/23-oracleupgradeable-continued/+page.md index ac93115ef..c130e2234 100644 --- a/courses/security/6-thunder-loan/23-oracleupgradeable-continued/+page.md +++ b/courses/security/6-thunder-loan/23-oracleupgradeable-continued/+page.md @@ -94,7 +94,7 @@ These are pretty basic getters. The `getPrice` function is a little redundant wi ### Wrap Up -Awesome! We've finished our recon of `OracleUpgradeable.sol`! That's one more contract checked off our first pass list. We managed to find a low severity bug in our risks associated with intializion and we asked lots of good follow up questions to come back to for the `getPriceInWeth` function. +Awesome! We've finished our recon of `OracleUpgradeable.sol`! That's one more contract checked off our first pass list. We managed to find a low severity bug in our risks associated with initialization and we asked lots of good follow up questions to come back to for the `getPriceInWeth` function. Let's mark this first pass done for now and move on to `AssetToken.sol` in the next lesson! diff --git a/courses/security/6-thunder-loan/24-assettoken/+page.md b/courses/security/6-thunder-loan/24-assettoken/+page.md index e61119200..7444d4127 100644 --- a/courses/security/6-thunder-loan/24-assettoken/+page.md +++ b/courses/security/6-thunder-loan/24-assettoken/+page.md @@ -4,7 +4,7 @@ title: AssetToken.sol ### AssetToken.sol -As we progress with tincho method the order we assess things we become less and less important. As the contracts get bigger they're going to start relying on eachother a lot and we may starting bouncing back and forth. +As we progress with tincho method the order we assess things we become less and less important. As the contracts get bigger they're going to start relying on each other a lot and we may starting bouncing back and forth. For example, we know the `ThunderLoanUpgraded.sol` contract is _smaller_ but it's also the _upgrade_ to `ThunderLoan.sol`, so it's a good idea to start with `ThunderLoan.sol` for context. @@ -23,7 +23,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s contract AssetToken is ERC20 { error AssetToken__onlyThunderLoan(); - error AssetToken__ExhangeRateCanOnlyIncrease(uint256 oldExchangeRate, uint256 newExchangeRate); + error AssetToken__ExchangeRateCanOnlyIncrease(uint256 oldExchangeRate, uint256 newExchangeRate); error AssetToken__ZeroAddress(); using SafeERC20 for IERC20; @@ -105,7 +105,7 @@ contract AssetToken is ERC20 { uint256 newExchangeRate = s_exchangeRate * (totalSupply() + fee) / totalSupply(); if (newExchangeRate <= s_exchangeRate) { - revert AssetToken__ExhangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); + revert AssetToken__ExchangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); } s_exchangeRate = newExchangeRate; emit ExchangeRateUpdated(s_exchangeRate); @@ -168,7 +168,7 @@ The comments left for some of our variables may be a little confusing at first g ```js error AssetToken__onlyThunderLoan(); -error AssetToken__ExhangeRateCanOnlyIncrease(uint256 oldExchangeRate, uint256 newExchangeRate); +error AssetToken__ExchangeRateCanOnlyIncrease(uint256 oldExchangeRate, uint256 newExchangeRate); error AssetToken__ZeroAddress(); using SafeERC20 for IERC20; @@ -190,7 +190,7 @@ When the protocol mentions `underlying` it's referring to the asset which is rep You can note that this exchange rate mechanism is distinct from a percentage share of a liquidity pool which we outlined earlier in TSwap. The exchange rate in this instance functions a lot like [**Compound Finance**](https://github.com/compound-finance/) (I'm secretly teaching you compound finance) and how their [**CToken**](https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol) works. -This may even be a point in a review where I would go on a side quest to better understand Compound and how it influenced the development of `ThunderLoan`. We aren't going to go on this tangeant here together, but I encourage you to become familiar with some of these DeFi protocols we touch on as the context and experience will go a long way in your future security reviews. +This may even be a point in a review where I would go on a side quest to better understand Compound and how it influenced the development of `ThunderLoan`. We aren't going to go on this tangent here together, but I encourage you to become familiar with some of these DeFi protocols we touch on as the context and experience will go a long way in your future security reviews. ### Modifiers diff --git a/courses/security/6-thunder-loan/25-asset-token-update-exchange-rate/+page.md b/courses/security/6-thunder-loan/25-asset-token-update-exchange-rate/+page.md index 1346239f8..23bea5fbd 100644 --- a/courses/security/6-thunder-loan/25-asset-token-update-exchange-rate/+page.md +++ b/courses/security/6-thunder-loan/25-asset-token-update-exchange-rate/+page.md @@ -19,7 +19,7 @@ function updateExchangeRate(uint256 fee) external onlyThunderLoan { uint256 newExchangeRate = s_exchangeRate * (totalSupply() + fee) / totalSupply(); if (newExchangeRate <= s_exchangeRate) { - revert AssetToken__ExhangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); + revert AssetToken__ExchangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); } s_exchangeRate = newExchangeRate; emit ExchangeRateUpdated(s_exchangeRate); @@ -43,11 +43,11 @@ The next bit of code is actually pretty clever. ```js if (newExchangeRate <= s_exchangeRate) { - revert AssetToken__ExhangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); + revert AssetToken__ExchangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); } ``` -This is explicitly checking for the invariant mentioned in the function comments. If the newExchangeRate is less than or equal to the old exchange rate, we revert with a custom error `AssetToken__ExhangeRateCanOnlyIncrease`. +This is explicitly checking for the invariant mentioned in the function comments. If the newExchangeRate is less than or equal to the old exchange rate, we revert with a custom error `AssetToken__ExchangeRateCanOnlyIncrease`. Then we're updating the exchange rate and emitting an event. diff --git a/courses/security/6-thunder-loan/26-thunderloan-starting-at-the-top/+page.md b/courses/security/6-thunder-loan/26-thunderloan-starting-at-the-top/+page.md index 99ce5645b..11a13fbbd 100644 --- a/courses/security/6-thunder-loan/26-thunderloan-starting-at-the-top/+page.md +++ b/courses/security/6-thunder-loan/26-thunderloan-starting-at-the-top/+page.md @@ -93,7 +93,7 @@ contract ThunderLoan is Initializable, OwnableUpgradeable, UUPSUpgradeable, Orac error ThunderLoan__NotEnoughTokenBalance(uint256 startingBalance, uint256 amount); error ThunderLoan__CallerIsNotContract(); error ThunderLoan__AlreadyAllowed(); - error ThunderLoan__ExhangeRateCanOnlyIncrease(); + error ThunderLoan__ExchangeRateCanOnlyIncrease(); error ThunderLoan__NotCurrentlyFlashLoaning(); error ThunderLoan__BadNewFee(); @@ -327,7 +327,7 @@ import { IFlashLoanReceiver } from "../interfaces/IFlashLoanReceiver.sol"; These look pretty standard though a few imports may stand out or be unfamiliar so far such as [**OwnableUpgradeable**](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/access/OwnableUpgradeable.sol) which serves as an upgradeable variation of the famous ownable library. We may also want to gain more familiarity with: - [**UUPSUpgradeable**](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol) - UUPS proxy patter covered in the [**Foundry Full Course**](https://updraft.cyfrin.io/courses/advanced-foundry). A very common smart contract proxy pattern. -- [**Address**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol) - Library to simplfy the handling of Address functionality. +- [**Address**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol) - Library to simplify the handling of Address functionality. I recommend taking the time to read up on these in more detail. diff --git a/courses/security/6-thunder-loan/27-thunderloan-functions/+page.md b/courses/security/6-thunder-loan/27-thunderloan-functions/+page.md index 40d9f8026..87cd8d0dd 100644 --- a/courses/security/6-thunder-loan/27-thunderloan-functions/+page.md +++ b/courses/security/6-thunder-loan/27-thunderloan-functions/+page.md @@ -91,7 +91,7 @@ contract ThunderLoan is Initializable, OwnableUpgradeable, UUPSUpgradeable, Orac error ThunderLoan__NotEnoughTokenBalance(uint256 startingBalance, uint256 amount); error ThunderLoan__CallerIsNotContract(); error ThunderLoan__AlreadyAllowed(); - error ThunderLoan__ExhangeRateCanOnlyIncrease(); + error ThunderLoan__ExchangeRateCanOnlyIncrease(); error ThunderLoan__NotCurrentlyFlashLoaning(); error ThunderLoan__BadNewFee(); diff --git a/courses/security/6-thunder-loan/29-note-on-linear-progress/+page.md b/courses/security/6-thunder-loan/29-note-on-linear-progress/+page.md index 172f74269..158be10d9 100644 --- a/courses/security/6-thunder-loan/29-note-on-linear-progress/+page.md +++ b/courses/security/6-thunder-loan/29-note-on-linear-progress/+page.md @@ -14,6 +14,6 @@ What I mean by this is, we've assessed much of this code base so far already and It's far more likely for security researchers to uncover the majority of their bugs nearing the end of their review when the greatest context and understanding of the protocol is achieved. It's not uncommon for the discovery of one vulnerability to snowball into exploits elsewhere and the process can become exponential. -Ultimately, don't be discouraged if you don't find anything immediately, perseverence is key! +Ultimately, don't be discouraged if you don't find anything immediately, perseverance is key! Let's keep going! diff --git a/courses/security/6-thunder-loan/3-reading-the-docs/+page.md b/courses/security/6-thunder-loan/3-reading-the-docs/+page.md index 9a0fe430e..5efcb4e31 100644 --- a/courses/security/6-thunder-loan/3-reading-the-docs/+page.md +++ b/courses/security/6-thunder-loan/3-reading-the-docs/+page.md @@ -14,7 +14,7 @@ The README has more contextual information about the project that we should take If we're unfamiliar with Aave, we're even directed to a [**short explainer video**](https://www.youtube.com/watch?v=dTCwssZ116A) by Whiteboard Crypto that I encourage you to take a moment to watch for a high-level understanding of things. -We'll be doing a much more comprehesive dive into these DeFi systems in this section of course! It's just good to be prepared. +We'll be doing a much more comprehensive dive into these DeFi systems in this section of course! It's just good to be prepared. ### About Section diff --git a/courses/security/6-thunder-loan/30-thunderloan-continued/+page.md b/courses/security/6-thunder-loan/30-thunderloan-continued/+page.md index 704735395..42261b4c9 100644 --- a/courses/security/6-thunder-loan/30-thunderloan-continued/+page.md +++ b/courses/security/6-thunder-loan/30-thunderloan-continued/+page.md @@ -25,7 +25,7 @@ function deposit(IERC20 token, uint256 amount) external revertIfZero(amount) rev
-The first thing the `deposit` function does is leverage the `s_tokenToAssetToken` mapping to acquire the `AssetToken` paired with the passed token parameter. Remember, these `asset tokens` ultimately represent how much of the pool the depositer owns as a result of their deposits. +The first thing the `deposit` function does is leverage the `s_tokenToAssetToken` mapping to acquire the `AssetToken` paired with the passed token parameter. Remember, these `asset tokens` ultimately represent how much of the pool the depositor owns as a result of their deposits. The function then needs to know how many asset tokens to mint as a result of the amount of tokens being deposited. To accomplish this we're using the `getExchangeRate` function, which we know from earlier is returning the ratio between the asset tokens and their underlying. We then use the exchangeRate to do a bit of math. @@ -80,7 +80,7 @@ function getCalculatedFee(IERC20 token, uint256 amount) public view returns (uin // @Audit-Informational: Function missing NATSPEC! ``` -Without any explicit comments we're left to speculate, but something here seems wrong. If this function is caculating the flash loan fee, I'm left with a bunch of questions.. +Without any explicit comments we're left to speculate, but something here seems wrong. If this function is calculating the flash loan fee, I'm left with a bunch of questions.. **_Why are we calculating this fee during deposit?_** diff --git a/courses/security/6-thunder-loan/32-thunderloan-redeem/+page.md b/courses/security/6-thunder-loan/32-thunderloan-redeem/+page.md index 8fcfdec53..465dbaaad 100644 --- a/courses/security/6-thunder-loan/32-thunderloan-redeem/+page.md +++ b/courses/security/6-thunder-loan/32-thunderloan-redeem/+page.md @@ -38,7 +38,7 @@ function redeem( We would expect this function to behave in opposite to the `deposit` function. Thankfully we have `NATSPEC` this time to verify the function's intent! -Two modifiers can be seen in `redeem`, `revertIfZero(amountOfAssetToken)` and `reverIfNotAllowedToken(token)`. This clarifies somewhat that the token parameter being passed to this function is intended to be the underlying `token`, not the `asset token`. +Two modifiers can be seen in `redeem`, `revertIfZero(amountOfAssetToken)` and `revertIfNotAllowedToken(token)`. This clarifies somewhat that the token parameter being passed to this function is intended to be the underlying `token`, not the `asset token`. ```js revertIfZero(amountOfAssetToken); diff --git a/courses/security/6-thunder-loan/33-thunderloan-flashloan/+page.md b/courses/security/6-thunder-loan/33-thunderloan-flashloan/+page.md index 44f11ab29..fc4592453 100644 --- a/courses/security/6-thunder-loan/33-thunderloan-flashloan/+page.md +++ b/courses/security/6-thunder-loan/33-thunderloan-flashloan/+page.md @@ -124,7 +124,7 @@ function updateExchangeRate(uint256 fee) external onlyThunderLoan { uint256 newExchangeRate = s_exchangeRate * (totalSupply() + fee) / totalSupply(); if (newExchangeRate <= s_exchangeRate) { - revert AssetToken__ExhangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); + revert AssetToken__ExchangeRateCanOnlyIncrease(s_exchangeRate, newExchangeRate); } s_exchangeRate = newExchangeRate; emit ExchangeRateUpdated(s_exchangeRate); diff --git a/courses/security/6-thunder-loan/34-note-on-being-discouraged/+page.md b/courses/security/6-thunder-loan/34-note-on-being-discouraged/+page.md index d8d1fe52a..f28579686 100644 --- a/courses/security/6-thunder-loan/34-note-on-being-discouraged/+page.md +++ b/courses/security/6-thunder-loan/34-note-on-being-discouraged/+page.md @@ -18,6 +18,6 @@ _Follow along with the video lesson:_ Having just gone through one of the major functions in Thunder Loan, and still finding nothing juicy, we may start to feel discouraged again. -I can't stress enough that reviews are not linear. We still have a tonne of unanswered questions and the trick really is perseverence. +I can't stress enough that reviews are not linear. We still have a tonne of unanswered questions and the trick really is perseverance. Let's keep going. diff --git a/courses/security/6-thunder-loan/35-thunderloan-repay-final-functions/+page.md b/courses/security/6-thunder-loan/35-thunderloan-repay-final-functions/+page.md index ad3e6ad10..26ff89990 100644 --- a/courses/security/6-thunder-loan/35-thunderloan-repay-final-functions/+page.md +++ b/courses/security/6-thunder-loan/35-thunderloan-repay-final-functions/+page.md @@ -21,7 +21,7 @@ function repay(IERC20 token, uint256 amount) public { } ``` -`repay`, in this circumstance, serves as a helper function more than anything. A user taking a flash loan could also just call `transfer`, in their `executeOperations` functionm, to return the borrowed funds, but this exists to make things a little easier. Repay performs a check to assure a token is in the `currentlyFlashLoaning` state before performing any transfers. +`repay`, in this circumstance, serves as a helper function more than anything. A user taking a flash loan could also just call `transfer`, in their `executeOperations` function, to return the borrowed funds, but this exists to make things a little easier. Repay performs a check to assure a token is in the `currentlyFlashLoaning` state before performing any transfers. Moving on! @@ -39,7 +39,7 @@ function getCalculatedFee(IERC20 token, uint256 amount) public view returns (uin - **token** - token being borrowed - **amount** - amount being borrowed -This function is calling `getPriceInWeth` (inherited from `OracleUpgrableable.sol`), and if we swing back to that contract some additional pieces will fall into play for us. +This function is calling `getPriceInWeth` (inherited from `OracleUpgradeable.sol`), and if we swing back to that contract some additional pieces will fall into play for us. ```js function getPriceInWeth(address token) public view returns (uint256) { diff --git a/courses/security/6-thunder-loan/36-answering-our-questions/+page.md b/courses/security/6-thunder-loan/36-answering-our-questions/+page.md index 027699d94..ca4cebcee 100644 --- a/courses/security/6-thunder-loan/36-answering-our-questions/+page.md +++ b/courses/security/6-thunder-loan/36-answering-our-questions/+page.md @@ -19,7 +19,7 @@ Some of these questions may seem obvious now that we have a much deeper understa We know this one! -**Answer:** TSwap is being used to get the value of a token to calculate floan loan fees! +**Answer:** TSwap is being used to get the value of a token to calculate flash loan fees! ```js // ITSwapPool.sol diff --git a/courses/security/6-thunder-loan/37-improving-test-coverage-to-find-a-high/+page.md b/courses/security/6-thunder-loan/37-improving-test-coverage-to-find-a-high/+page.md index 916d534ef..617356c7a 100644 --- a/courses/security/6-thunder-loan/37-improving-test-coverage-to-find-a-high/+page.md +++ b/courses/security/6-thunder-loan/37-improving-test-coverage-to-find-a-high/+page.md @@ -17,7 +17,7 @@ uint256 calculatedFee = getCalculatedFee(token, amount); assetToken.updateExchangeRate(calculatedFee); ``` -Our review has taught us that `updateExchangeRate` is effectively keeping track of the ratio of `underlying` and `asset tokens`. If the `deposit` function isn't acruing any fees, it doesn't really make sense to be updating this value here... +Our review has taught us that `updateExchangeRate` is effectively keeping track of the ratio of `underlying` and `asset tokens`. If the `deposit` function isn't accruing any fees, it doesn't really make sense to be updating this value here... We need to write some tests. diff --git a/courses/security/6-thunder-loan/39-exploit-oracle-manipulation-minimized/+page.md b/courses/security/6-thunder-loan/39-exploit-oracle-manipulation-minimized/+page.md index 5feb5c729..53493a41a 100644 --- a/courses/security/6-thunder-loan/39-exploit-oracle-manipulation-minimized/+page.md +++ b/courses/security/6-thunder-loan/39-exploit-oracle-manipulation-minimized/+page.md @@ -37,7 +37,7 @@ In the diagram above, we can see that an interaction with TSwap is being used to The profit of course is used to then repay the flashloan. -It's the NFT Protocol's reliance on a Dex like TSwap as an oracle that leads to a vulnerabilitiy like this! +It's the NFT Protocol's reliance on a Dex like TSwap as an oracle that leads to a vulnerability like this! > **Note:** The Diagram is simplified, there are other considerations not accounted for such as slippage, the weth spent on the NFT etc, but the concept is the same. diff --git a/courses/security/6-thunder-loan/4-what-is-flash-loan/+page.md b/courses/security/6-thunder-loan/4-what-is-flash-loan/+page.md index 8dfad586b..8498ad62f 100644 --- a/courses/security/6-thunder-loan/4-what-is-flash-loan/+page.md +++ b/courses/security/6-thunder-loan/4-what-is-flash-loan/+page.md @@ -18,7 +18,7 @@ You could buy one Ethereum at DEX A for $5, then head over to DEX B and sell tha Imagine if this situation were to scale up, and you were able to buy 10, 100 or 1000 ETH. The problem lies in the average person's ability to shoulder the upfront investment. -In contemporay finance opportunities like I've outlined above could only maximally be taken advantage of by `whales` aka the incredibly wealthy. +In contemporary finance opportunities like I've outlined above could only maximally be taken advantage of by `whales` aka the incredibly wealthy. This is where flash loans come in to level the playing field in DeFi by giving any user access to much more liquidity - for a single transaction. diff --git a/courses/security/6-thunder-loan/40-exploit-oracle-manipulation-thunderloan-poc/+page.md b/courses/security/6-thunder-loan/40-exploit-oracle-manipulation-thunderloan-poc/+page.md index c09c13890..714ca8c0c 100644 --- a/courses/security/6-thunder-loan/40-exploit-oracle-manipulation-thunderloan-poc/+page.md +++ b/courses/security/6-thunder-loan/40-exploit-oracle-manipulation-thunderloan-poc/+page.md @@ -209,7 +209,7 @@ contract MaliciousFlashLoanReceiver is IFlashLoanReceiver { } ``` -The function call triggered in our receiver, by the flashloan execution, necessitates that our receiver contract contains an executeOperation function. It's within this function that we need to perfom all of our actions with the loan. We're going to need to: +The function call triggered in our receiver, by the flashloan execution, necessitates that our receiver contract contains an executeOperation function. It's within this function that we need to perform all of our actions with the loan. We're going to need to: - swap borrowed TokenA for WETH - Take out a second loan to compare fees to @@ -226,7 +226,7 @@ function executeOperation( uint256 amount, uint256 fee, address,/*initiator*/ - butes calldata /*params*/ + bytes calldata /*params*/ ) external returns(bool) { if(!attacked){ diff --git a/courses/security/6-thunder-loan/41-oracle-manipulation-recap/+page.md b/courses/security/6-thunder-loan/41-oracle-manipulation-recap/+page.md index e60a8ba86..e643af7b1 100644 --- a/courses/security/6-thunder-loan/41-oracle-manipulation-recap/+page.md +++ b/courses/security/6-thunder-loan/41-oracle-manipulation-recap/+page.md @@ -36,7 +36,7 @@ Finally, we covered how flash loans and the impact they have on Dex prices of as Flash Loans have the potential of drastically altering the ratio based pricing of asset pairs on Dexs by affording a user the ability to swap huge numbers of a token and tanking it's price - for that transaction. -The practical offshoot of this is that any protocol that reads from that Dex is going to trust this inaccurate, temporarly price, leaving itself open to exploitation or unfavorable transactions. +The practical offshoot of this is that any protocol that reads from that Dex is going to trust this inaccurate, temporary price, leaving itself open to exploitation or unfavorable transactions. ### Thunder Loan Oracle Manipulation diff --git a/courses/security/6-thunder-loan/42-exploit-deposit-instead-of-repay/+page.md b/courses/security/6-thunder-loan/42-exploit-deposit-instead-of-repay/+page.md index f2e30e92b..101d68941 100644 --- a/courses/security/6-thunder-loan/42-exploit-deposit-instead-of-repay/+page.md +++ b/courses/security/6-thunder-loan/42-exploit-deposit-instead-of-repay/+page.md @@ -83,7 +83,7 @@ If I deposit the tokens, I should be able to redeem them later. This could cause ### Repayment Backdoor -Moving back to ThunderLoanTest.t.sol, we can add a test to our suite to see how ThunderLoan reacts if a flashload is repaid with the deposit function. +Moving back to ThunderLoanTest.t.sol, we can add a test to our suite to see how ThunderLoan reacts if a flashloan is repaid with the deposit function. We know that the flash loan receiver needs to be a smart contract, because of this we'll need to set up a simple malicious contract with our `deposit instead of repay` login in its executeOperation function. Stripped down, it should look something like this: @@ -113,7 +113,7 @@ contract DepositOverRepay is IFlashLoanReceiver { } ``` -For this attack to work we need to deposit the funds we've borrowed back into ThunderLoan (as well as the expected fee). This, if we're right, will clear the flash loan and allow us to redeem the amount of the loan, stealing the funds permenantly! +For this attack to work we need to deposit the funds we've borrowed back into ThunderLoan (as well as the expected fee). This, if we're right, will clear the flash loan and allow us to redeem the amount of the loan, stealing the funds permanently! ```js function executeOperation( diff --git a/courses/security/6-thunder-loan/45-exploit-storage-collision-remix-examplee/+page.md b/courses/security/6-thunder-loan/45-exploit-storage-collision-remix-examplee/+page.md index caa00e1a1..331e7ed32 100644 --- a/courses/security/6-thunder-loan/45-exploit-storage-collision-remix-examplee/+page.md +++ b/courses/security/6-thunder-loan/45-exploit-storage-collision-remix-examplee/+page.md @@ -45,9 +45,9 @@ contract StorageCollisionProxy is Proxy { return abi.encodeWithSignature("setValue(uint256)", numberToUpdate); } - function readStorage(uint256 storageSlot) public view returns (uint256 vauleAtStorageSlot) { + function readStorage(uint256 storageSlot) public view returns (uint256 valueAtStorageSlot) { assembly { - vauleAtStorageSlot := sload(storageSlot) + valueAtStorageSlot := sload(storageSlot) } } @@ -126,7 +126,7 @@ contract ImplementationB { uint256 public value; ``` -This means, when we're checking our `intialized` value, storage slot 0 of our proxy is being referenced...but slot 0 isn't empty! Slot 0 contains the value we set from a previous implementation, which means `initialized` reads true! +This means, when we're checking our `initialized` value, storage slot 0 of our proxy is being referenced...but slot 0 isn't empty! Slot 0 contains the value we set from a previous implementation, which means `initialized` reads true! We can confirm this by interacting with our StorageCollisionProxy contract and calling `readStorage` and passing our storage slot. diff --git a/courses/security/6-thunder-loan/47-exploit-storage-collision-write-up/+page.md b/courses/security/6-thunder-loan/47-exploit-storage-collision-write-up/+page.md index 2b9110c7c..b8fdb96b8 100644 --- a/courses/security/6-thunder-loan/47-exploit-storage-collision-write-up/+page.md +++ b/courses/security/6-thunder-loan/47-exploit-storage-collision-write-up/+page.md @@ -37,7 +37,7 @@ What's the severity of our storage collision vulnerability? There may be argument for this to be a medium, but given the impact in `ThunderLoan`, I'm going to stick with my assessment of `high severity`. -Our title is actually going to idenfity an impact we didn't even go over together, but this storage collision actually affects more than the fee variable. We have to remember that changing how many storage slots are used may impact any assignment that comes later in the 'array'! +Our title is actually going to identify an impact we didn't even go over together, but this storage collision actually affects more than the fee variable. We have to remember that changing how many storage slots are used may impact any assignment that comes later in the 'array'! In the case of ThunderLoan and significant affect of this is that the `s_currentlyFlashloaning` mapping is impacted, which freezes the protocol entirely. diff --git a/courses/security/6-thunder-loan/48-wrapping-up/+page.md b/courses/security/6-thunder-loan/48-wrapping-up/+page.md index 89fcfeb92..60b3eb010 100644 --- a/courses/security/6-thunder-loan/48-wrapping-up/+page.md +++ b/courses/security/6-thunder-loan/48-wrapping-up/+page.md @@ -14,7 +14,7 @@ Remember, you can always reference the audit-data branch of the ThunderLoan repo Customize the report to your liking, but _do not_ skip this step. **_Actually_** create this report. -It's only through repetition that you'll build familiarity and get really good at these things, and you'll have a bad-ass new audit to add to your porfolio. +It's only through repetition that you'll build familiarity and get really good at these things, and you'll have a bad-ass new audit to add to your portfolio. ### First Flights diff --git a/courses/security/6-thunder-loan/49-section-6-recap/+page.md b/courses/security/6-thunder-loan/49-section-6-recap/+page.md index 6156b985c..7b66bbc68 100644 --- a/courses/security/6-thunder-loan/49-section-6-recap/+page.md +++ b/courses/security/6-thunder-loan/49-section-6-recap/+page.md @@ -26,7 +26,7 @@ We also learnt the value of pursuing knowledge of popular existing protocols. Ha We were exposed to a whole new batch of vulnerabilities which include: -- **Failure to Initialize** - as showcased by the Parity Wallet case study as well as our [**Remix example**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/failure-to-initialize/FailureToInitialize.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js). Failure to initialize a protocol leaves it open to these values being initialize at an unexpected time, resulting in unintented protocol behaviour. +- **Failure to Initialize** - as showcased by the Parity Wallet case study as well as our [**Remix example**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/failure-to-initialize/FailureToInitialize.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js). Failure to initialize a protocol leaves it open to these values being initialize at an unexpected time, resulting in unintended protocol behaviour. - **Storage Collision** - we saw first had, through PoCs and [**Remix examples**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/storage-collision/StorageCollision.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js) how altering storage slot assignments during a protocol upgrade can have dire implications. - **Oracle & Price Manipulation** - Using an AMM as an oracle can have unintended consequences with respect to asset price feeds. Dexs/AMMs are susceptible to having their prices manipulated via swaps on the platform. A decentralized oracle like a [**Chainlink Price Feed**](https://data.chain.link/) is a more secure route. @@ -38,7 +38,7 @@ We also learnt about risks associated with using proxies both with regards to pr Something we didn't actually touch on, but I _do_ want to mention briefly, is the concept of `malicious scope`. -It may be the case that a protocol approaches you for an audit and they provide you scope, but intentially leave malicious code _outside of scope_ - try your best to sniff these out. +It may be the case that a protocol approaches you for an audit and they provide you scope, but intentionally leave malicious code _outside of scope_ - try your best to sniff these out. Protocols that you audit resulting in rug pulls is going to look bad on you, so defend yourself and be cautious! diff --git a/courses/security/6-thunder-loan/6-liquidity-providers/+page.md b/courses/security/6-thunder-loan/6-liquidity-providers/+page.md index 15c38c04d..939bb8ff5 100644 --- a/courses/security/6-thunder-loan/6-liquidity-providers/+page.md +++ b/courses/security/6-thunder-loan/6-liquidity-providers/+page.md @@ -14,6 +14,6 @@ The answer is a familiar one - `Liquidity Providers`! Much like we saw in `TSwap`, where a `Liquidity Provider` would deposit funds into a pool to earn fees, the same takes place with `flash loans`. -A `Liquidity Provider` would deposit funds into a `flash loan` protocol, receiving some form of LP Token representative of their contribution. The `flash loan` protocol then acrues fees as people use `flash loans`, which increases the value of a `Liquidity Provider`'s representative allotment of the pool. +A `Liquidity Provider` would deposit funds into a `flash loan` protocol, receiving some form of LP Token representative of their contribution. The `flash loan` protocol then accrues fees as people use `flash loans`, which increases the value of a `Liquidity Provider`'s representative allotment of the pool. ::image{src='/security-section-6/6-liquidity-providers/liquidity-providers1.png' style='width: 100%; height: auto;'} diff --git a/courses/security/6-thunder-loan/8-are-flash-loans-bad/+page.md b/courses/security/6-thunder-loan/8-are-flash-loans-bad/+page.md index d9d22eec3..f4e8961a5 100644 --- a/courses/security/6-thunder-loan/8-are-flash-loans-bad/+page.md +++ b/courses/security/6-thunder-loan/8-are-flash-loans-bad/+page.md @@ -10,6 +10,6 @@ There are some in Web3 who view Flash Loans as being a _negative_ in the space, Personally, I don't agree. I see flash loans as a leveler, allowing anyone to be a "whale" for a single transaction. -In contemporay finance, the arbitrage opportunity we exemplified would only really be available to wealthy people in finance. Web3 and systems like flash loans assure that doesn't need to be the case any longer. +In contemporary finance, the arbitrage opportunity we exemplified would only really be available to wealthy people in finance. Web3 and systems like flash loans assure that doesn't need to be the case any longer. Let's recap a few things in the next lesson and then keep going with our recon of Thunder Loan! diff --git a/courses/security/7-bridges/10-unsupported-opcodes/+page.md b/courses/security/7-bridges/10-unsupported-opcodes/+page.md index bb2af1108..d891c1131 100644 --- a/courses/security/7-bridges/10-unsupported-opcodes/+page.md +++ b/courses/security/7-bridges/10-unsupported-opcodes/+page.md @@ -87,7 +87,7 @@ Run `forge build`. This should generate a JSON file for TokenFactory in our `out **...right-click and select `Format Document`.** -We can scroll down to `bytecode` or `deployedBytecode` for a list of what's used in this contract. This string of numbers and letters is the hexidecimal representation of the opcodes of which this contract is comprised. +We can scroll down to `bytecode` or `deployedBytecode` for a list of what's used in this contract. This string of numbers and letters is the hexadecimal representation of the opcodes of which this contract is comprised. Within this list, we expect to find the `create` opcode. A reference list for opcodes can be found here on [**evm.codes**](https://www.evm.codes/). From that reference we can see that `create` is represented by the opcode `F0`. diff --git a/courses/security/7-bridges/15-polygon/+page.md b/courses/security/7-bridges/15-polygon/+page.md index ac4c706bc..e65cb489f 100644 --- a/courses/security/7-bridges/15-polygon/+page.md +++ b/courses/security/7-bridges/15-polygon/+page.md @@ -17,13 +17,13 @@ On May 31, 2020 the Matic blockchain was launched, this was later rebranded to t - Short Block Time - ZK Rollup Tech -In the Gensis Block of the Polygon Chain (block 0), there are 10 transactions, one of which is the creation of a contract - MRC20. You can view this block yourself on [**PolygonScan**](https://polygonscan.com/txs?block=0). On creation, this contract was deployed with nearly 10 billion MATIC (the Polygon native currency). +In the Genesis Block of the Polygon Chain (block 0), there are 10 transactions, one of which is the creation of a contract - MRC20. You can view this block yourself on [**PolygonScan**](https://polygonscan.com/txs?block=0). On creation, this contract was deployed with nearly 10 billion MATIC (the Polygon native currency). A defining feature of this contract is that it contains a function which allows someone to sign a transaction without sending it. These are known as metatransactions and you can read more about them in [**EIP-2771**](https://eips.ethereum.org/EIPS/eip-2771). An exploit was lurking in MRC20 though, waiting to drain the contract of all these funds. -On December 3, 2021, nearly a year and a half after creation. A bug bounty report was submitted on Immunify by `LeonSpacewalker` laying out exactly how someone could exploit the MRC20 contract. Over the next 2 days, reports flooded in, detailing this exploit until, a malicious actor found the vulnerability and stole 800,000 MATIC tokens. +On December 3, 2021, nearly a year and a half after creation. A bug bounty report was submitted on Immunefi by `LeonSpacewalker` laying out exactly how someone could exploit the MRC20 contract. Over the next 2 days, reports flooded in, detailing this exploit until, a malicious actor found the vulnerability and stole 800,000 MATIC tokens. On Dec 5th, just two days after the initial report, the Polygon Chain was forked with the exploit patched. @@ -103,7 +103,7 @@ So, how did `LeonSpacewalker` find this bug, disclose it and get his massive pay 2. Find a bug and search for projects - Find a bug that's rare or many people are unfamiliar with and look for projects that may be vulnerable to that bug. It can be much easier to look for a specific thing in a code base than to look for something that stands out. - 3. Be fast with new updates: Be signed up to Bug Bounty announcements through platforms like Immunify to assure you're notified as soon as a bounty is made live by a protocol. + 3. Be fast with new updates: Be signed up to Bug Bounty announcements through platforms like Immunefi to assure you're notified as soon as a bounty is made live by a protocol. 4. Be creative with finding your edge: Something Leon did to give him an edge was traverse community forums to scope out which protocols were considering doing a bug bounty. He would then proactively look through code based _before_ they were even submitted for approval! diff --git a/courses/security/7-bridges/17-recon-continued/+page.md b/courses/security/7-bridges/17-recon-continued/+page.md index b194cd3c0..c102c8ced 100644 --- a/courses/security/7-bridges/17-recon-continued/+page.md +++ b/courses/security/7-bridges/17-recon-continued/+page.md @@ -94,7 +94,7 @@ event Deposit(address from, address to, uint256 amount); The errors are fairly standard, but the state variables reveal and confirm valuable information. We see that `token` and `vault` are immutable, which confirms our previous suspicions that there's to be one `token` and one `vault` per `bridge`. We also see a `signers` mapping. `Signers`, we can see in the `Actor/Roles` section of the protocol README are `Users who can "send" a token from L2 -> L1.`. Setting `signers` we expect to be access controlled, so we should watch out for that. -Next we've the constructor and what seem to be some admintrator functions. +Next we've the constructor and what seem to be some administrator functions. ```js constructor(IERC20 _token) Ownable(msg.sender) { diff --git a/courses/security/7-bridges/19-arbitrary/+page.md b/courses/security/7-bridges/19-arbitrary/+page.md index 9088cc6ff..8cf69b7b6 100644 --- a/courses/security/7-bridges/19-arbitrary/+page.md +++ b/courses/security/7-bridges/19-arbitrary/+page.md @@ -10,7 +10,7 @@ _Follow along with the video lesson:_ Did you find the bug in depositTokensToL2 from the previous lesson? -If not, that's ok. Our friend Slither is here to help us. This vulnerabilitiy is actually one that Slither caught for us earlier. Let's run the tool again. +If not, that's ok. Our friend Slither is here to help us. This vulnerability is actually one that Slither caught for us earlier. Let's run the tool again. ```bash make slither @@ -57,7 +57,7 @@ Because this function allows the setting of any `from` parameter, instead of def **Severity - HIGH!** ```js -// @Audit-High: Arbirary transferFrom risks any approved tokens +// @Audit-High: Arbitrary transferFrom risks any approved tokens function depositTokensToL2(address from, address l2Recipient, uint256 amount) external whenNotPaused {...} ``` diff --git a/courses/security/7-bridges/21-recon-continued-again/+page.md b/courses/security/7-bridges/21-recon-continued-again/+page.md index 20d0b769d..434199ecb 100644 --- a/courses/security/7-bridges/21-recon-continued-again/+page.md +++ b/courses/security/7-bridges/21-recon-continued-again/+page.md @@ -97,7 +97,7 @@ function depositTokensToL2(address from, address l2Recipient, uint256 amount) ex } ``` -Ok, yes! We're transfering our tokens (making an external call), before our event. This definitely is an issue. Now, it's important to note that because we're only using `L1Tokens` and we don't have to worry about any Weird `ERC20s` with callback functions - this isn't actually a security risk. +Ok, yes! We're transferring our tokens (making an external call), before our event. This definitely is an issue. Now, it's important to note that because we're only using `L1Tokens` and we don't have to worry about any Weird `ERC20s` with callback functions - this isn't actually a security risk. But, we can definitely call out the lack of best practices when we see them. diff --git a/courses/security/7-bridges/23-quick-aside/+page.md b/courses/security/7-bridges/23-quick-aside/+page.md index 758b54c13..0fd2730bd 100644 --- a/courses/security/7-bridges/23-quick-aside/+page.md +++ b/courses/security/7-bridges/23-quick-aside/+page.md @@ -10,14 +10,14 @@ _Follow along with the video lesson:_ After the following lesson, you might be asking yourself: -**_Why isn't this the same as the `arbirary from` finding?_** +**_Why isn't this the same as the `arbitrary from` finding?_** The answer is that the `root causes` of these findings are _slightly_ different. -- **Arbirary From:** approved tokens can be stolen by sending from any address +- **Arbitrary From:** approved tokens can be stolen by sending from any address - **Infinite Mint:** vault possesses maximum approvals by default and at all times -While `infinite mint` uses `arbirary from` as a mechanism for it's exploitation, the true root is that the vault has approved the bridge 100% of the time. +While `infinite mint` uses `arbitrary from` as a mechanism for it's exploitation, the true root is that the vault has approved the bridge 100% of the time. There could be argument for these to be the same finding, but I think they're unique enough to warrant separation. diff --git a/courses/security/7-bridges/26-replay-minimizd/+page.md b/courses/security/7-bridges/26-replay-minimizd/+page.md index 78034309c..67a1d26f0 100644 --- a/courses/security/7-bridges/26-replay-minimizd/+page.md +++ b/courses/security/7-bridges/26-replay-minimizd/+page.md @@ -41,7 +41,7 @@ function test_signatureReplay() public { } ``` -In this test, we have a victim depositing funds to a protocol and then signing a transaction with `vm.sign`. The victim then calls `withdrawBySig` which broadcasts the `v, r, and s` values of the victimes signature for this message, on-chain. +In this test, we have a victim depositing funds to a protocol and then signing a transaction with `vm.sign`. The victim then calls `withdrawBySig` which broadcasts the `v, r, and s` values of the victims signature for this message, on-chain. ```js signatureReplay.withdrawBySig(v, r, s, withdrawAmount); diff --git a/courses/security/7-bridges/27-signature-replay-poc/+page.md b/courses/security/7-bridges/27-signature-replay-poc/+page.md index 9c9a07b15..5ecaab3d8 100644 --- a/courses/security/7-bridges/27-signature-replay-poc/+page.md +++ b/courses/security/7-bridges/27-signature-replay-poc/+page.md @@ -45,7 +45,7 @@ vm.startPrank(attacker); token.approve(address(tokenBridge), type(uint256).max); tokenBridge.depositTokensToL2(attacker, attacker, attackerInitialBalance); -// Signer/Operator is going to sign the withdrawl +// Signer/Operator is going to sign the withdrawal bytes memory message = abi.encode( address(token), 0, abi.encodeCall(IERC20.transferFrom, (address(vault), attacker, attackerInitialBalance)) ); @@ -89,7 +89,7 @@ address(token), 0, abi.encodeCall(IERC20.transferFrom, (address(vault), attacker ); ``` -We're going to leverage some Foundry magic by using the Cheatcode `vm.sign` to similate this signature. We need to pass `vm.sign` a private key and a message. Fortunately, Foundry can help us again. +We're going to leverage some Foundry magic by using the Cheatcode `vm.sign` to simulate this signature. We need to pass `vm.sign` a private key and a message. Fortunately, Foundry can help us again. We're very familiar with the creation of addresses in our Foundry tests, but something we've not really touched on is the creation of accounts. At the very top of `L1TokenBridge.t.sol`, you can see we have an example. diff --git a/courses/security/7-bridges/29-low-level-exploit/+page.md b/courses/security/7-bridges/29-low-level-exploit/+page.md index 975dfa0e9..69f3a0c61 100644 --- a/courses/security/7-bridges/29-low-level-exploit/+page.md +++ b/courses/security/7-bridges/29-low-level-exploit/+page.md @@ -50,7 +50,7 @@ function approveTo(address target, uint256 amount) external onlyOwner { } ``` -Were a malicious actor to pass _this_ function data to the `sendToL1` message paramater, they could steal all the tokens in the vault! +Were a malicious actor to pass _this_ function data to the `sendToL1` message parameter, they could steal all the tokens in the vault! ### Wrap Up diff --git a/courses/security/7-bridges/31-recap/+page.md b/courses/security/7-bridges/31-recap/+page.md index 3a476fd37..de73fddcc 100644 --- a/courses/security/7-bridges/31-recap/+page.md +++ b/courses/security/7-bridges/31-recap/+page.md @@ -32,13 +32,13 @@ To start, we were introduced to even more tooling to assist in our security revi - AI: We didn't explicitly cover using AI, but AI is pretty pervasive in the space these days. Find a model you like, ChatGPT, Phind, Claude - you should be using AI. - [**"The Hans" Checklist**](https://solodit.xyz/checklist): a systematic approach to security reviews whereby a literal exhaustive checklist is applied to a protocol, to leave no stone unturned. Check it out on [**Solodit**](https://solodit.xyz/). -We learnt about precompiles, like `ecrecover` and the part it plays in the signing of transactions. We saw through our [**Polygon case study**](https://www.youtube.com/watch?v=QdIG7TfjUiM) the potentially disasterous effects of overlooking precompiles and how a white hat profited $2.2 million for finding the bug. +We learnt about precompiles, like `ecrecover` and the part it plays in the signing of transactions. We saw through our [**Polygon case study**](https://www.youtube.com/watch?v=QdIG7TfjUiM) the potentially disastrous effects of overlooking precompiles and how a white hat profited $2.2 million for finding the bug. In addition to this we dove deep into signatures, how they work and the vulnerabilities possible such as `Signature Replay Attacks`. We learnt the importance of restricting the use of signatures put on chain through a `nonce` or `deadline` to protect against their repeated use. -We learnt that different blockchain are different! Surpising, I know! `EVM Equivalency` is not `EVM Compatibility`. We outlined a [**case study**](https://medium.com/coinmonks/gemstoneido-contract-stuck-with-921-eth-an-analysis-of-why-transfer-does-not-work-on-zksync-era-d5a01807227d) where overlooking this on zkSync resulted in 921 ETH being stuck because `transfer()` wouldn't work! +We learnt that different blockchain are different! Surprising, I know! `EVM Equivalency` is not `EVM Compatibility`. We outlined a [**case study**](https://medium.com/coinmonks/gemstoneido-contract-stuck-with-921-eth-an-analysis-of-why-transfer-does-not-work-on-zksync-era-d5a01807227d) where overlooking this on zkSync resulted in 921 ETH being stuck because `transfer()` wouldn't work! -And, in the process we identified a bunch of new vulnerabilites like `gas bombs`, `unlimited minting`, `centralization` and the risks of `arbitrary code`. We learnt **a lot**. +And, in the process we identified a bunch of new vulnerabilities like `gas bombs`, `unlimited minting`, `centralization` and the risks of `arbitrary code`. We learnt **a lot**. One thing we didn't cover with as much depth was the actual writing of the findings. This is very much intentional. I'm trying to wean you off the hand holding so that you're able to perform reviews solo, confident in your ability to spot all these new exploits in your repertoire. diff --git a/courses/security/8-mev-and-governance/11-case-study-pashov/+page.md b/courses/security/8-mev-and-governance/11-case-study-pashov/+page.md index 40a10426b..d0c79b741 100644 --- a/courses/security/8-mev-and-governance/11-case-study-pashov/+page.md +++ b/courses/security/8-mev-and-governance/11-case-study-pashov/+page.md @@ -12,7 +12,7 @@ To walk us through some real-world reports where MEV was reported, we have guest ### What is MEV? -**MEV** - Maximum Extractable Value (Miner Extractable Value) - Both good and bad for the Ethereum Ecosysem, this concept exists in 4 forms +**MEV** - Maximum Extractable Value (Miner Extractable Value) - Both good and bad for the Ethereum Ecosystem, this concept exists in 4 forms 1. **Arbitrage** - detailed in previous lessons, this process is often handled by MEV bots. A difference in price between exchanges will be identified and MEV bots will balance the pools and their prices by leveraging swaps between them (and profiting along the way) 2. **Sandwiches** - we've covered this briefly earlier as well (remember Thunder Loan!), but we'll cover it with Pashov in more detail later diff --git a/courses/security/8-mev-and-governance/12-mev-prevention/+page.md b/courses/security/8-mev-and-governance/12-mev-prevention/+page.md index beecae388..c81272838 100644 --- a/courses/security/8-mev-and-governance/12-mev-prevention/+page.md +++ b/courses/security/8-mev-and-governance/12-mev-prevention/+page.md @@ -55,7 +55,7 @@ There's no universal statement that covers all the possible situations in which ### Private or Dark Mempool -Another thing we can consider for defence is the use of a private or "dark" `mempool`, such as [**Flashbots Protect**](https://docs.flashbots.net/flashbots-protect/overview), [**MEVBlocker**](https://mevblocker.io/) or [**Securerpc**](https://securerpc.com/). +Another thing we can consider for defense is the use of a private or "dark" `mempool`, such as [**Flashbots Protect**](https://docs.flashbots.net/flashbots-protect/overview), [**MEVBlocker**](https://mevblocker.io/) or [**Securerpc**](https://securerpc.com/). ::image{src='/security-section-8/12-mev-prevention/flashbots.png' style='width: 100%; height: auto;' alt='pashov'} @@ -79,6 +79,6 @@ function swapExactInput( ){...} ``` -As we discussed previously, leveraging a parameter like this allows the user to set their tolerance of price change during their transaction, limiting their exposure to sudden price fluxtuations by MEV Exploits! +As we discussed previously, leveraging a parameter like this allows the user to set their tolerance of price change during their transaction, limiting their exposure to sudden price fluctuations by MEV Exploits! As security experts, we should always be advising protocols how they can defend their users against MEV. Let's recap everything we've been over, in the next lesson. diff --git a/courses/security/8-mev-and-governance/14-governance-attack-intro/+page.md b/courses/security/8-mev-and-governance/14-governance-attack-intro/+page.md index 4b6141cee..fc3be4a09 100644 --- a/courses/security/8-mev-and-governance/14-governance-attack-intro/+page.md +++ b/courses/security/8-mev-and-governance/14-governance-attack-intro/+page.md @@ -46,7 +46,7 @@ There are a few ways to mitigate the effects of governance attacks, but at their - **Centralization of Power** - while not ideal in a Web3 ecosystem, this _does_ solve the issue of control being democratically wielded through `voting mechanisms`. -- **Strategic Voting Power Distribution** - think carefully about who holds the most power over protocol `governance`, by strategic in assuring voting power is alotted to those invested and not made available to anyone with a flash loan +- **Strategic Voting Power Distribution** - think carefully about who holds the most power over protocol `governance`, by strategic in assuring voting power is allotted to those invested and not made available to anyone with a flash loan - **Guardian Buffer** - while this also sacrifices a degree of decentrality, this is an entity which serves as a buffer to vet proposals for malicious actions and assure pursued proposals are financially viable for the organization. This protects against `governance attacks` by filtering malicious proposals before they reach the voting stage diff --git a/courses/security/8-mev-and-governance/15-case-study-bean/+page.md b/courses/security/8-mev-and-governance/15-case-study-bean/+page.md index 6c0322cd1..1ba2f68f3 100644 --- a/courses/security/8-mev-and-governance/15-case-study-bean/+page.md +++ b/courses/security/8-mev-and-governance/15-case-study-bean/+page.md @@ -16,11 +16,11 @@ You can read more about the [Bean attack in Rekt](https://rekt.news/beanstalk-re - $182,000,000 loss to the protocol -- Attacker profitted $76,000,000 which they laundered through Tornado Cash +- Attacker profited $76,000,000 which they laundered through Tornado Cash - $106,000,000 was paid in flash loan and swap feed on Aave and Uniswap respectively. -- Governnance Manipulation Attack +- Governance Manipulation Attack - Highly Sophisticated diff --git a/courses/security/8-mev-and-governance/2-perseverance/+page.md b/courses/security/8-mev-and-governance/2-perseverance/+page.md index f1ce6e025..813a2929e 100644 --- a/courses/security/8-mev-and-governance/2-perseverance/+page.md +++ b/courses/security/8-mev-and-governance/2-perseverance/+page.md @@ -1,5 +1,5 @@ --- -title: Perserverance +title: Perseverance --- _Follow along with this video:_ @@ -20,7 +20,7 @@ Securing Web3 isn't a one man/woman job. Collaboration and working together is a As always, there'll be an audit-data branch of the Vault Guardians repo to compare your results to. -::image{src='/security-section-8/2-perserverance/vault-guardians.png' style='width: 100%; height: auto;' alt='vault guardians'} +::image{src='/security-section-8/2-perseverance/vault-guardians.png' style='width: 100%; height: auto;' alt='vault guardians'} ### Wrap Up diff --git a/courses/security/8-mev-and-governance/4-mev-minimized/+page.md b/courses/security/8-mev-and-governance/4-mev-minimized/+page.md index 1341c59f7..8d571a121 100644 --- a/courses/security/8-mev-and-governance/4-mev-minimized/+page.md +++ b/courses/security/8-mev-and-governance/4-mev-minimized/+page.md @@ -14,6 +14,6 @@ We can take a look at this image to see a minimized visual representation of wha ### MEV - Everywhere -To demonstrate just how prevasive this vulnerability is in Web3 .. I've got a secret. +To demonstrate just how pervasive this vulnerability is in Web3 .. I've got a secret. **_EVERY_** code base we've audited up to now has been susceptible to MEV attacks! Let's go over how it applies in each situation, starting with Puppy Raffle! diff --git a/courses/security/8-mev-and-governance/6-mev-t-swap/+page.md b/courses/security/8-mev-and-governance/6-mev-t-swap/+page.md index 08ba13f6d..2d0715255 100644 --- a/courses/security/8-mev-and-governance/6-mev-t-swap/+page.md +++ b/courses/security/8-mev-and-governance/6-mev-t-swap/+page.md @@ -95,11 +95,11 @@ function deposit( We identified, during our review, that the `deadline` parameter wasn't being used. How would that potentially lead to an `MEV` attack in `TSwap`? -Before a transaction is sent to the `MemPool`, it is sent to a node. Node operators have priviledged information with respect to transactions about to be added to the blockchain and in some circumstances they can delay when a transaction is processed by up to a whole block. If the `deadline` parameter was properly employed it could have prevented this! +Before a transaction is sent to the `MemPool`, it is sent to a node. Node operators have privileged information with respect to transactions about to be added to the blockchain and in some circumstances they can delay when a transaction is processed by up to a whole block. If the `deadline` parameter was properly employed it could have prevented this! Imagine a node operator happened to be a `liquidity provider` in `TSwap`. This operator would be able to see pending deposits into the protocol, the practical effect of which would be that their shares and fees are lowered as the `LPTokens` are diluted. -This malicious node operator would have the power to delay the processing of this `deposit` transaction in favor of validating more swap transactions maximizing the fees they would obtain from the protocol at the expensive of the new depositer! +This malicious node operator would have the power to delay the processing of this `deposit` transaction in favor of validating more swap transactions maximizing the fees they would obtain from the protocol at the expensive of the new depositor! ::image{src='/security-section-8/6-tswap-mev/mev-in-tswap1.png' style='width: 100%; height: auto;'} diff --git a/courses/solidity/1-simple-storage/6-functions/+page.md b/courses/solidity/1-simple-storage/6-functions/+page.md index d716e68ea..d20afe7d9 100644 --- a/courses/solidity/1-simple-storage/6-functions/+page.md +++ b/courses/solidity/1-simple-storage/6-functions/+page.md @@ -39,7 +39,7 @@ contract SimpleStorage { ``` The content of the function is placed within the curly brackets `{}`. -The prefix `_` before `_favoriteNumber` is used to emphasise that the **_local_** variable `_favoriteNumber` is a **different** variable from the **_state_** variable `favoriteNumber`. This helps prevent potential confusion when dealing with different variables with similar names in complex codebases. +The prefix `_` before `_favoriteNumber` is used to emphasize that the **_local_** variable `_favoriteNumber` is a **different** variable from the **_state_** variable `favoriteNumber`. This helps prevent potential confusion when dealing with different variables with similar names in complex codebases. ### Deploying the smart contract diff --git a/courses/solidity/1-simple-storage/9-memory-storage-calldata/+page.md b/courses/solidity/1-simple-storage/9-memory-storage-calldata/+page.md index 8796895b9..a0f325ce6 100644 --- a/courses/solidity/1-simple-storage/9-memory-storage-calldata/+page.md +++ b/courses/solidity/1-simple-storage/9-memory-storage-calldata/+page.md @@ -37,7 +37,7 @@ Calldata variables are read-only and cheaper than memory. They are mostly used f In the following example, if we try to replace the keyword `memory` with `calldata`, we receive an error because `calldata` variables can't be manipulated. ```solidity -function addPerson(string calldata _name, uitn256 _favoriteNumber) public { +function addPerson(string calldata _name, uint256 _favoriteNumber) public { _name = "cat"; listOfPeople.push(Person(_favoriteNumber, _name)); } @@ -73,7 +73,7 @@ In Solidity, a `string` is recognized as an **array of bytes**. On the other han > You can't use the `storage` keyword for variables inside a function. Only `memory` and `calldata` are allowed here, as the variable only exists temporarily. ```solidity -function addPerson(string memory _name, uitn256 _favoriteNumber) public { // cannot use storage as input parameters +function addPerson(string memory _name, uint256 _favoriteNumber) public { // cannot use storage as input parameters uint256 test = 0; // variable here can be stored in memory or stack listOfPeople.push(Person(_favoriteNumber, _name)); } diff --git a/courses/solidity/4-ai-prompting/1-ai-and-forums/+page.md b/courses/solidity/4-ai-prompting/1-ai-and-forums/+page.md index b6765d3dd..ce2c92601 100644 --- a/courses/solidity/4-ai-prompting/1-ai-and-forums/+page.md +++ b/courses/solidity/4-ai-prompting/1-ai-and-forums/+page.md @@ -28,7 +28,7 @@ Pinpoint your error, review your code manually making small adjustments you susp There are several AI models available these days, each with their pros and cons. Here are a few to consider. -- [**ChatGPT**](https://chat.openai.com) - The OG. This model offered by OpenAI is robust, multi-modal, includes code interpretion and can browse the web. The best quality unfortunately comes from the paid version. +- [**ChatGPT**](https://chat.openai.com) - The OG. This model offered by OpenAI is robust, multi-modal, includes code interpretation and can browse the web. The best quality unfortunately comes from the paid version. - [**Phind**](https://www.phind.com/search?home=true) - This is a programming focused model with intuition allowing it to proactively ask questions to clarify assumptions. Can also browse the web, and has a VS Code extension! - [**Copilot**](https://www.microsoft.com/en-us/edge/features/copilot?form=MA13FJ) - formerly `Bing Chat`, and not to be confused with the IDE AI assistant, Copilot is rapidly becoming Microsoft's whole ecosystem response to the age of AI - [**Google Bard**](https://bard.google.com/) - ehhhhh - results may vary. @@ -37,7 +37,7 @@ There are `6 principles` to prompt engineering to get the best out of your AI. - **Principle 1:** Write clear and specific instructions - **Principle 2:** Give as much context as possible -- **Principle 3:** Use delimiters to clearerly indicate distinct parts of the input +- **Principle 3:** Use delimiters to clearly indicate distinct parts of the input - **Principle 4:** Look out for `hallucinations` - **Principle 5:** Understand the limitations of the model - many have strict context token limits (though this is rapidly changing) - **Principle 6:** Iterate constantly @@ -48,7 +48,7 @@ Asking questions is a skill, so keep practicing. There's a great free course at ### Read Docs -If a problem is occuring with a particular implementation, framework, language - whatever - you can almost always read the documentation for further insight and examples of how to accomplish your goals. +If a problem is occurring with a particular implementation, framework, language - whatever - you can almost always read the documentation for further insight and examples of how to accomplish your goals. > You can even use AI to help you here by copying docs as context into a model like ChatGPT and asking questions to it @@ -68,7 +68,7 @@ We always want to ask our questions in a web-indexed forum which will allow sear - [**Ethereum Stack Exchange**](https://ethereum.stackexchange.com/) - a community-driven question-and-answer platform dedicated to Ethereum, and blockchain technology - [**Stack Overflow**](https://stackoverflow.com/) - online platform that facilitates knowledge exchange and problem-solving within the global programming and software development community -- [**Peerhana**](https://peeranha.io) - Peeranha is a decentralized knowledge sharing platform built on web3 technology, particularly blockchain +- [**Peeranha**](https://peeranha.io) - Peeranha is a decentralized knowledge sharing platform built on web3 technology, particularly blockchain - [**Reddit**](https://www.reddit.com/) - Reddit is a widely popular and diverse social media platform that serves as a hub for online communities, discussions, and content sharing Questions asked on Discord and Twitter are likely to get buried in their conversational chaos and will never be indexed, so use these avenues sparingly. diff --git a/courses/solidity/4-ai-prompting/2-triage/+page.md b/courses/solidity/4-ai-prompting/2-triage/+page.md index abec7da3f..826dc919b 100644 --- a/courses/solidity/4-ai-prompting/2-triage/+page.md +++ b/courses/solidity/4-ai-prompting/2-triage/+page.md @@ -24,6 +24,6 @@ When you're stuck on an issue you can't solve, you can visit forum platforms lik ### GitHub Issues -If you can't get help elsewhere, you can open an Github Issue in the [GitHub's Issue Tracker](https://github.com/Cyfrin/remix-fund-me-cu/issues). This section allows you to interact with the developer community, report bugs, and suggest enhancements. Remembert to always search within existing issues before posting to avoid duplicates. +If you can't get help elsewhere, you can open an Github Issue in the [GitHub's Issue Tracker](https://github.com/Cyfrin/remix-fund-me-cu/issues). This section allows you to interact with the developer community, report bugs, and suggest enhancements. Remember to always search within existing issues before posting to avoid duplicates. -GitHub is essential for sharing, writing, and interacting with fellow developers, as well as accessing and contributing to code. We will use it as a **portfolio** for our projects thorughout the courses. This portfolio will become very valuable when applying for jobs, because it easily showcase your coding skills and contributions to open-source projects. +GitHub is essential for sharing, writing, and interacting with fellow developers, as well as accessing and contributing to code. We will use it as a **portfolio** for our projects throughout the courses. This portfolio will become very valuable when applying for jobs, because it easily showcase your coding skills and contributions to open-source projects. diff --git a/courses/solidity/4-ai-prompting/5-speedrun/+page.md b/courses/solidity/4-ai-prompting/5-speedrun/+page.md index 79bee9109..2bc2b6c2a 100644 --- a/courses/solidity/4-ai-prompting/5-speedrun/+page.md +++ b/courses/solidity/4-ai-prompting/5-speedrun/+page.md @@ -21,7 +21,7 @@ Through Speedrun Ethereum, you'll delve into a plethora of projects, including: - **Developing a token vendor** - **Building a Dice Game** - learning about randomness on chain - **Creating a Decentralized Exchange (Dex)** -- **Contructing and using a MultiSig Wallet** +- **Constructing and using a MultiSig Wallet** - **SVG NFTs and on chain Data** ...and much more diff --git a/courses/solidity/4-ai-prompting/6-congrats/+page.md b/courses/solidity/4-ai-prompting/6-congrats/+page.md index 23bb30504..0c955471a 100644 --- a/courses/solidity/4-ai-prompting/6-congrats/+page.md +++ b/courses/solidity/4-ai-prompting/6-congrats/+page.md @@ -8,6 +8,6 @@ _Follow along with the video_ Congratulations on completing the Solidity Fundamentals course! You now understand the basics of deploying and working with smart contracts, which are essential skills for a smart contract developer or a security researcher. -Next, we'll move on to the **Foundry** course. Foundry is a smart contract framework that will enhance our smar contract development skills, allowing us to create safer tests, deploy contracts programmatically, and more. +Next, we'll move on to the **Foundry** course. Foundry is a smart contract framework that will enhance our smart contract development skills, allowing us to create safer tests, deploy contracts programmatically, and more. Take a well deserved break: get some ice cream, go for a walk, or hit the gym. Looking forward to seeing you in the Foundry course 🐸! diff --git a/courses/wallets/2-section-1/5-multi-sig-wallets/+page.md b/courses/wallets/2-section-1/5-multi-sig-wallets/+page.md index e167120fa..0d3b9c80c 100644 --- a/courses/wallets/2-section-1/5-multi-sig-wallets/+page.md +++ b/courses/wallets/2-section-1/5-multi-sig-wallets/+page.md @@ -8,7 +8,7 @@ _Follow along with this video:_ ### Multi Sig Wallets -A multi-sig wallet is a smart contract that governs transactions. These can be setup so taht they require several people to sign a transaction for it to go through. +A multi-sig wallet is a smart contract that governs transactions. These can be setup so that they require several people to sign a transaction for it to go through. These can be customized such that any X number of people are required to sign out of Y before a transaction will process.